mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Correctly tag heredocs (#16061)
This allows text editors to use correct syntax coloring for the heredoc sections. Heredoc tag names we use: languages: SQL, JS, RUBY, LUA, HTML, CSS, SCSS, SH, HBS, XML, YAML/YML, MF, ICS other: MD, TEXT/TXT, RAW, EMAIL
This commit is contained in:
@@ -45,14 +45,14 @@ class PostsController < ApplicationController
|
|||||||
opts[:limit] = MARKDOWN_TOPIC_PAGE_SIZE
|
opts[:limit] = MARKDOWN_TOPIC_PAGE_SIZE
|
||||||
topic_view = TopicView.new(params[:topic_id], current_user, opts)
|
topic_view = TopicView.new(params[:topic_id], current_user, opts)
|
||||||
content = topic_view.posts.map do |p|
|
content = topic_view.posts.map do |p|
|
||||||
<<~HEREDOC
|
<<~MD
|
||||||
#{p.user.username} | #{p.updated_at} | ##{p.post_number}
|
#{p.user.username} | #{p.updated_at} | ##{p.post_number}
|
||||||
|
|
||||||
#{p.raw}
|
#{p.raw}
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
HEREDOC
|
MD
|
||||||
end
|
end
|
||||||
render plain: content.join
|
render plain: content.join
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ class SessionController < ApplicationController
|
|||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
|
||||||
if SiteSetting.verbose_discourse_connect_logging
|
if SiteSetting.verbose_discourse_connect_logging
|
||||||
Rails.logger.warn(<<~EOF)
|
Rails.logger.warn(<<~TEXT)
|
||||||
Verbose SSO log: Record was invalid: #{e.record.class.name} #{e.record.id}
|
Verbose SSO log: Record was invalid: #{e.record.class.name} #{e.record.id}
|
||||||
#{e.record.errors.to_h}
|
#{e.record.errors.to_h}
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ class SessionController < ApplicationController
|
|||||||
|
|
||||||
SSO Diagnostics:
|
SSO Diagnostics:
|
||||||
#{sso.diagnostics}
|
#{sso.diagnostics}
|
||||||
EOF
|
TEXT
|
||||||
end
|
end
|
||||||
|
|
||||||
text = nil
|
text = nil
|
||||||
|
|||||||
@@ -303,11 +303,11 @@ module Jobs
|
|||||||
# Simulate the args being dumped/parsed through JSON
|
# Simulate the args being dumped/parsed through JSON
|
||||||
parsed_opts = JSON.parse(JSON.dump(opts))
|
parsed_opts = JSON.parse(JSON.dump(opts))
|
||||||
if opts != parsed_opts
|
if opts != parsed_opts
|
||||||
Discourse.deprecate(<<~MSG.squish, since: "2.9", drop_from: "3.0")
|
Discourse.deprecate(<<~TEXT.squish, since: "2.9", drop_from: "3.0")
|
||||||
#{klass.name} was enqueued with argument values which do not cleanly serialize to/from JSON.
|
#{klass.name} was enqueued with argument values which do not cleanly serialize to/from JSON.
|
||||||
This means that the job will be run with slightly different values than the ones supplied to `enqueue`.
|
This means that the job will be run with slightly different values than the ones supplied to `enqueue`.
|
||||||
Argument values should be strings, booleans, numbers, or nil (or arrays/hashes of those value types).
|
Argument values should be strings, booleans, numbers, or nil (or arrays/hashes of those value types).
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
opts = parsed_opts
|
opts = parsed_opts
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class ReviewableSerializer < ApplicationSerializer
|
|||||||
def self.create_attribute(name, field)
|
def self.create_attribute(name, field)
|
||||||
attribute(name)
|
attribute(name)
|
||||||
|
|
||||||
class_eval <<~GETTER
|
class_eval <<~RUBY
|
||||||
def #{name}
|
def #{name}
|
||||||
#{field}
|
#{field}
|
||||||
end
|
end
|
||||||
@@ -67,7 +67,7 @@ class ReviewableSerializer < ApplicationSerializer
|
|||||||
def include_#{name}?
|
def include_#{name}?
|
||||||
#{name}.present?
|
#{name}.present?
|
||||||
end
|
end
|
||||||
GETTER
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is easier than creating an AMS method for each attribute
|
# This is easier than creating an AMS method for each attribute
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class UserActionManager
|
|||||||
end
|
end
|
||||||
|
|
||||||
[:notification, :post, :topic, :post_action].each do |type|
|
[:notification, :post, :topic, :post_action].each do |type|
|
||||||
self.class_eval(<<~METHODS)
|
self.class_eval(<<~RUBY)
|
||||||
def self.#{type}_created(*args)
|
def self.#{type}_created(*args)
|
||||||
return if @disabled
|
return if @disabled
|
||||||
#{type}_rows(*args).each { |row| UserAction.log_action!(row) }
|
#{type}_rows(*args).each { |row| UserAction.log_action!(row) }
|
||||||
@@ -20,7 +20,7 @@ class UserActionManager
|
|||||||
return if @disabled
|
return if @disabled
|
||||||
#{type}_rows(*args).each { |row| UserAction.remove_action!(row) }
|
#{type}_rows(*args).each { |row| UserAction.remove_action!(row) }
|
||||||
end
|
end
|
||||||
METHODS
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ if ENV["TRACE_PG_CONNECTIONS"]
|
|||||||
def log_access(&blk)
|
def log_access(&blk)
|
||||||
@access_log_mutex.synchronize do
|
@access_log_mutex.synchronize do
|
||||||
if !@accessor_thread.nil?
|
if !@accessor_thread.nil?
|
||||||
Rails.logger.error <<~STRING
|
Rails.logger.error <<~TEXT
|
||||||
PG Clash: A connection is being accessed from two locations
|
PG Clash: A connection is being accessed from two locations
|
||||||
|
|
||||||
#{@accessor_thread} was using the connection. Backtrace:
|
#{@accessor_thread} was using the connection. Backtrace:
|
||||||
@@ -49,7 +49,7 @@ if ENV["TRACE_PG_CONNECTIONS"]
|
|||||||
#{Thread.current} is now attempting to use the connection. Backtrace:
|
#{Thread.current} is now attempting to use the connection. Backtrace:
|
||||||
|
|
||||||
#{Thread.current&.backtrace&.join("\n")}
|
#{Thread.current&.backtrace&.join("\n")}
|
||||||
STRING
|
TEXT
|
||||||
|
|
||||||
if ENV["ON_PG_CLASH"] == "byebug"
|
if ENV["ON_PG_CLASH"] == "byebug"
|
||||||
require "byebug"
|
require "byebug"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
if defined?(Rails::Server) && Rails.env.production? # Only run these checks when starting up a production server
|
if defined?(Rails::Server) && Rails.env.production? # Only run these checks when starting up a production server
|
||||||
|
|
||||||
if ['localhost', 'production.localhost'].include?(Discourse.current_hostname)
|
if ['localhost', 'production.localhost'].include?(Discourse.current_hostname)
|
||||||
puts <<END
|
puts <<~TEXT
|
||||||
|
|
||||||
Discourse.current_hostname = '#{Discourse.current_hostname}'
|
Discourse.current_hostname = '#{Discourse.current_hostname}'
|
||||||
|
|
||||||
@@ -13,20 +13,20 @@ if defined?(Rails::Server) && Rails.env.production? # Only run these checks when
|
|||||||
so that it uses the hostname of your site. Otherwise you will
|
so that it uses the hostname of your site. Otherwise you will
|
||||||
experience problems, like links in emails using #{Discourse.current_hostname}.
|
experience problems, like links in emails using #{Discourse.current_hostname}.
|
||||||
|
|
||||||
END
|
TEXT
|
||||||
|
|
||||||
raise "Invalid host_names in database.yml"
|
raise "Invalid host_names in database.yml"
|
||||||
end
|
end
|
||||||
|
|
||||||
if !Dir.glob(File.join(Rails.root, 'public', 'assets', 'application*.js')).present?
|
if !Dir.glob(File.join(Rails.root, 'public', 'assets', 'application*.js')).present?
|
||||||
puts <<END
|
puts <<~TEXT
|
||||||
|
|
||||||
Assets have not been precompiled. Please run the following command
|
Assets have not been precompiled. Please run the following command
|
||||||
before starting the rails server in production mode:
|
before starting the rails server in production mode:
|
||||||
|
|
||||||
rake assets:precompile
|
rake assets:precompile
|
||||||
|
|
||||||
END
|
TEXT
|
||||||
|
|
||||||
raise "Assets have not been precompiled"
|
raise "Assets have not been precompiled"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ class FixIncorrectUserHistory < ActiveRecord::Migration[4.2]
|
|||||||
|
|
||||||
# this is a :auto_trust_level_change mislabeled as :check_email
|
# this is a :auto_trust_level_change mislabeled as :check_email
|
||||||
# impersonate that was actually delete topic
|
# impersonate that was actually delete topic
|
||||||
condition = <<CLAUSE
|
condition = <<~SQL
|
||||||
(action = 16 AND previous_value in ('0','1','2','3','4')) OR
|
(action = 16 AND previous_value in ('0','1','2','3','4')) OR
|
||||||
(action = 19 AND target_user_id IS NULL AND details IS NOT NULL)
|
(action = 19 AND target_user_id IS NULL AND details IS NOT NULL)
|
||||||
CLAUSE
|
SQL
|
||||||
|
|
||||||
first_wrong_id = execute("SELECT min(id) FROM user_histories WHERE #{condition}").values[0][0].to_i
|
first_wrong_id = execute("SELECT min(id) FROM user_histories WHERE #{condition}").values[0][0].to_i
|
||||||
last_wrong_id = execute("SELECT max(id) FROM user_histories WHERE #{condition}").values[0][0].to_i
|
last_wrong_id = execute("SELECT max(id) FROM user_histories WHERE #{condition}").values[0][0].to_i
|
||||||
|
|||||||
@@ -1011,13 +1011,13 @@ module Email
|
|||||||
|
|
||||||
def forwarded_email_quote_forwarded(destination, user)
|
def forwarded_email_quote_forwarded(destination, user)
|
||||||
embedded = embedded_email_raw
|
embedded = embedded_email_raw
|
||||||
raw = <<~EOF
|
raw = <<~MD
|
||||||
#{@before_embedded}
|
#{@before_embedded}
|
||||||
|
|
||||||
[quote]
|
[quote]
|
||||||
#{PlainTextToMarkdown.new(embedded).to_markdown}
|
#{PlainTextToMarkdown.new(embedded).to_markdown}
|
||||||
[/quote]
|
[/quote]
|
||||||
EOF
|
MD
|
||||||
|
|
||||||
return true if forwarded_email_create_topic(destination: destination, user: user, raw: raw, title: subject)
|
return true if forwarded_email_create_topic(destination: destination, user: user, raw: raw, title: subject)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Barber::Precompiler
|
|||||||
# very hacky but lets us use ES6. I'm ashamed of this code -RW
|
# very hacky but lets us use ES6. I'm ashamed of this code -RW
|
||||||
transpiled = transpiled[transpiled.index('var RawHandlebars = ')...transpiled.index('export ')]
|
transpiled = transpiled[transpiled.index('var RawHandlebars = ')...transpiled.index('export ')]
|
||||||
|
|
||||||
@precompiler = StringIO.new <<~END
|
@precompiler = StringIO.new <<~JS
|
||||||
var __RawHandlebars;
|
var __RawHandlebars;
|
||||||
(function() {
|
(function() {
|
||||||
#{transpiled};
|
#{transpiled};
|
||||||
@@ -30,7 +30,7 @@ class Barber::Precompiler
|
|||||||
return __RawHandlebars.precompile(string, false).toString();
|
return __RawHandlebars.precompile(string, false).toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
END
|
JS
|
||||||
end
|
end
|
||||||
|
|
||||||
@precompiler
|
@precompiler
|
||||||
@@ -111,10 +111,10 @@ class Ember::Handlebars::Template
|
|||||||
"define('#{module_name}', ['exports'], function(__exports__){ __exports__['default'] = #{template} });"
|
"define('#{module_name}', ['exports'], function(__exports__){ __exports__['default'] = #{template} });"
|
||||||
when :global
|
when :global
|
||||||
if raw
|
if raw
|
||||||
return <<~RAW_TEMPLATE
|
return <<~JS
|
||||||
var __t = #{template};
|
var __t = #{template};
|
||||||
requirejs('discourse-common/lib/raw-templates').addRawTemplate(#{path_for(template_name, config)}, __t);
|
requirejs('discourse-common/lib/raw-templates').addRawTemplate(#{path_for(template_name, config)}, __t);
|
||||||
RAW_TEMPLATE
|
JS
|
||||||
end
|
end
|
||||||
|
|
||||||
target = global_template_target('Ember.TEMPLATES', template_name, config)
|
target = global_template_target('Ember.TEMPLATES', template_name, config)
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class Migration::SafeMigrate
|
|||||||
|
|
||||||
def self.protect!(sql)
|
def self.protect!(sql)
|
||||||
if sql =~ /^\s*(?:drop\s+table|alter\s+table.*rename\s+to)\s+/i
|
if sql =~ /^\s*(?:drop\s+table|alter\s+table.*rename\s+to)\s+/i
|
||||||
$stdout.puts("", <<~STR)
|
$stdout.puts("", <<~TEXT)
|
||||||
WARNING
|
WARNING
|
||||||
-------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
An attempt was made to drop or rename a table in a migration
|
An attempt was made to drop or rename a table in a migration
|
||||||
@@ -131,10 +131,10 @@ class Migration::SafeMigrate
|
|||||||
|
|
||||||
This protection is in place to protect us against dropping tables that are currently
|
This protection is in place to protect us against dropping tables that are currently
|
||||||
in use by live applications.
|
in use by live applications.
|
||||||
STR
|
TEXT
|
||||||
raise Discourse::InvalidMigration, "Attempt was made to drop a table"
|
raise Discourse::InvalidMigration, "Attempt was made to drop a table"
|
||||||
elsif sql =~ /^\s*alter\s+table.*(?:rename|drop)\s+/i
|
elsif sql =~ /^\s*alter\s+table.*(?:rename|drop)\s+/i
|
||||||
$stdout.puts("", <<~STR)
|
$stdout.puts("", <<~TEXT)
|
||||||
WARNING
|
WARNING
|
||||||
-------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
An attempt was made to drop or rename a column in a migration
|
An attempt was made to drop or rename a column in a migration
|
||||||
@@ -148,7 +148,7 @@ class Migration::SafeMigrate
|
|||||||
|
|
||||||
This protection is in place to protect us against dropping columns that are currently
|
This protection is in place to protect us against dropping columns that are currently
|
||||||
in use by live applications.
|
in use by live applications.
|
||||||
STR
|
TEXT
|
||||||
raise Discourse::InvalidMigration, "Attempt was made to rename or delete column"
|
raise Discourse::InvalidMigration, "Attempt was made to rename or delete column"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -218,14 +218,14 @@ module Onebox
|
|||||||
def card_html
|
def card_html
|
||||||
escaped_url = ::Onebox::Helpers.normalize_url_for_output(data[:player])
|
escaped_url = ::Onebox::Helpers.normalize_url_for_output(data[:player])
|
||||||
|
|
||||||
<<~RAW
|
<<~HTML
|
||||||
<iframe src="#{escaped_url}"
|
<iframe src="#{escaped_url}"
|
||||||
width="#{data[:player_width] || "100%"}"
|
width="#{data[:player_width] || "100%"}"
|
||||||
height="#{data[:player_height]}"
|
height="#{data[:player_height]}"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
frameborder="0">
|
frameborder="0">
|
||||||
</iframe>
|
</iframe>
|
||||||
RAW
|
HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
def article_html
|
def article_html
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def plugin_initialization_guard(&block)
|
|||||||
end
|
end
|
||||||
end.reverse.join("\n")
|
end.reverse.join("\n")
|
||||||
|
|
||||||
STDERR.puts <<~MESSAGE
|
STDERR.puts <<~TEXT
|
||||||
#{stack_trace}
|
#{stack_trace}
|
||||||
|
|
||||||
** INCOMPATIBLE PLUGIN **
|
** INCOMPATIBLE PLUGIN **
|
||||||
@@ -33,9 +33,9 @@ def plugin_initialization_guard(&block)
|
|||||||
#{plugin_path}
|
#{plugin_path}
|
||||||
|
|
||||||
Please try removing this plugin and rebuilding again!
|
Please try removing this plugin and rebuilding again!
|
||||||
MESSAGE
|
TEXT
|
||||||
else
|
else
|
||||||
STDERR.puts <<~MESSAGE
|
STDERR.puts <<~TEXT
|
||||||
** PLUGIN FAILURE **
|
** PLUGIN FAILURE **
|
||||||
|
|
||||||
You are unable to build Discourse due to this error during plugin
|
You are unable to build Discourse due to this error during plugin
|
||||||
@@ -44,7 +44,7 @@ def plugin_initialization_guard(&block)
|
|||||||
#{error}
|
#{error}
|
||||||
|
|
||||||
#{error.backtrace.join("\n")}
|
#{error.backtrace.join("\n")}
|
||||||
MESSAGE
|
TEXT
|
||||||
end
|
end
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -34,23 +34,23 @@ module Stylesheet
|
|||||||
contents = +""
|
contents = +""
|
||||||
|
|
||||||
if body_font.present?
|
if body_font.present?
|
||||||
contents << <<~EOF
|
contents << <<~CSS
|
||||||
#{font_css(body_font)}
|
#{font_css(body_font)}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--font-family: #{body_font[:stack]};
|
--font-family: #{body_font[:stack]};
|
||||||
}
|
}
|
||||||
EOF
|
CSS
|
||||||
end
|
end
|
||||||
|
|
||||||
if heading_font.present?
|
if heading_font.present?
|
||||||
contents << <<~EOF
|
contents << <<~CSS
|
||||||
#{font_css(heading_font)}
|
#{font_css(heading_font)}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--heading-font-family: #{heading_font[:stack]};
|
--heading-font-family: #{heading_font[:stack]};
|
||||||
}
|
}
|
||||||
EOF
|
CSS
|
||||||
end
|
end
|
||||||
|
|
||||||
contents
|
contents
|
||||||
@@ -70,14 +70,14 @@ module Stylesheet
|
|||||||
end
|
end
|
||||||
|
|
||||||
contents << font_css(font)
|
contents << font_css(font)
|
||||||
contents << <<~EOF
|
contents << <<~CSS
|
||||||
.body-font-#{font[:key].tr("_", "-")} {
|
.body-font-#{font[:key].tr("_", "-")} {
|
||||||
font-family: #{font[:stack]};
|
font-family: #{font[:stack]};
|
||||||
}
|
}
|
||||||
.heading-font-#{font[:key].tr("_", "-")} h2 {
|
.heading-font-#{font[:key].tr("_", "-")} h2 {
|
||||||
font-family: #{font[:stack]};
|
font-family: #{font[:stack]};
|
||||||
}
|
}
|
||||||
EOF
|
CSS
|
||||||
end
|
end
|
||||||
|
|
||||||
contents
|
contents
|
||||||
@@ -184,11 +184,11 @@ module Stylesheet
|
|||||||
fields.map do |field|
|
fields.map do |field|
|
||||||
value = field.value
|
value = field.value
|
||||||
if value.present?
|
if value.present?
|
||||||
contents << <<~COMMENT
|
contents << <<~SCSS
|
||||||
// Theme: #{field.theme.name}
|
// Theme: #{field.theme.name}
|
||||||
// Target: #{field.target_name} #{field.name}
|
// Target: #{field.target_name} #{field.name}
|
||||||
// Last Edited: #{field.updated_at}
|
// Last Edited: #{field.updated_at}
|
||||||
COMMENT
|
SCSS
|
||||||
|
|
||||||
contents << value
|
contents << value
|
||||||
end
|
end
|
||||||
@@ -216,13 +216,13 @@ module Stylesheet
|
|||||||
fonts_dir = UrlHelper.absolute("#{Discourse.base_path}/fonts")
|
fonts_dir = UrlHelper.absolute("#{Discourse.base_path}/fonts")
|
||||||
font[:variants].each do |variant|
|
font[:variants].each do |variant|
|
||||||
src = variant[:src] ? variant[:src] : "url(\"#{fonts_dir}/#{variant[:filename]}?v=#{DiscourseFonts::VERSION}\") format(\"#{variant[:format]}\")"
|
src = variant[:src] ? variant[:src] : "url(\"#{fonts_dir}/#{variant[:filename]}?v=#{DiscourseFonts::VERSION}\") format(\"#{variant[:format]}\")"
|
||||||
contents << <<~EOF
|
contents << <<~CSS
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: #{font[:name]};
|
font-family: #{font[:name]};
|
||||||
src: #{src};
|
src: #{src};
|
||||||
font-weight: #{variant[:weight]};
|
font-weight: #{variant[:weight]};
|
||||||
}
|
}
|
||||||
EOF
|
CSS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ task 'assets:precompile:before' do
|
|||||||
|
|
||||||
if EMBER_CLI && !(ENV["EMBER_CLI_COMPILE_DONE"] == "1")
|
if EMBER_CLI && !(ENV["EMBER_CLI_COMPILE_DONE"] == "1")
|
||||||
# Using exec to free up Rails app memory during ember build
|
# Using exec to free up Rails app memory during ember build
|
||||||
exec <<~SCRIPT
|
exec <<~SH
|
||||||
NODE_OPTIONS='--max-old-space-size=2048' yarn --cwd app/assets/javascripts/discourse run ember build -prod && \
|
NODE_OPTIONS='--max-old-space-size=2048' yarn --cwd app/assets/javascripts/discourse run ember build -prod && \
|
||||||
EMBER_CLI_COMPILE_DONE=1 bin/rake assets:precompile
|
EMBER_CLI_COMPILE_DONE=1 bin/rake assets:precompile
|
||||||
SCRIPT
|
SH
|
||||||
end
|
end
|
||||||
|
|
||||||
# Ensure we ALWAYS do a clean build
|
# Ensure we ALWAYS do a clean build
|
||||||
@@ -124,9 +124,9 @@ def compress_node(from, to)
|
|||||||
source_map_url = "#{File.basename(to)}.map"
|
source_map_url = "#{File.basename(to)}.map"
|
||||||
base_source_map = assets_path + assets_additional_path
|
base_source_map = assets_path + assets_additional_path
|
||||||
|
|
||||||
cmd = <<~EOS
|
cmd = <<~SH
|
||||||
terser '#{assets_path}/#{from}' -m -c -o '#{to_path}' --source-map "base='#{base_source_map}',root='#{source_map_root}',url='#{source_map_url}',includeSources=true"
|
terser '#{assets_path}/#{from}' -m -c -o '#{to_path}' --source-map "base='#{base_source_map}',root='#{source_map_root}',url='#{source_map_url}',includeSources=true"
|
||||||
EOS
|
SH
|
||||||
|
|
||||||
STDERR.puts cmd
|
STDERR.puts cmd
|
||||||
result = `#{cmd} 2>&1`
|
result = `#{cmd} 2>&1`
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
smtp = Discourse::Application.config.action_mailer.smtp_settings
|
smtp = Discourse::Application.config.action_mailer.smtp_settings
|
||||||
|
|
||||||
if smtp[:address].match(/smtp\.gmail\.com/)
|
if smtp[:address].match(/smtp\.gmail\.com/)
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
#{smtp}
|
#{smtp}
|
||||||
============================== WARNING ==============================
|
============================== WARNING ==============================
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
https://meta.discourse.org/t/discourse-aws-ec2-g-suite-troubleshooting/62931?u=pfaffman
|
https://meta.discourse.org/t/discourse-aws-ec2-g-suite-troubleshooting/62931?u=pfaffman
|
||||||
|
|
||||||
========================= CONTINUING TEST ============================
|
========================= CONTINUING TEST ============================
|
||||||
STR
|
TEXT
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "Testing sending to #{email} using #{smtp[:address]}:#{smtp[:port]}, username:#{smtp[:user_name]} with #{smtp[:authentication]} auth."
|
puts "Testing sending to #{email} using #{smtp[:address]}:#{smtp[:port]}, username:#{smtp[:user_name]} with #{smtp[:authentication]} auth."
|
||||||
@@ -93,21 +93,21 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
|
|
||||||
if e.to_s.match(/execution expired/)
|
if e.to_s.match(/execution expired/)
|
||||||
message = <<~STR
|
message = <<~TEXT
|
||||||
======================================== ERROR ========================================
|
======================================== ERROR ========================================
|
||||||
Connection to port #{smtp[:port]} failed.
|
Connection to port #{smtp[:port]} failed.
|
||||||
====================================== SOLUTION =======================================
|
====================================== SOLUTION =======================================
|
||||||
The most likely problem is that your server has outgoing SMTP traffic blocked.
|
The most likely problem is that your server has outgoing SMTP traffic blocked.
|
||||||
If you are using a service like Mailgun or Sendgrid, try using port 2525.
|
If you are using a service like Mailgun or Sendgrid, try using port 2525.
|
||||||
=======================================================================================
|
=======================================================================================
|
||||||
STR
|
TEXT
|
||||||
|
|
||||||
elsif e.to_s.match(/530.*STARTTLS/)
|
elsif e.to_s.match(/530.*STARTTLS/)
|
||||||
# We can't run a preliminary test with STARTTLS, we'll just try sending the test email.
|
# We can't run a preliminary test with STARTTLS, we'll just try sending the test email.
|
||||||
message = "OK"
|
message = "OK"
|
||||||
|
|
||||||
elsif e.to_s.match(/535/)
|
elsif e.to_s.match(/535/)
|
||||||
message = <<~STR
|
message = <<~TEXT
|
||||||
======================================== ERROR ========================================
|
======================================== ERROR ========================================
|
||||||
AUTHENTICATION FAILED
|
AUTHENTICATION FAILED
|
||||||
|
|
||||||
@@ -117,10 +117,10 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
The most likely problem is that your SMTP username and/or Password is incorrect.
|
The most likely problem is that your SMTP username and/or Password is incorrect.
|
||||||
Check them and try again.
|
Check them and try again.
|
||||||
=======================================================================================
|
=======================================================================================
|
||||||
STR
|
TEXT
|
||||||
|
|
||||||
elsif e.to_s.match(/Connection refused/)
|
elsif e.to_s.match(/Connection refused/)
|
||||||
message = <<~STR
|
message = <<~TEXT
|
||||||
======================================== ERROR ========================================
|
======================================== ERROR ========================================
|
||||||
CONNECTION REFUSED
|
CONNECTION REFUSED
|
||||||
|
|
||||||
@@ -132,10 +132,10 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
|
|
||||||
Check the port and your networking configuration.
|
Check the port and your networking configuration.
|
||||||
=======================================================================================
|
=======================================================================================
|
||||||
STR
|
TEXT
|
||||||
|
|
||||||
elsif e.to_s.match(/service not known/)
|
elsif e.to_s.match(/service not known/)
|
||||||
message = <<~STR
|
message = <<~TEXT
|
||||||
======================================== ERROR ========================================
|
======================================== ERROR ========================================
|
||||||
SMTP SERVER NOT FOUND
|
SMTP SERVER NOT FOUND
|
||||||
|
|
||||||
@@ -145,10 +145,10 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
The most likely problem is that the host name of your SMTP server is incorrect.
|
The most likely problem is that the host name of your SMTP server is incorrect.
|
||||||
Check it and try again.
|
Check it and try again.
|
||||||
=======================================================================================
|
=======================================================================================
|
||||||
STR
|
TEXT
|
||||||
|
|
||||||
else
|
else
|
||||||
message = <<~STR
|
message = <<~TEXT
|
||||||
======================================== ERROR ========================================
|
======================================== ERROR ========================================
|
||||||
UNEXPECTED ERROR
|
UNEXPECTED ERROR
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
Please report the exact error message above to https://meta.discourse.org/
|
Please report the exact error message above to https://meta.discourse.org/
|
||||||
(And a solution, if you find one!)
|
(And a solution, if you find one!)
|
||||||
=======================================================================================
|
=======================================================================================
|
||||||
STR
|
TEXT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if message == "OK"
|
if message == "OK"
|
||||||
@@ -174,13 +174,13 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
email_log = Email::Sender.new(TestMailer.send_test(email), :test_message).send
|
email_log = Email::Sender.new(TestMailer.send_test(email), :test_message).send
|
||||||
case email_log
|
case email_log
|
||||||
when SkippedEmailLog
|
when SkippedEmailLog
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
Mail was not sent.
|
Mail was not sent.
|
||||||
|
|
||||||
Reason: #{email_log.reason}
|
Reason: #{email_log.reason}
|
||||||
STR
|
TEXT
|
||||||
when EmailLog
|
when EmailLog
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
Mail accepted by SMTP server.
|
Mail accepted by SMTP server.
|
||||||
Message-ID: #{email_log.message_id}
|
Message-ID: #{email_log.message_id}
|
||||||
|
|
||||||
@@ -190,20 +190,20 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
If the message is not delivered it is not a problem with Discourse.
|
If the message is not delivered it is not a problem with Discourse.
|
||||||
Check the SMTP server logs for the above Message ID to see why it
|
Check the SMTP server logs for the above Message ID to see why it
|
||||||
failed to deliver the message.
|
failed to deliver the message.
|
||||||
STR
|
TEXT
|
||||||
when nil
|
when nil
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
Mail was not sent.
|
Mail was not sent.
|
||||||
|
|
||||||
Verify the status of the `disable_emails` site setting.
|
Verify the status of the `disable_emails` site setting.
|
||||||
STR
|
TEXT
|
||||||
else
|
else
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
SCRIPT BUG: Got back a #{email_log.class}
|
SCRIPT BUG: Got back a #{email_log.class}
|
||||||
#{email_log.inspect}
|
#{email_log.inspect}
|
||||||
|
|
||||||
Mail may or may not have been sent. Check the destination mailbox.
|
Mail may or may not have been sent. Check the destination mailbox.
|
||||||
STR
|
TEXT
|
||||||
end
|
end
|
||||||
rescue => error
|
rescue => error
|
||||||
puts "Sending mail failed."
|
puts "Sending mail failed."
|
||||||
@@ -211,11 +211,11 @@ task 'emails:test', [:email] => [:environment] do |_, args|
|
|||||||
end
|
end
|
||||||
|
|
||||||
if SiteSetting.disable_emails != 'no'
|
if SiteSetting.disable_emails != 'no'
|
||||||
puts <<~STR
|
puts <<~TEXT
|
||||||
|
|
||||||
### WARNING
|
### WARNING
|
||||||
The `disable_emails` site setting is currently set to #{SiteSetting.disable_emails}.
|
The `disable_emails` site setting is currently set to #{SiteSetting.disable_emails}.
|
||||||
Consider changing it to 'no' before performing any further troubleshooting.
|
Consider changing it to 'no' before performing any further troubleshooting.
|
||||||
STR
|
TEXT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def html_for_section(group)
|
|||||||
" {{replace-emoji \":#{icon['name']}:\" (hash lazy=true#{class_attr})}}"
|
" {{replace-emoji \":#{icon['name']}:\" (hash lazy=true#{class_attr})}}"
|
||||||
end
|
end
|
||||||
|
|
||||||
<<~SECTION
|
<<~HTML
|
||||||
<div class="section" data-section="#{group["name"]}">
|
<div class="section" data-section="#{group["name"]}">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<span class="title">{{i18n "emoji_picker.#{group["name"]}"}}</span>
|
<span class="title">{{i18n "emoji_picker.#{group["name"]}"}}</span>
|
||||||
@@ -31,14 +31,14 @@ def html_for_section(group)
|
|||||||
#{icons.join("\n").strip}
|
#{icons.join("\n").strip}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
SECTION
|
HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_template(path, task_name, template)
|
def write_template(path, task_name, template)
|
||||||
header = <<~HEADER
|
header = <<~JS
|
||||||
// DO NOT EDIT THIS FILE!!!
|
// DO NOT EDIT THIS FILE!!!
|
||||||
// Update it by running `rake javascript:#{task_name}`
|
// Update it by running `rake javascript:#{task_name}`
|
||||||
HEADER
|
JS
|
||||||
|
|
||||||
basename = File.basename(path)
|
basename = File.basename(path)
|
||||||
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
||||||
@@ -50,10 +50,10 @@ def write_template(path, task_name, template)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def write_hbs_template(path, task_name, template)
|
def write_hbs_template(path, task_name, template)
|
||||||
header = <<~HEADER
|
header = <<~HBS
|
||||||
{{!-- DO NOT EDIT THIS FILE!!! --}}
|
{{!-- DO NOT EDIT THIS FILE!!! --}}
|
||||||
{{!-- Update it by running `rake javascript:#{task_name}` --}}
|
{{!-- Update it by running `rake javascript:#{task_name}` --}}
|
||||||
HEADER
|
HBS
|
||||||
|
|
||||||
basename = File.basename(path)
|
basename = File.basename(path)
|
||||||
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
||||||
@@ -244,11 +244,11 @@ task 'javascript:update_constants' => :environment do
|
|||||||
groups_json = JSON.parse(File.read("lib/emoji/groups.json"))
|
groups_json = JSON.parse(File.read("lib/emoji/groups.json"))
|
||||||
|
|
||||||
emoji_buttons = groups_json.map do |group|
|
emoji_buttons = groups_json.map do |group|
|
||||||
<<~BUTTON
|
<<~HTML
|
||||||
<button type="button" data-section="#{group["name"]}" {{action onCategorySelection "#{group["name"]}"}} class="btn btn-default category-button emoji">
|
<button type="button" data-section="#{group["name"]}" {{action onCategorySelection "#{group["name"]}"}} class="btn btn-default category-button emoji">
|
||||||
{{replace-emoji ":#{group["tabicon"]}:"}}
|
{{replace-emoji ":#{group["tabicon"]}:"}}
|
||||||
</button>
|
</button>
|
||||||
BUTTON
|
HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
emoji_sections = groups_json.map { |group| html_for_section(group) }
|
emoji_sections = groups_json.map { |group| html_for_section(group) }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Generates posts and topics
|
# Generates posts and topics
|
||||||
class Populate < Thor
|
class Populate < Thor
|
||||||
desc "posts", "Generate posts"
|
desc "posts", "Generate posts"
|
||||||
long_desc <<-LONGDESC
|
long_desc <<-MD
|
||||||
Create topics with any number of posts, or add posts to an existing topic.
|
Create topics with any number of posts, or add posts to an existing topic.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@@ -20,7 +20,7 @@ class Populate < Thor
|
|||||||
|
|
||||||
> $ thor populate:posts -p 10 -n 5
|
> $ thor populate:posts -p 10 -n 5
|
||||||
|
|
||||||
LONGDESC
|
MD
|
||||||
method_option :num_posts, aliases: '-n', type: :numeric, required: true, desc: "Number of posts to make"
|
method_option :num_posts, aliases: '-n', type: :numeric, required: true, desc: "Number of posts to make"
|
||||||
method_option :users, aliases: '-u', type: :array, desc: "Usernames of users who will make the posts"
|
method_option :users, aliases: '-u', type: :array, desc: "Usernames of users who will make the posts"
|
||||||
method_option :title, aliases: '-t', desc: "The title of the topic, if making a new topic"
|
method_option :title, aliases: '-t', desc: "The title of the topic, if making a new topic"
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ task "themes:qunit", :type, :value do |t, args|
|
|||||||
type = args[:type]
|
type = args[:type]
|
||||||
value = args[:value]
|
value = args[:value]
|
||||||
if !%w(name url id).include?(type) || value.blank?
|
if !%w(name url id).include?(type) || value.blank?
|
||||||
raise <<~MSG
|
raise <<~TEXT
|
||||||
Wrong arguments type:#{type.inspect}, value:#{value.inspect}"
|
Wrong arguments type:#{type.inspect}, value:#{value.inspect}"
|
||||||
Usage:
|
Usage:
|
||||||
`bundle exec rake "themes:qunit[url,<theme_url>]"`
|
`bundle exec rake "themes:qunit[url,<theme_url>]"`
|
||||||
@@ -126,7 +126,7 @@ task "themes:qunit", :type, :value do |t, args|
|
|||||||
`bundle exec rake "themes:qunit[name,<theme_name>]"`
|
`bundle exec rake "themes:qunit[name,<theme_name>]"`
|
||||||
OR
|
OR
|
||||||
`bundle exec rake "themes:qunit[id,<theme_id>]"`
|
`bundle exec rake "themes:qunit[id,<theme_id>]"`
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
ENV["THEME_#{type.upcase}"] = value.to_s
|
ENV["THEME_#{type.upcase}"] = value.to_s
|
||||||
ENV["QUNIT_RAILS_ENV"] ||= 'development' # qunit:test will switch to `test` by default
|
ENV["QUNIT_RAILS_ENV"] ||= 'development' # qunit:test will switch to `test` by default
|
||||||
|
|||||||
@@ -165,11 +165,11 @@ def clean_up_uploads
|
|||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
puts <<~OUTPUT
|
puts <<~TEXT
|
||||||
This task will remove upload records and files permanently.
|
This task will remove upload records and files permanently.
|
||||||
|
|
||||||
Would you like to take a full backup before the clean up? (Y/N)
|
Would you like to take a full backup before the clean up? (Y/N)
|
||||||
OUTPUT
|
TEXT
|
||||||
|
|
||||||
if STDIN.gets.chomp.downcase == 'y'
|
if STDIN.gets.chomp.downcase == 'y'
|
||||||
puts "Starting backup..."
|
puts "Starting backup..."
|
||||||
@@ -420,7 +420,7 @@ task "uploads:analyze", [:cache_path, :limit] => :environment do |_, args|
|
|||||||
uploads_count = Upload.count
|
uploads_count = Upload.count
|
||||||
optimized_images_count = OptimizedImage.count
|
optimized_images_count = OptimizedImage.count
|
||||||
|
|
||||||
puts <<~REPORT
|
puts <<~TEXT
|
||||||
Report for '#{current_db}'
|
Report for '#{current_db}'
|
||||||
-----------#{'-' * current_db.length}
|
-----------#{'-' * current_db.length}
|
||||||
Number of `Upload` records in DB: #{uploads_count}
|
Number of `Upload` records in DB: #{uploads_count}
|
||||||
@@ -430,7 +430,7 @@ task "uploads:analyze", [:cache_path, :limit] => :environment do |_, args|
|
|||||||
Number of images in uploads folder: #{paths_count}
|
Number of images in uploads folder: #{paths_count}
|
||||||
------------------------------------#{'-' * paths_count.to_s.length}
|
------------------------------------#{'-' * paths_count.to_s.length}
|
||||||
|
|
||||||
REPORT
|
TEXT
|
||||||
|
|
||||||
helper = Class.new do
|
helper = Class.new do
|
||||||
include ActionView::Helpers::NumberHelper
|
include ActionView::Helpers::NumberHelper
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ describe PrettyText do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'can replace spoilers in emails' do
|
it 'can replace spoilers in emails' do
|
||||||
md = PrettyText.cook(<<~EOF)
|
md = PrettyText.cook(<<~MD)
|
||||||
hello
|
hello
|
||||||
|
|
||||||
[details="Summary"]
|
[details="Summary"]
|
||||||
world
|
world
|
||||||
[/details]
|
[/details]
|
||||||
EOF
|
MD
|
||||||
md = PrettyText.format_for_email(md, post)
|
md = PrettyText.format_for_email(md, post)
|
||||||
html = "<p>hello</p>\n\nSummary <a href=\"#{post.full_url}\">(click for more details)</a>"
|
html = "<p>hello</p>\n\nSummary <a href=\"#{post.full_url}\">(click for more details)</a>"
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ describe PrettyText do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'properly handles multiple spoiler blocks in a post' do
|
it 'properly handles multiple spoiler blocks in a post' do
|
||||||
md = PrettyText.cook(<<~EOF)
|
md = PrettyText.cook(<<~MD)
|
||||||
[details="First"]
|
[details="First"]
|
||||||
body secret stuff very long
|
body secret stuff very long
|
||||||
[/details]
|
[/details]
|
||||||
@@ -55,7 +55,7 @@ describe PrettyText do
|
|||||||
[details="Third"]
|
[details="Third"]
|
||||||
body secret stuff very long
|
body secret stuff very long
|
||||||
[/details]
|
[/details]
|
||||||
EOF
|
MD
|
||||||
|
|
||||||
md = PrettyText.format_for_email(md, post)
|
md = PrettyText.format_for_email(md, post)
|
||||||
expect(md).not_to include('secret stuff')
|
expect(md).not_to include('secret stuff')
|
||||||
@@ -65,12 +65,12 @@ describe PrettyText do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'escapes summary text' do
|
it 'escapes summary text' do
|
||||||
md = PrettyText.cook(<<~EOF)
|
md = PrettyText.cook(<<~MD)
|
||||||
<script>alert('hello')</script>
|
<script>alert('hello')</script>
|
||||||
[details="<script>alert('hello')</script>"]
|
[details="<script>alert('hello')</script>"]
|
||||||
<script>alert('hello')</script>
|
<script>alert('hello')</script>
|
||||||
[/details]
|
[/details]
|
||||||
EOF
|
MD
|
||||||
md = PrettyText.format_for_email(md, post)
|
md = PrettyText.format_for_email(md, post)
|
||||||
|
|
||||||
expect(md).not_to include('<script>')
|
expect(md).not_to include('<script>')
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ RSpec.describe "Local Dates" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should work without timezone" do
|
it "should work without timezone" do
|
||||||
post = Fabricate(:post, raw: <<~TXT)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
[date=2018-05-08 time=22:00 format="L LTS" timezones="Europe/Paris|America/Los_Angeles"]
|
[date=2018-05-08 time=22:00 format="L LTS" timezones="Europe/Paris|America/Los_Angeles"]
|
||||||
TXT
|
MD
|
||||||
|
|
||||||
cooked = post.cooked
|
cooked = post.cooked
|
||||||
|
|
||||||
@@ -28,9 +28,9 @@ RSpec.describe "Local Dates" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should work with timezone" do
|
it "should work with timezone" do
|
||||||
post = Fabricate(:post, raw: <<~TXT)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
[date=2018-05-08 time=22:00 format="L LTS" timezone="Asia/Calcutta" timezones="Europe/Paris|America/Los_Angeles"]
|
[date=2018-05-08 time=22:00 format="L LTS" timezone="Asia/Calcutta" timezones="Europe/Paris|America/Los_Angeles"]
|
||||||
TXT
|
MD
|
||||||
|
|
||||||
cooked = post.cooked
|
cooked = post.cooked
|
||||||
|
|
||||||
@@ -39,9 +39,9 @@ RSpec.describe "Local Dates" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'requires the right attributes to convert to a local date' do
|
it 'requires the right attributes to convert to a local date' do
|
||||||
post = Fabricate(:post, raw: <<~TXT)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
[date]
|
[date]
|
||||||
TXT
|
MD
|
||||||
|
|
||||||
cooked = post.cooked
|
cooked = post.cooked
|
||||||
|
|
||||||
@@ -50,9 +50,9 @@ RSpec.describe "Local Dates" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'requires the right attributes to convert to a local date' do
|
it 'requires the right attributes to convert to a local date' do
|
||||||
post = Fabricate(:post, raw: <<~TXT)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
[date]
|
[date]
|
||||||
TXT
|
MD
|
||||||
|
|
||||||
cooked = post.cooked
|
cooked = post.cooked
|
||||||
|
|
||||||
|
|||||||
@@ -163,11 +163,11 @@ module DiscourseNarrativeBot
|
|||||||
def start_advanced_track
|
def start_advanced_track
|
||||||
raw = I18n.t("#{I18N_KEY}.start_message", i18n_post_args(username: @user.username))
|
raw = I18n.t("#{I18N_KEY}.start_message", i18n_post_args(username: @user.username))
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{raw}
|
#{raw}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
opts = {
|
opts = {
|
||||||
title: I18n.t("#{I18N_KEY}.title"),
|
title: I18n.t("#{I18N_KEY}.title"),
|
||||||
@@ -197,11 +197,11 @@ module DiscourseNarrativeBot
|
|||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.edit.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.edit.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
reply_to(@post, raw)
|
reply_to(@post, raw)
|
||||||
end
|
end
|
||||||
@@ -227,11 +227,11 @@ module DiscourseNarrativeBot
|
|||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.delete.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.delete.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
PostCreator.create!(self.discobot_user,
|
PostCreator.create!(self.discobot_user,
|
||||||
raw: raw,
|
raw: raw,
|
||||||
@@ -252,11 +252,11 @@ module DiscourseNarrativeBot
|
|||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.recover.reply", i18n_post_args(deletion_after: SiteSetting.delete_removed_posts_after))}
|
#{I18n.t("#{I18N_KEY}.recover.reply", i18n_post_args(deletion_after: SiteSetting.delete_removed_posts_after))}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
PostCreator.create!(self.discobot_user,
|
PostCreator.create!(self.discobot_user,
|
||||||
raw: raw,
|
raw: raw,
|
||||||
@@ -279,11 +279,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(topic_id)
|
return unless valid_topic?(topic_id)
|
||||||
|
|
||||||
if Nokogiri::HTML5.fragment(@post.cooked).css('.hashtag').size > 0
|
if Nokogiri::HTML5.fragment(@post.cooked).css('.hashtag').size > 0
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.category_hashtag.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.category_hashtag.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
reply_to(@post, raw)
|
reply_to(@post, raw)
|
||||||
@@ -308,11 +308,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(@topic_id)
|
return unless valid_topic?(@topic_id)
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.change_topic_notification_level.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.change_topic_notification_level.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -330,11 +330,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(topic_id)
|
return unless valid_topic?(topic_id)
|
||||||
|
|
||||||
if Nokogiri::HTML5.fragment(@post.cooked).css(".poll").size > 0
|
if Nokogiri::HTML5.fragment(@post.cooked).css(".poll").size > 0
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.poll.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.poll.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
reply_to(@post, raw)
|
reply_to(@post, raw)
|
||||||
|
|||||||
@@ -175,11 +175,11 @@ module DiscourseNarrativeBot
|
|||||||
|
|
||||||
MessageBus.publish('/new_user_narrative/tutorial_search', {}, user_ids: [@user.id])
|
MessageBus.publish('/new_user_narrative/tutorial_search', {}, user_ids: [@user.id])
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{post.raw}
|
#{post.raw}
|
||||||
|
|
||||||
#{I18n.t("#{I18N_KEY}.search.hidden_message", i18n_post_args.merge(search_answer: NewUserNarrative.search_answer))}
|
#{I18n.t("#{I18N_KEY}.search.hidden_message", i18n_post_args.merge(search_answer: NewUserNarrative.search_answer))}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
PostRevisor.new(post, topic).revise!(
|
PostRevisor.new(post, topic).revise!(
|
||||||
self.discobot_user,
|
self.discobot_user,
|
||||||
@@ -206,11 +206,11 @@ module DiscourseNarrativeBot
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{raw}
|
#{raw}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
title = I18n.t("#{I18N_KEY}.hello.title", title: SiteSetting.title)
|
title = I18n.t("#{I18N_KEY}.hello.title", title: SiteSetting.title)
|
||||||
if SiteSetting.max_emojis_in_title == 0
|
if SiteSetting.max_emojis_in_title == 0
|
||||||
@@ -259,11 +259,11 @@ module DiscourseNarrativeBot
|
|||||||
|
|
||||||
profile_page_url = url_helpers(:user_url, username: @user.username)
|
profile_page_url = url_helpers(:user_url, username: @user.username)
|
||||||
bookmark_url = "#{profile_page_url}/activity/bookmarks"
|
bookmark_url = "#{profile_page_url}/activity/bookmarks"
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.bookmark.reply", i18n_post_args(bookmark_url: bookmark_url))}
|
#{I18n.t("#{I18N_KEY}.bookmark.reply", i18n_post_args(bookmark_url: bookmark_url))}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -279,11 +279,11 @@ module DiscourseNarrativeBot
|
|||||||
@post.post_analyzer.cook(@post.raw, {})
|
@post.post_analyzer.cook(@post.raw, {})
|
||||||
|
|
||||||
if @post.post_analyzer.found_oneboxes?
|
if @post.post_analyzer.found_oneboxes?
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.onebox.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.onebox.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -315,11 +315,11 @@ module DiscourseNarrativeBot
|
|||||||
fake_delay
|
fake_delay
|
||||||
like_post(post)
|
like_post(post)
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
reply = reply_to(@post, raw)
|
reply = reply_to(@post, raw)
|
||||||
enqueue_timeout_job(@user)
|
enqueue_timeout_job(@user)
|
||||||
@@ -350,11 +350,11 @@ module DiscourseNarrativeBot
|
|||||||
set_state_data(:post_id, @post.id)
|
set_state_data(:post_id, @post.id)
|
||||||
|
|
||||||
if get_state_data(:liked)
|
if get_state_data(:liked)
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
like_post(@post)
|
like_post(@post)
|
||||||
else
|
else
|
||||||
@@ -405,11 +405,11 @@ module DiscourseNarrativeBot
|
|||||||
)
|
)
|
||||||
|
|
||||||
if post_liked
|
if post_liked
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.likes.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.likes.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -426,11 +426,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(post_topic_id)
|
return unless valid_topic?(post_topic_id)
|
||||||
|
|
||||||
if Nokogiri::HTML5.fragment(@post.cooked).css("b", "strong", "em", "i", ".bbcode-i", ".bbcode-b").size > 0
|
if Nokogiri::HTML5.fragment(@post.cooked).css("b", "strong", "em", "i", ".bbcode-i", ".bbcode-b").size > 0
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.formatting.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.formatting.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -452,11 +452,11 @@ module DiscourseNarrativeBot
|
|||||||
doc = Nokogiri::HTML5.fragment(@post.cooked)
|
doc = Nokogiri::HTML5.fragment(@post.cooked)
|
||||||
|
|
||||||
if doc.css(".quote").size > 0
|
if doc.css(".quote").size > 0
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.quoting.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.quoting.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -478,11 +478,11 @@ module DiscourseNarrativeBot
|
|||||||
doc = Nokogiri::HTML5.fragment(@post.cooked)
|
doc = Nokogiri::HTML5.fragment(@post.cooked)
|
||||||
|
|
||||||
if doc.css(".emoji").size > 0
|
if doc.css(".emoji").size > 0
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.emoji.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.emoji.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -502,11 +502,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(post_topic_id)
|
return unless valid_topic?(post_topic_id)
|
||||||
|
|
||||||
if bot_mentioned?(@post)
|
if bot_mentioned?(@post)
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.mention.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.mention.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
@@ -552,11 +552,11 @@ module DiscourseNarrativeBot
|
|||||||
return unless valid_topic?(post_topic_id)
|
return unless valid_topic?(post_topic_id)
|
||||||
return unless @post.user.id == -2
|
return unless @post.user.id == -2
|
||||||
|
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
#{I18n.t("#{I18N_KEY}.flag.reply", i18n_post_args)}
|
#{I18n.t("#{I18N_KEY}.flag.reply", i18n_post_args)}
|
||||||
|
|
||||||
#{instance_eval(&@next_instructions)}
|
#{instance_eval(&@next_instructions)}
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
fake_delay
|
fake_delay
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class Onebox::Engine::YoutubeOnebox
|
|||||||
# Put in the LazyYT div instead of the iframe
|
# Put in the LazyYT div instead of the iframe
|
||||||
escaped_title = ERB::Util.html_escape(video_title)
|
escaped_title = ERB::Util.html_escape(video_title)
|
||||||
|
|
||||||
<<~EOF
|
<<~HTML
|
||||||
<div class="onebox lazyYT lazyYT-container"
|
<div class="onebox lazyYT lazyYT-container"
|
||||||
data-youtube-id="#{video_id}"
|
data-youtube-id="#{video_id}"
|
||||||
data-youtube-title="#{escaped_title}"
|
data-youtube-title="#{escaped_title}"
|
||||||
@@ -49,7 +49,7 @@ class Onebox::Engine::YoutubeOnebox
|
|||||||
title="#{escaped_title}">
|
title="#{escaped_title}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
EOF
|
HTML
|
||||||
else
|
else
|
||||||
yt_onebox_to_html
|
yt_onebox_to_html
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ describe NewPostManager do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 're-validates the poll when the approve_post event is triggered' do
|
it 're-validates the poll when the approve_post event is triggered' do
|
||||||
invalid_raw_poll = <<~RAW
|
invalid_raw_poll = <<~MD
|
||||||
[poll type=multiple min=0]
|
[poll type=multiple min=0]
|
||||||
* 1
|
* 1
|
||||||
* 2
|
* 2
|
||||||
[/poll]
|
[/poll]
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
result = NewPostManager.new(user, params).perform
|
result = NewPostManager.new(user, params).perform
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
require "pg"
|
require "pg"
|
||||||
|
|
||||||
usage = <<-END
|
usage = <<-TEXT
|
||||||
Commands:
|
Commands:
|
||||||
ruby db_timestamp_updater.rb yesterday <date> move all timestamps by x days so that <date> will be moved to yesterday
|
ruby db_timestamp_updater.rb yesterday <date> move all timestamps by x days so that <date> will be moved to yesterday
|
||||||
ruby db_timestamp_updater.rb 100 move all timestamps forward by 100 days
|
ruby db_timestamp_updater.rb 100 move all timestamps forward by 100 days
|
||||||
ruby db_timestamp_updater.rb -100 move all timestamps backward by 100 days
|
ruby db_timestamp_updater.rb -100 move all timestamps backward by 100 days
|
||||||
END
|
TEXT
|
||||||
|
|
||||||
class TimestampsUpdater
|
class TimestampsUpdater
|
||||||
def initialize(schema, ignore_tables)
|
def initialize(schema, ignore_tables)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class DiscourseCLI < Thor
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc "remap [--global,--regex] FROM TO", "Remap a string sequence across all tables"
|
desc "remap [--global,--regex] FROM TO", "Remap a string sequence across all tables"
|
||||||
long_desc <<-LONGDESC
|
long_desc <<-TEXT
|
||||||
Replace a string sequence FROM with TO across all tables.
|
Replace a string sequence FROM with TO across all tables.
|
||||||
|
|
||||||
With --global option, the remapping is run on ***ALL***
|
With --global option, the remapping is run on ***ALL***
|
||||||
@@ -30,7 +30,7 @@ class DiscourseCLI < Thor
|
|||||||
discourse remap talk.foo.com talk.bar.com # renaming a Discourse domain name
|
discourse remap talk.foo.com talk.bar.com # renaming a Discourse domain name
|
||||||
|
|
||||||
discourse remap --regex "\[\/?color(=[^\]]*)*]" "" # removing "color" bbcodes
|
discourse remap --regex "\[\/?color(=[^\]]*)*]" "" # removing "color" bbcodes
|
||||||
LONGDESC
|
TEXT
|
||||||
option :global, type: :boolean
|
option :global, type: :boolean
|
||||||
option :regex, type: :boolean
|
option :regex, type: :boolean
|
||||||
def remap(from, to)
|
def remap(from, to)
|
||||||
|
|||||||
@@ -85,11 +85,11 @@ def crawl_topics
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
if start == 1 && find("h2").text == "Error 403"
|
if start == 1 && find("h2").text == "Error 403"
|
||||||
exit_with_error(<<~MSG.red.bold)
|
exit_with_error(<<~TEXT.red.bold)
|
||||||
Unable to find topics. Try running the script with the "--domain example.com"
|
Unable to find topics. Try running the script with the "--domain example.com"
|
||||||
option if you are a G Suite user and your group's URL contains a path with
|
option if you are a G Suite user and your group's URL contains a path with
|
||||||
your domain that looks like "/a/example.com".
|
your domain that looks like "/a/example.com".
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||||
# Ignore this error. It simply means there wasn't an error.
|
# Ignore this error. It simply means there wasn't an error.
|
||||||
@@ -151,10 +151,10 @@ def crawl_message(url, might_be_deleted)
|
|||||||
@first_message_checked = true
|
@first_message_checked = true
|
||||||
|
|
||||||
if content.match?(/From:.*\.\.\.@.*/i) && !@force_import
|
if content.match?(/From:.*\.\.\.@.*/i) && !@force_import
|
||||||
exit_with_error(<<~MSG.red.bold)
|
exit_with_error(<<~TEXT.red.bold)
|
||||||
It looks like you do not have permissions to see email addresses. Aborting.
|
It looks like you do not have permissions to see email addresses. Aborting.
|
||||||
Use the --force option to import anyway.
|
Use the --force option to import anyway.
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -114,28 +114,28 @@ class ImportScripts::IpboardSQL < ImportScripts::Base
|
|||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts '=' * 50
|
puts '=' * 50
|
||||||
puts e.message
|
puts e.message
|
||||||
puts <<EOM
|
puts <<~TEXT
|
||||||
Cannot log in to database.
|
Cannot log in to database.
|
||||||
|
|
||||||
Hostname: #{DB_HOST}
|
Hostname: #{DB_HOST}
|
||||||
Username: #{DB_USER}
|
Username: #{DB_USER}
|
||||||
Password: #{DB_PW}
|
Password: #{DB_PW}
|
||||||
database: #{DB_NAME}
|
database: #{DB_NAME}
|
||||||
|
|
||||||
You should set these variables:
|
You should set these variables:
|
||||||
|
|
||||||
export DB_HOST="localhost"
|
export DB_HOST="localhost"
|
||||||
export DB_NAME="ipboard"
|
export DB_NAME="ipboard"
|
||||||
export DB_PW="ipboard"
|
export DB_PW="ipboard"
|
||||||
export DB_USER="ipboard"
|
export DB_USER="ipboard"
|
||||||
export TABLE_PREFIX="ipb_"
|
export TABLE_PREFIX="ipb_"
|
||||||
export IMPORT_AFTER="1970-01-01"
|
export IMPORT_AFTER="1970-01-01"
|
||||||
export URL="http://example.com"
|
export URL="http://example.com"
|
||||||
export UPLOADS=
|
export UPLOADS=
|
||||||
export USERDIR="user"
|
export USERDIR="user"
|
||||||
|
|
||||||
Exiting.
|
Exiting.
|
||||||
EOM
|
TEXT
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -43,25 +43,25 @@ class ImportScripts::Modx < ImportScripts::Base
|
|||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts '=' * 50
|
puts '=' * 50
|
||||||
puts e.message
|
puts e.message
|
||||||
puts <<EOM
|
puts <<~TEXT
|
||||||
Cannot connect in to database.
|
Cannot connect in to database.
|
||||||
|
|
||||||
Hostname: #{DB_HOST}
|
Hostname: #{DB_HOST}
|
||||||
Username: #{DB_USER}
|
Username: #{DB_USER}
|
||||||
Password: #{DB_PW}
|
Password: #{DB_PW}
|
||||||
database: #{DB_NAME}
|
database: #{DB_NAME}
|
||||||
|
|
||||||
Edit the script or set these environment variables:
|
Edit the script or set these environment variables:
|
||||||
|
|
||||||
export DB_HOST="localhost"
|
export DB_HOST="localhost"
|
||||||
export DB_NAME="modx"
|
export DB_NAME="modx"
|
||||||
export DB_PW="modx"
|
export DB_PW="modx"
|
||||||
export DB_USER="modx"
|
export DB_USER="modx"
|
||||||
export TABLE_PREFIX="modx_"
|
export TABLE_PREFIX="modx_"
|
||||||
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
|
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
|
||||||
|
|
||||||
Exiting.
|
Exiting.
|
||||||
EOM
|
TEXT
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -446,12 +446,12 @@ FROM #{TABLE_PREFIX}discuss_users
|
|||||||
# keep track of closed topics
|
# keep track of closed topics
|
||||||
closed_topic_ids = []
|
closed_topic_ids = []
|
||||||
|
|
||||||
topics = mysql_query <<-MYSQL
|
topics = mysql_query <<-SQL
|
||||||
SELECT t.threadid threadid, firstpostid, open
|
SELECT t.threadid threadid, firstpostid, open
|
||||||
FROM #{TABLE_PREFIX}thread t
|
FROM #{TABLE_PREFIX}thread t
|
||||||
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
|
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
|
||||||
ORDER BY t.threadid
|
ORDER BY t.threadid
|
||||||
MYSQL
|
SQL
|
||||||
topics.each do |topic|
|
topics.each do |topic|
|
||||||
topic_id = "thread-#{topic["threadid"]}"
|
topic_id = "thread-#{topic["threadid"]}"
|
||||||
closed_topic_ids << topic_id if topic["open"] == 0
|
closed_topic_ids << topic_id if topic["open"] == 0
|
||||||
|
|||||||
@@ -58,27 +58,27 @@ class ImportScripts::MylittleforumSQL < ImportScripts::Base
|
|||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts '=' * 50
|
puts '=' * 50
|
||||||
puts e.message
|
puts e.message
|
||||||
puts <<EOM
|
puts <<~TEXT
|
||||||
Cannot log in to database.
|
Cannot log in to database.
|
||||||
|
|
||||||
Hostname: #{DB_HOST}
|
Hostname: #{DB_HOST}
|
||||||
Username: #{DB_USER}
|
Username: #{DB_USER}
|
||||||
Password: #{DB_PW}
|
Password: #{DB_PW}
|
||||||
database: #{DB_NAME}
|
database: #{DB_NAME}
|
||||||
|
|
||||||
You should set these variables:
|
You should set these variables:
|
||||||
|
|
||||||
export DB_HOST="localhost"
|
export DB_HOST="localhost"
|
||||||
export DB_NAME="mylittleforum"
|
export DB_NAME="mylittleforum"
|
||||||
export DB_PW=""
|
export DB_PW=""
|
||||||
export DB_USER="root"
|
export DB_USER="root"
|
||||||
export TABLE_PREFIX="forum_"
|
export TABLE_PREFIX="forum_"
|
||||||
export IMPORT_AFTER="1970-01-01"
|
export IMPORT_AFTER="1970-01-01"
|
||||||
export IMAGE_BASE="http://www.example.com/forum"
|
export IMAGE_BASE="http://www.example.com/forum"
|
||||||
export BASE="forum"
|
export BASE="forum"
|
||||||
|
|
||||||
Exiting.
|
Exiting.
|
||||||
EOM
|
TEXT
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ module ImportScripts::PhpBB3
|
|||||||
require_relative 'database_3_1'
|
require_relative 'database_3_1'
|
||||||
Database_3_1.new(@database_client, @database_settings)
|
Database_3_1.new(@database_client, @database_settings)
|
||||||
else
|
else
|
||||||
raise UnsupportedVersionError, <<~MSG
|
raise UnsupportedVersionError, <<~TEXT
|
||||||
Unsupported version (#{version}) of phpBB detected.
|
Unsupported version (#{version}) of phpBB detected.
|
||||||
Currently only version 3.0, 3.1 and 3.2 are supported by this importer.
|
Currently only version 3.0, 3.1 and 3.2 are supported by this importer.
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -53,25 +53,25 @@ class ImportScripts::VBulletin < ImportScripts::Base
|
|||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts '=' * 50
|
puts '=' * 50
|
||||||
puts e.message
|
puts e.message
|
||||||
puts <<EOM
|
puts <<~TEXT
|
||||||
Cannot connect in to database.
|
Cannot connect in to database.
|
||||||
|
|
||||||
Hostname: #{DB_HOST}
|
Hostname: #{DB_HOST}
|
||||||
Username: #{DB_USER}
|
Username: #{DB_USER}
|
||||||
Password: #{DB_PW}
|
Password: #{DB_PW}
|
||||||
database: #{DB_NAME}
|
database: #{DB_NAME}
|
||||||
|
|
||||||
Edit the script or set these environment variables:
|
Edit the script or set these environment variables:
|
||||||
|
|
||||||
export DB_HOST="localhost"
|
export DB_HOST="localhost"
|
||||||
export DB_NAME="vbulletin"
|
export DB_NAME="vbulletin"
|
||||||
export DB_PW=""
|
export DB_PW=""
|
||||||
export DB_USER="root"
|
export DB_USER="root"
|
||||||
export TABLE_PREFIX="vb_"
|
export TABLE_PREFIX="vb_"
|
||||||
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
|
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
|
||||||
|
|
||||||
Exiting.
|
Exiting.
|
||||||
EOM
|
TEXT
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -674,12 +674,12 @@ EOM
|
|||||||
# keep track of closed topics
|
# keep track of closed topics
|
||||||
closed_topic_ids = []
|
closed_topic_ids = []
|
||||||
|
|
||||||
topics = mysql_query <<-MYSQL
|
topics = mysql_query <<-SQL
|
||||||
SELECT t.threadid threadid, firstpostid, open
|
SELECT t.threadid threadid, firstpostid, open
|
||||||
FROM #{TABLE_PREFIX}thread t
|
FROM #{TABLE_PREFIX}thread t
|
||||||
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
|
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
|
||||||
ORDER BY t.threadid
|
ORDER BY t.threadid
|
||||||
MYSQL
|
SQL
|
||||||
topics.each do |topic|
|
topics.each do |topic|
|
||||||
topic_id = "thread-#{topic["threadid"]}"
|
topic_id = "thread-#{topic["threadid"]}"
|
||||||
closed_topic_ids << topic_id if topic["open"] == 0
|
closed_topic_ids << topic_id if topic["open"] == 0
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ end
|
|||||||
puts 'Done! File moves are staged and ready for commit.'
|
puts 'Done! File moves are staged and ready for commit.'
|
||||||
puts 'Suggested commit message:'
|
puts 'Suggested commit message:'
|
||||||
puts '-' * 20
|
puts '-' * 20
|
||||||
puts <<~MESSAGE
|
puts <<~TEXT
|
||||||
DEV: Promote historic post_deploy migrations
|
DEV: Promote historic post_deploy migrations
|
||||||
|
|
||||||
This commit promotes all post_deploy migrations which existed in Discourse #{previous_stable_version} (timestamp <= #{promote_threshold})
|
This commit promotes all post_deploy migrations which existed in Discourse #{previous_stable_version} (timestamp <= #{promote_threshold})
|
||||||
MESSAGE
|
TEXT
|
||||||
puts '-' * 20
|
puts '-' * 20
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Fabricator(:incoming_email) do
|
|||||||
imap_sync false
|
imap_sync false
|
||||||
created_via 0
|
created_via 0
|
||||||
|
|
||||||
raw <<~RAW
|
raw <<~EMAIL
|
||||||
Return-Path: <foo@example.com>
|
Return-Path: <foo@example.com>
|
||||||
From: Foo <foo@example.com>
|
From: Foo <foo@example.com>
|
||||||
To: someone@else.com
|
To: someone@else.com
|
||||||
@@ -20,5 +20,5 @@ Fabricator(:incoming_email) do
|
|||||||
Content-Transfer-Encoding: quoted-printable
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
The body contains "Hello world" too.
|
The body contains "Hello world" too.
|
||||||
RAW
|
EMAIL
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -102,20 +102,20 @@ Fabricator(:post_with_uploads, from: :post) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:post_with_uploads_and_links, from: :post) do
|
Fabricator(:post_with_uploads_and_links, from: :post) do
|
||||||
raw <<~RAW
|
raw <<~MD
|
||||||
<a href="/#{Discourse.store.upload_path}/original/2X/2345678901234567.jpg">Link</a>
|
<a href="/#{Discourse.store.upload_path}/original/2X/2345678901234567.jpg">Link</a>
|
||||||
<img src="/#{Discourse.store.upload_path}/original/1X/1234567890123456.jpg">
|
<img src="/#{Discourse.store.upload_path}/original/1X/1234567890123456.jpg">
|
||||||
<a href="http://www.google.com">Google</a>
|
<a href="http://www.google.com">Google</a>
|
||||||
<img src="http://foo.bar/image.png">
|
<img src="http://foo.bar/image.png">
|
||||||
<a class="attachment" href="/#{Discourse.store.upload_path}/original/1X/af2c2618032c679333bebf745e75f9088748d737.txt">text.txt</a> (20 Bytes)
|
<a class="attachment" href="/#{Discourse.store.upload_path}/original/1X/af2c2618032c679333bebf745e75f9088748d737.txt">text.txt</a> (20 Bytes)
|
||||||
:smile:
|
:smile:
|
||||||
RAW
|
MD
|
||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:post_with_external_links, from: :post) do
|
Fabricator(:post_with_external_links, from: :post) do
|
||||||
user
|
user
|
||||||
topic
|
topic
|
||||||
raw <<~RAW
|
raw <<~MD
|
||||||
Here's a link to twitter: http://twitter.com
|
Here's a link to twitter: http://twitter.com
|
||||||
And a link to google: http://google.com
|
And a link to google: http://google.com
|
||||||
And a secure link to google: https://google.com
|
And a secure link to google: https://google.com
|
||||||
@@ -123,7 +123,7 @@ Fabricator(:post_with_external_links, from: :post) do
|
|||||||
And a markdown link with a period after it [codinghorror](http://www.codinghorror.com/blog).
|
And a markdown link with a period after it [codinghorror](http://www.codinghorror.com/blog).
|
||||||
And one with a hash http://discourse.org#faq
|
And one with a hash http://discourse.org#faq
|
||||||
And one with a two hash http://discourse.org#a#b
|
And one with a two hash http://discourse.org#a#b
|
||||||
RAW
|
MD
|
||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:private_message_post, from: :post) do
|
Fabricator(:private_message_post, from: :post) do
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ describe 'Coding style' do
|
|||||||
js_files = list_js_files('app/assets/javascripts')
|
js_files = list_js_files('app/assets/javascripts')
|
||||||
offenses = grep_files(js_files, /this\.get\("\w+"\)/)
|
offenses = grep_files(js_files, /this\.get\("\w+"\)/)
|
||||||
|
|
||||||
expect(offenses).to be_empty, <<~MSG
|
expect(offenses).to be_empty, <<~TEXT
|
||||||
Do not use this.get("foo") accessor for single property, instead
|
Do not use this.get("foo") accessor for single property, instead
|
||||||
prefer to use this.foo
|
prefer to use this.foo
|
||||||
|
|
||||||
Offenses:
|
Offenses:
|
||||||
#{offenses.join("\n")}
|
#{offenses.join("\n")}
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ describe 'Coding style' do
|
|||||||
constant_name_regex = /#{Regexp.escape(constant_name)}/
|
constant_name_regex = /#{Regexp.escape(constant_name)}/
|
||||||
offenses = files.reject { |file| is_valid?(file, method_name_regex, constant_name_regex) }
|
offenses = files.reject { |file| is_valid?(file, method_name_regex, constant_name_regex) }
|
||||||
|
|
||||||
expect(offenses).to be_empty, <<~MSG
|
expect(offenses).to be_empty, <<~TEXT
|
||||||
You need to use the constant #{constant_name} when you use
|
You need to use the constant #{constant_name} when you use
|
||||||
#{method_name} in order to help with restoring backups.
|
#{method_name} in order to help with restoring backups.
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ describe 'Coding style' do
|
|||||||
|
|
||||||
Offenses:
|
Offenses:
|
||||||
#{offenses.join("\n")}
|
#{offenses.join("\n")}
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_valid?(file, method_name_regex, constant_name_regex)
|
def is_valid?(file, method_name_regex, constant_name_regex)
|
||||||
|
|||||||
@@ -25,36 +25,36 @@ describe Jobs::OldKeysReminder do
|
|||||||
expect(post.archetype).to eq(Archetype.private_message)
|
expect(post.archetype).to eq(Archetype.private_message)
|
||||||
expect(post.topic.topic_allowed_users.map(&:user_id).sort).to eq([Discourse.system_user.id, admin.id, another_admin.id].sort)
|
expect(post.topic.topic_allowed_users.map(&:user_id).sort).to eq([Discourse.system_user.id, admin.id, another_admin.id].sort)
|
||||||
expect(post.topic.title).to eq('Reminder about old credentials')
|
expect(post.topic.title).to eq('Reminder about old credentials')
|
||||||
expect(post.raw).to eq(<<-MSG.rstrip)
|
expect(post.raw).to eq(<<~TEXT.rstrip)
|
||||||
Hello! This is a routine yearly security reminder from your Discourse instance.
|
Hello! This is a routine yearly security reminder from your Discourse instance.
|
||||||
|
|
||||||
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
|
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
|
||||||
|
|
||||||
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
|
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
|
||||||
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
|
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
|
||||||
api key description - #{api_key.created_at.to_date.to_s(:db)}
|
api key description - #{api_key.created_at.to_date.to_s(:db)}
|
||||||
|
|
||||||
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
|
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
|
||||||
MSG
|
TEXT
|
||||||
|
|
||||||
post.topic.destroy
|
post.topic.destroy
|
||||||
freeze_time 4.years.from_now
|
freeze_time 4.years.from_now
|
||||||
described_class.new.execute({})
|
described_class.new.execute({})
|
||||||
post = Post.last
|
post = Post.last
|
||||||
expect(post.topic.title).to eq('Reminder about old credentials')
|
expect(post.topic.title).to eq('Reminder about old credentials')
|
||||||
expect(post.raw).to eq(<<-MSG.rstrip)
|
expect(post.raw).to eq(<<~TEXT.rstrip)
|
||||||
Hello! This is a routine yearly security reminder from your Discourse instance.
|
Hello! This is a routine yearly security reminder from your Discourse instance.
|
||||||
|
|
||||||
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
|
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
|
||||||
|
|
||||||
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
|
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
|
||||||
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
|
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
|
||||||
twitter_consumer_secret - #{recent_twitter_secret.updated_at.to_date.to_s(:db)}
|
twitter_consumer_secret - #{recent_twitter_secret.updated_at.to_date.to_s(:db)}
|
||||||
api key description - #{api_key.created_at.to_date.to_s(:db)}
|
api key description - #{api_key.created_at.to_date.to_s(:db)}
|
||||||
recent api key description - #{admin.username} - #{recent_api_key.created_at.to_date.to_s(:db)}
|
recent api key description - #{admin.username} - #{recent_api_key.created_at.to_date.to_s(:db)}
|
||||||
|
|
||||||
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
|
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
|
||||||
MSG
|
TEXT
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not send message when send_old_credential_reminder_days is set to 0 or no old keys' do
|
it 'does not send message when send_old_credential_reminder_days is set to 0 or no old keys' do
|
||||||
|
|||||||
@@ -122,12 +122,12 @@ describe Jobs::PullHotlinkedImages do
|
|||||||
stub_request(:get, "http://test.localhost/uploads/short-url/z2QSs1KJWoj51uYhDjb6ifCzxH6.gif")
|
stub_request(:get, "http://test.localhost/uploads/short-url/z2QSs1KJWoj51uYhDjb6ifCzxH6.gif")
|
||||||
.to_return(status: 200, body: "")
|
.to_return(status: 200, body: "")
|
||||||
|
|
||||||
post = Fabricate(:post, raw: <<~RAW)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
<h1></h1>
|
<h1></h1>
|
||||||
<a href="https://somelink.com">
|
<a href="https://somelink.com">
|
||||||
<img alt="somelink" src="#{image_url}" />
|
<img alt="somelink" src="#{image_url}" />
|
||||||
</a>
|
</a>
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
Jobs::PullHotlinkedImages.new.execute(post_id: post.id)
|
Jobs::PullHotlinkedImages.new.execute(post_id: post.id)
|
||||||
@@ -135,12 +135,12 @@ describe Jobs::PullHotlinkedImages do
|
|||||||
|
|
||||||
upload = post.uploads.last
|
upload = post.uploads.last
|
||||||
|
|
||||||
expect(post.reload.raw).to eq(<<~RAW.chomp)
|
expect(post.reload.raw).to eq(<<~MD.chomp)
|
||||||
<h1></h1>
|
<h1></h1>
|
||||||
<a href="https://somelink.com">
|
<a href="https://somelink.com">
|
||||||

|

|
||||||
</a>
|
</a>
|
||||||
RAW
|
MD
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'replaces correct image URL' do
|
it 'replaces correct image URL' do
|
||||||
@@ -371,12 +371,12 @@ describe Jobs::PullHotlinkedImages do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'all combinations' do
|
it 'all combinations' do
|
||||||
post = Fabricate(:post, raw: <<~BODY)
|
post = Fabricate(:post, raw: <<~MD)
|
||||||
<img src='#{image_url}'>
|
<img src='#{image_url}'>
|
||||||
#{url}
|
#{url}
|
||||||
<img src='#{broken_image_url}'>
|
<img src='#{broken_image_url}'>
|
||||||
<a href='#{url}'><img src='#{large_image_url}'></a>
|
<a href='#{url}'><img src='#{large_image_url}'></a>
|
||||||
BODY
|
MD
|
||||||
stub_image_size
|
stub_image_size
|
||||||
|
|
||||||
2.times do
|
2.times do
|
||||||
|
|||||||
@@ -327,13 +327,13 @@ describe ContentSecurityPolicy do
|
|||||||
it 'is extended automatically when themes reference external scripts' do
|
it 'is extended automatically when themes reference external scripts' do
|
||||||
policy # call this first to make sure further actions clear the cache
|
policy # call this first to make sure further actions clear the cache
|
||||||
|
|
||||||
theme.set_field(target: :common, name: "header", value: <<~SCRIPT)
|
theme.set_field(target: :common, name: "header", value: <<~HTML)
|
||||||
<script src='https://example.com/myscript.js'></script>
|
<script src='https://example.com/myscript.js'></script>
|
||||||
<script src='https://example.com/myscript2.js?with=query'></script>
|
<script src='https://example.com/myscript2.js?with=query'></script>
|
||||||
<script src='//example2.com/protocol-less-script.js'></script>
|
<script src='//example2.com/protocol-less-script.js'></script>
|
||||||
<script src='domain-only.com'></script>
|
<script src='domain-only.com'></script>
|
||||||
<script>console.log('inline script')</script>
|
<script>console.log('inline script')</script>
|
||||||
SCRIPT
|
HTML
|
||||||
|
|
||||||
theme.set_field(target: :desktop, name: "header", value: "")
|
theme.set_field(target: :desktop, name: "header", value: "")
|
||||||
theme.save!
|
theme.save!
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ describe Email::AuthenticationResults do
|
|||||||
|
|
||||||
it "parses 'Service Provided, Authentication Done' correctly" do
|
it "parses 'Service Provided, Authentication Done' correctly" do
|
||||||
# https://tools.ietf.org/html/rfc8601#appendix-B.3
|
# https://tools.ietf.org/html/rfc8601#appendix-B.3
|
||||||
results = described_class.new(<<~EOF
|
results = described_class.new(<<~RAW
|
||||||
example.com;
|
example.com;
|
||||||
spf=pass smtp.mailfrom=example.net
|
spf=pass smtp.mailfrom=example.net
|
||||||
EOF
|
RAW
|
||||||
).results
|
).results
|
||||||
expect(results[0][:authserv_id]).to eq "example.com"
|
expect(results[0][:authserv_id]).to eq "example.com"
|
||||||
expect(results[0][:resinfo][0][:method]).to eq "spf"
|
expect(results[0][:resinfo][0][:method]).to eq "spf"
|
||||||
@@ -30,15 +30,15 @@ describe Email::AuthenticationResults do
|
|||||||
|
|
||||||
it "parses 'Service Provided, Several Authentications Done, Single MTA' correctly" do
|
it "parses 'Service Provided, Several Authentications Done, Single MTA' correctly" do
|
||||||
# https://tools.ietf.org/html/rfc8601#appendix-B.4
|
# https://tools.ietf.org/html/rfc8601#appendix-B.4
|
||||||
results = described_class.new([<<~EOF ,
|
results = described_class.new([<<~RAW ,
|
||||||
example.com;
|
example.com;
|
||||||
auth=pass (cram-md5) smtp.auth=sender@example.net;
|
auth=pass (cram-md5) smtp.auth=sender@example.net;
|
||||||
spf=pass smtp.mailfrom=example.net
|
spf=pass smtp.mailfrom=example.net
|
||||||
EOF
|
RAW
|
||||||
<<~EOF ,
|
<<~RAW ,
|
||||||
example.com; iprev=pass
|
example.com; iprev=pass
|
||||||
policy.iprev=192.0.2.200
|
policy.iprev=192.0.2.200
|
||||||
EOF
|
RAW
|
||||||
]).results
|
]).results
|
||||||
expect(results[0][:authserv_id]).to eq "example.com"
|
expect(results[0][:authserv_id]).to eq "example.com"
|
||||||
expect(results[0][:resinfo][0][:method]).to eq "auth"
|
expect(results[0][:resinfo][0][:method]).to eq "auth"
|
||||||
@@ -64,15 +64,15 @@ describe Email::AuthenticationResults do
|
|||||||
|
|
||||||
it "parses 'Service Provided, Several Authentications Done, Different MTAs' correctly" do
|
it "parses 'Service Provided, Several Authentications Done, Different MTAs' correctly" do
|
||||||
# https://tools.ietf.org/html/rfc8601#appendix-B.5
|
# https://tools.ietf.org/html/rfc8601#appendix-B.5
|
||||||
results = described_class.new([<<~EOF ,
|
results = described_class.new([<<~RAW ,
|
||||||
example.com;
|
example.com;
|
||||||
dkim=pass (good signature) header.d=example.com
|
dkim=pass (good signature) header.d=example.com
|
||||||
EOF
|
RAW
|
||||||
<<~EOF ,
|
<<~RAW ,
|
||||||
example.com;
|
example.com;
|
||||||
auth=pass (cram-md5) smtp.auth=sender@example.com;
|
auth=pass (cram-md5) smtp.auth=sender@example.com;
|
||||||
spf=fail smtp.mailfrom=example.com
|
spf=fail smtp.mailfrom=example.com
|
||||||
EOF
|
RAW
|
||||||
]).results
|
]).results
|
||||||
|
|
||||||
expect(results[0][:authserv_id]).to eq "example.com"
|
expect(results[0][:authserv_id]).to eq "example.com"
|
||||||
@@ -99,17 +99,17 @@ describe Email::AuthenticationResults do
|
|||||||
|
|
||||||
it "parses 'Service Provided, Multi-tiered Authentication Done' correctly" do
|
it "parses 'Service Provided, Multi-tiered Authentication Done' correctly" do
|
||||||
# https://tools.ietf.org/html/rfc8601#appendix-B.6
|
# https://tools.ietf.org/html/rfc8601#appendix-B.6
|
||||||
results = described_class.new([<<~EOF ,
|
results = described_class.new([<<~RAW ,
|
||||||
example.com;
|
example.com;
|
||||||
dkim=pass reason="good signature"
|
dkim=pass reason="good signature"
|
||||||
header.i=@mail-router.example.net;
|
header.i=@mail-router.example.net;
|
||||||
dkim=fail reason="bad signature"
|
dkim=fail reason="bad signature"
|
||||||
header.i=@newyork.example.com
|
header.i=@newyork.example.com
|
||||||
EOF
|
RAW
|
||||||
<<~EOF ,
|
<<~RAW ,
|
||||||
example.net;
|
example.net;
|
||||||
dkim=pass (good signature) header.i=@newyork.example.com
|
dkim=pass (good signature) header.i=@newyork.example.com
|
||||||
EOF
|
RAW
|
||||||
]).results
|
]).results
|
||||||
|
|
||||||
expect(results[0][:authserv_id]).to eq "example.com"
|
expect(results[0][:authserv_id]).to eq "example.com"
|
||||||
@@ -136,12 +136,12 @@ describe Email::AuthenticationResults do
|
|||||||
|
|
||||||
it "parses 'Comment-Heavy Example' correctly" do
|
it "parses 'Comment-Heavy Example' correctly" do
|
||||||
# https://tools.ietf.org/html/rfc8601#appendix-B.7
|
# https://tools.ietf.org/html/rfc8601#appendix-B.7
|
||||||
results = described_class.new(<<~EOF
|
results = described_class.new(<<~RAW
|
||||||
foo.example.net (foobar) 1 (baz);
|
foo.example.net (foobar) 1 (baz);
|
||||||
dkim (Because I like it) / 1 (One yay) = (wait for it) fail
|
dkim (Because I like it) / 1 (One yay) = (wait for it) fail
|
||||||
policy (A dot can go here) . (like that) expired
|
policy (A dot can go here) . (like that) expired
|
||||||
(this surprised me) = (as I wasn't expecting it) 1362471462
|
(this surprised me) = (as I wasn't expecting it) 1362471462
|
||||||
EOF
|
RAW
|
||||||
).results
|
).results
|
||||||
|
|
||||||
expect(results[0][:authserv_id]).to eq "foo.example.net"
|
expect(results[0][:authserv_id]).to eq "foo.example.net"
|
||||||
@@ -163,12 +163,12 @@ describe Email::AuthenticationResults do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "parses header with multiple props correctly" do
|
it "parses header with multiple props correctly" do
|
||||||
results = described_class.new(<<~EOF
|
results = described_class.new(<<~RAW
|
||||||
mx.google.com;
|
mx.google.com;
|
||||||
dkim=pass header.i=@email.example.com header.s=20111006 header.b=URn9MW+F;
|
dkim=pass header.i=@email.example.com header.s=20111006 header.b=URn9MW+F;
|
||||||
spf=pass (google.com: domain of foo@b.email.example.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=foo@b.email.example.com;
|
spf=pass (google.com: domain of foo@b.email.example.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=foo@b.email.example.com;
|
||||||
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=email.example.com
|
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=email.example.com
|
||||||
EOF
|
RAW
|
||||||
).results
|
).results
|
||||||
|
|
||||||
expect(results[0][:authserv_id]).to eq "mx.google.com"
|
expect(results[0][:authserv_id]).to eq "mx.google.com"
|
||||||
|
|||||||
@@ -808,7 +808,7 @@ describe Email::Receiver do
|
|||||||
post = Post.last
|
post = Post.last
|
||||||
|
|
||||||
expect(post.user.email).to eq("ba@bar.com")
|
expect(post.user.email).to eq("ba@bar.com")
|
||||||
expect(post.raw).to eq(<<~EOF.chomp
|
expect(post.raw).to eq(<<~RAW.chomp)
|
||||||
@team, can you have a look at this email below?
|
@team, can you have a look at this email below?
|
||||||
|
|
||||||
[quote]
|
[quote]
|
||||||
@@ -823,8 +823,7 @@ describe Email::Receiver do
|
|||||||
|
|
||||||
XoXo
|
XoXo
|
||||||
[/quote]
|
[/quote]
|
||||||
EOF
|
RAW
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -976,7 +975,7 @@ describe Email::Receiver do
|
|||||||
let!(:post) { Fabricate(:post, topic: topic) }
|
let!(:post) { Fabricate(:post, topic: topic) }
|
||||||
|
|
||||||
def process_mail_with_message_id(message_id)
|
def process_mail_with_message_id(message_id)
|
||||||
mail_string = <<~REPLY
|
mail_string = <<~EMAIL
|
||||||
Return-Path: <two@foo.com>
|
Return-Path: <two@foo.com>
|
||||||
From: Two <two@foo.com>
|
From: Two <two@foo.com>
|
||||||
To: one@foo.com
|
To: one@foo.com
|
||||||
@@ -989,7 +988,7 @@ describe Email::Receiver do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
This is email reply testing with Message-ID formats.
|
This is email reply testing with Message-ID formats.
|
||||||
REPLY
|
EMAIL
|
||||||
Email::Receiver.new(mail_string).process!
|
Email::Receiver.new(mail_string).process!
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1867,7 +1866,7 @@ describe Email::Receiver do
|
|||||||
context "#select_body" do
|
context "#select_body" do
|
||||||
|
|
||||||
let(:email) {
|
let(:email) {
|
||||||
<<~EOF
|
<<~EMAIL
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
||||||
Subject: An email with whitespaces
|
Subject: An email with whitespaces
|
||||||
@@ -1916,11 +1915,11 @@ describe Email::Receiver do
|
|||||||
This is going to be stripped too.
|
This is going to be stripped too.
|
||||||
|
|
||||||
Bye!
|
Bye!
|
||||||
EOF
|
EMAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
let(:stripped_text) {
|
let(:stripped_text) {
|
||||||
<<~EOF
|
<<~MD
|
||||||
This is a line that will be stripped
|
This is a line that will be stripped
|
||||||
This is another line that will be stripped
|
This is another line that will be stripped
|
||||||
|
|
||||||
@@ -1962,7 +1961,7 @@ describe Email::Receiver do
|
|||||||
This is going to be stripped too.
|
This is going to be stripped too.
|
||||||
|
|
||||||
Bye!
|
Bye!
|
||||||
EOF
|
MD
|
||||||
}
|
}
|
||||||
|
|
||||||
it "strips lines if strip_incoming_email_lines is enabled" do
|
it "strips lines if strip_incoming_email_lines is enabled" do
|
||||||
@@ -1976,7 +1975,7 @@ describe Email::Receiver do
|
|||||||
it "works with empty mail body" do
|
it "works with empty mail body" do
|
||||||
SiteSetting.strip_incoming_email_lines = true
|
SiteSetting.strip_incoming_email_lines = true
|
||||||
|
|
||||||
email = <<~EOF
|
email = <<~EMAIL
|
||||||
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
||||||
Subject: An email with whitespaces
|
Subject: An email with whitespaces
|
||||||
From: Foo <foo@discourse.org>
|
From: Foo <foo@discourse.org>
|
||||||
@@ -1986,7 +1985,7 @@ describe Email::Receiver do
|
|||||||
--
|
--
|
||||||
my signature
|
my signature
|
||||||
|
|
||||||
EOF
|
EMAIL
|
||||||
|
|
||||||
receiver = Email::Receiver.new(email)
|
receiver = Email::Receiver.new(email)
|
||||||
text, _elided, _format = receiver.select_body
|
text, _elided, _format = receiver.select_body
|
||||||
@@ -2004,7 +2003,7 @@ describe Email::Receiver do
|
|||||||
message_id: digest_message_id
|
message_id: digest_message_id
|
||||||
)}
|
)}
|
||||||
let(:email) {
|
let(:email) {
|
||||||
<<~EOF
|
<<~EMAIL
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
Date: Tue, 01 Jan 2019 00:00:00 +0300
|
||||||
From: someone <#{user.email}>
|
From: someone <#{user.email}>
|
||||||
@@ -2017,7 +2016,7 @@ describe Email::Receiver do
|
|||||||
|
|
||||||
hello there! I like the digest!
|
hello there! I like the digest!
|
||||||
|
|
||||||
EOF
|
EMAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@@ -2034,7 +2033,7 @@ describe Email::Receiver do
|
|||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:group) { Fabricate(:group, users: [user]) }
|
let(:group) { Fabricate(:group, users: [user]) }
|
||||||
|
|
||||||
let (:email_1) { <<~EOF
|
let (:email_1) { <<~EMAIL
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Date: Wed, 01 Jan 2019 12:00:00 +0200
|
Date: Wed, 01 Jan 2019 12:00:00 +0200
|
||||||
Message-ID: <7aN1uwcokt2xkfG3iYrpKmiuVhy4w9b5@mail.gmail.com>
|
Message-ID: <7aN1uwcokt2xkfG3iYrpKmiuVhy4w9b5@mail.gmail.com>
|
||||||
@@ -2052,7 +2051,7 @@ describe Email::Receiver do
|
|||||||
Vivamus semper lacinia scelerisque. Cras urna magna, porttitor nec
|
Vivamus semper lacinia scelerisque. Cras urna magna, porttitor nec
|
||||||
libero quis, congue viverra sapien. Nulla sodales ac tellus a
|
libero quis, congue viverra sapien. Nulla sodales ac tellus a
|
||||||
suscipit.
|
suscipit.
|
||||||
EOF
|
EMAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
let (:post_2) {
|
let (:post_2) {
|
||||||
@@ -2064,7 +2063,7 @@ describe Email::Receiver do
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (:email_3) { <<~EOF
|
let (:email_3) { <<~EMAIL
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Date: Wed, 01 Jan 2019 12:00:00 +0200
|
Date: Wed, 01 Jan 2019 12:00:00 +0200
|
||||||
References: <7aN1uwcokt2xkfG3iYrpKmiuVhy4w9b5@mail.gmail.com> <topic/#{post_2.topic_id}/#{post_2.id}@test.localhost>
|
References: <7aN1uwcokt2xkfG3iYrpKmiuVhy4w9b5@mail.gmail.com> <topic/#{post_2.topic_id}/#{post_2.id}@test.localhost>
|
||||||
@@ -2087,7 +2086,7 @@ describe Email::Receiver do
|
|||||||
felis. Sed pellentesque, massa auctor venenatis gravida, risus lorem
|
felis. Sed pellentesque, massa auctor venenatis gravida, risus lorem
|
||||||
iaculis mi, at hendrerit nisi turpis sit amet metus. Nulla egestas
|
iaculis mi, at hendrerit nisi turpis sit amet metus. Nulla egestas
|
||||||
ante eget nisi luctus consectetur.
|
ante eget nisi luctus consectetur.
|
||||||
EOF
|
EMAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive(email_string)
|
def receive(email_string)
|
||||||
|
|||||||
@@ -16,28 +16,28 @@ describe EmailCook do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't add linebreaks to long lines" do
|
it "doesn't add linebreaks to long lines" do
|
||||||
long = plaintext(<<~LONG_EMAIL)
|
long = plaintext(<<~EMAIL)
|
||||||
Hello,
|
Hello,
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
||||||
risus. Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
risus. Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
||||||
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = (+<<~LONG_COOKED).strip!
|
long_cooked = (+<<~HTML).strip!
|
||||||
Hello,
|
Hello,
|
||||||
<br>
|
<br>
|
||||||
<br>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
<br>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
||||||
risus. Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
risus. Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
||||||
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
||||||
<br>
|
<br>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "replaces a blank line with 2 linebreaks" do
|
it "replaces a blank line with 2 linebreaks" do
|
||||||
long = plaintext(<<~LONG_EMAIL)
|
long = plaintext(<<~EMAIL)
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
||||||
risus.
|
risus.
|
||||||
Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
||||||
@@ -45,9 +45,9 @@ describe EmailCook do
|
|||||||
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
Vestibulum feugiat mi vitae turpis tempor dignissim.
|
||||||
|
|
||||||
Stet clita kasd gubergren.
|
Stet clita kasd gubergren.
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = (+<<~LONG_COOKED).strip!
|
long_cooked = (+<<~HTML).strip!
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc convallis volutpat
|
||||||
risus.
|
risus.
|
||||||
<br>Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
<br>Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
|
||||||
@@ -56,13 +56,13 @@ describe EmailCook do
|
|||||||
<br>
|
<br>
|
||||||
<br>Stet clita kasd gubergren.
|
<br>Stet clita kasd gubergren.
|
||||||
<br>
|
<br>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "escapes HTML" do
|
it "escapes HTML" do
|
||||||
long = plaintext(<<~LONG_EMAIL)
|
long = plaintext(<<~EMAIL)
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
<form name="f1" method="post" action="test.html" onsubmit="javascript:showAlert()">
|
<form name="f1" method="post" action="test.html" onsubmit="javascript:showAlert()">
|
||||||
@@ -70,9 +70,9 @@ describe EmailCook do
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
Nunc convallis volutpat risus.
|
Nunc convallis volutpat risus.
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = (+<<~LONG_COOKED).strip!
|
long_cooked = (+<<~HTML).strip!
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
<br>
|
<br>
|
||||||
<br><form name="f1" method="post" action="test.html" onsubmit="javascript:showAlert()">
|
<br><form name="f1" method="post" action="test.html" onsubmit="javascript:showAlert()">
|
||||||
@@ -81,29 +81,29 @@ describe EmailCook do
|
|||||||
<br>
|
<br>
|
||||||
<br>Nunc convallis volutpat risus.
|
<br>Nunc convallis volutpat risus.
|
||||||
<br>
|
<br>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "replaces indentation of more than 2 spaces with corresponding amount of non-breaking spaces" do
|
it "replaces indentation of more than 2 spaces with corresponding amount of non-breaking spaces" do
|
||||||
nbsp = "\u00A0"
|
nbsp = "\u00A0"
|
||||||
long = plaintext(<<~LONG_EMAIL)
|
long = plaintext(<<~EMAIL)
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
this is intended by 4 spaces
|
this is intended by 4 spaces
|
||||||
this is intended by 1 space
|
this is intended by 1 space
|
||||||
no indentation, but lots of spaces
|
no indentation, but lots of spaces
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = (+<<~LONG_COOKED).strip!
|
long_cooked = (+<<~HTML).strip!
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
<br>
|
<br>
|
||||||
<br>#{nbsp}#{nbsp}#{nbsp}#{nbsp}this is intended by 4 spaces
|
<br>#{nbsp}#{nbsp}#{nbsp}#{nbsp}this is intended by 4 spaces
|
||||||
<br> this is intended by 1 space
|
<br> this is intended by 1 space
|
||||||
<br>no indentation, but lots of spaces
|
<br>no indentation, but lots of spaces
|
||||||
<br>
|
<br>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
@@ -129,7 +129,7 @@ describe EmailCook do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "it works and does not interpret Markdown in plaintext and elided" do
|
it "it works and does not interpret Markdown in plaintext and elided" do
|
||||||
long = <<~LONG_EMAIL
|
long = <<~EMAIL
|
||||||
[plaintext]
|
[plaintext]
|
||||||
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
|
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
|
||||||
[/plaintext]
|
[/plaintext]
|
||||||
@@ -139,9 +139,9 @@ describe EmailCook do
|
|||||||
[elided]
|
[elided]
|
||||||
At vero eos *et accusam* et justo duo dolores et ea rebum.
|
At vero eos *et accusam* et justo duo dolores et ea rebum.
|
||||||
[/elided]
|
[/elided]
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = <<~LONG_COOKED
|
long_cooked = <<~HTML
|
||||||
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
|
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
|
||||||
<br><img src='some_image.png' width='100' height='100'>
|
<br><img src='some_image.png' width='100' height='100'>
|
||||||
<br><br>
|
<br><br>
|
||||||
@@ -152,22 +152,22 @@ describe EmailCook do
|
|||||||
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
|
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "works without attachments" do
|
it "works without attachments" do
|
||||||
long = <<~LONG_EMAIL
|
long = <<~EMAIL
|
||||||
[plaintext]
|
[plaintext]
|
||||||
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
|
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
|
||||||
[/plaintext]
|
[/plaintext]
|
||||||
[elided]
|
[elided]
|
||||||
At vero eos *et accusam* et justo duo dolores et ea rebum.
|
At vero eos *et accusam* et justo duo dolores et ea rebum.
|
||||||
[/elided]
|
[/elided]
|
||||||
LONG_EMAIL
|
EMAIL
|
||||||
|
|
||||||
long_cooked = <<~LONG_COOKED
|
long_cooked = <<~HTML
|
||||||
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
|
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ describe EmailCook do
|
|||||||
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
|
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
LONG_COOKED
|
HTML
|
||||||
|
|
||||||
expect(cook(long)).to eq(long_cooked)
|
expect(cook(long)).to eq(long_cooked)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ describe PrettyText do
|
|||||||
expect(PrettyText.cook("[quote]\ntest")).not_to include('aside')
|
expect(PrettyText.cook("[quote]\ntest")).not_to include('aside')
|
||||||
expect(PrettyText.cook("[quote]\ntest\n[/quote]z")).not_to include('aside')
|
expect(PrettyText.cook("[quote]\ntest\n[/quote]z")).not_to include('aside')
|
||||||
|
|
||||||
nested = <<~QUOTE
|
nested = <<~MD
|
||||||
[quote]
|
[quote]
|
||||||
a
|
a
|
||||||
[quote]
|
[quote]
|
||||||
@@ -361,7 +361,7 @@ describe PrettyText do
|
|||||||
[/quote]
|
[/quote]
|
||||||
c
|
c
|
||||||
[/quote]
|
[/quote]
|
||||||
QUOTE
|
MD
|
||||||
|
|
||||||
cooked = PrettyText.cook(nested)
|
cooked = PrettyText.cook(nested)
|
||||||
expect(cooked.scan('aside').length).to eq(4)
|
expect(cooked.scan('aside').length).to eq(4)
|
||||||
@@ -799,9 +799,9 @@ describe PrettyText do
|
|||||||
|
|
||||||
context "emojis" do
|
context "emojis" do
|
||||||
it "should remove broken emoji" do
|
it "should remove broken emoji" do
|
||||||
html = <<~EOS
|
html = <<~HTML
|
||||||
<img src=\"//localhost:3000/images/emoji/twitter/bike.png?v=#{Emoji::EMOJI_VERSION}\" title=\":bike:\" class=\"emoji\" alt=\":bike:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"//localhost:3000/images/emoji/twitter/cat.png?v=#{Emoji::EMOJI_VERSION}\" title=\":cat:\" class=\"emoji\" alt=\":cat:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"//localhost:3000/images/emoji/twitter/discourse.png?v=#{Emoji::EMOJI_VERSION}\" title=\":discourse:\" class=\"emoji\" alt=\":discourse:\" loading=\"lazy\" width=\"20\" height=\"20\">
|
<img src=\"//localhost:3000/images/emoji/twitter/bike.png?v=#{Emoji::EMOJI_VERSION}\" title=\":bike:\" class=\"emoji\" alt=\":bike:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"//localhost:3000/images/emoji/twitter/cat.png?v=#{Emoji::EMOJI_VERSION}\" title=\":cat:\" class=\"emoji\" alt=\":cat:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"//localhost:3000/images/emoji/twitter/discourse.png?v=#{Emoji::EMOJI_VERSION}\" title=\":discourse:\" class=\"emoji\" alt=\":discourse:\" loading=\"lazy\" width=\"20\" height=\"20\">
|
||||||
EOS
|
HTML
|
||||||
expect(PrettyText.excerpt(html, 7)).to eq(":bike: …")
|
expect(PrettyText.excerpt(html, 7)).to eq(":bike: …")
|
||||||
expect(PrettyText.excerpt(html, 8)).to eq(":bike: …")
|
expect(PrettyText.excerpt(html, 8)).to eq(":bike: …")
|
||||||
expect(PrettyText.excerpt(html, 9)).to eq(":bike: …")
|
expect(PrettyText.excerpt(html, 9)).to eq(":bike: …")
|
||||||
@@ -914,7 +914,7 @@ describe PrettyText do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should not extract links inside oneboxes" do
|
it "should not extract links inside oneboxes" do
|
||||||
onebox = <<~EOF
|
onebox = <<~HTML
|
||||||
<aside class="onebox twitterstatus" data-onebox-src="https://twitter.com/EDBPostgres/status/1402528437441634306">
|
<aside class="onebox twitterstatus" data-onebox-src="https://twitter.com/EDBPostgres/status/1402528437441634306">
|
||||||
<header class="source">
|
<header class="source">
|
||||||
<a href="https://twitter.com/EDBPostgres/status/1402528437441634306" target="_blank" rel="noopener">twitter.com</a>
|
<a href="https://twitter.com/EDBPostgres/status/1402528437441634306" target="_blank" rel="noopener">twitter.com</a>
|
||||||
@@ -924,7 +924,7 @@ describe PrettyText do
|
|||||||
<div class="tweet">Example URL: <a target="_blank" href="https://example.com" rel="noopener">example.com</a></div>
|
<div class="tweet">Example URL: <a target="_blank" href="https://example.com" rel="noopener">example.com</a></div>
|
||||||
</article>
|
</article>
|
||||||
</aside>
|
</aside>
|
||||||
EOF
|
HTML
|
||||||
|
|
||||||
expect(PrettyText.extract_links(onebox).map(&:url)).to contain_exactly("https://twitter.com/EDBPostgres/status/1402528437441634306")
|
expect(PrettyText.extract_links(onebox).map(&:url)).to contain_exactly("https://twitter.com/EDBPostgres/status/1402528437441634306")
|
||||||
end
|
end
|
||||||
@@ -938,12 +938,13 @@ describe PrettyText do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "handles custom bbcode excerpt" do
|
it "handles custom bbcode excerpt" do
|
||||||
raw = <<~RAW
|
raw = <<~MD
|
||||||
[excerpt]
|
[excerpt]
|
||||||
hello [site](https://site.com)
|
hello [site](https://site.com)
|
||||||
[/excerpt]
|
[/excerpt]
|
||||||
more stuff
|
more stuff
|
||||||
RAW
|
MD
|
||||||
|
|
||||||
post = Fabricate(:post, raw: raw)
|
post = Fabricate(:post, raw: raw)
|
||||||
expect(post.excerpt).to eq("hello <a href=\"https://site.com\" rel=\"noopener nofollow ugc\">site</a>")
|
expect(post.excerpt).to eq("hello <a href=\"https://site.com\" rel=\"noopener nofollow ugc\">site</a>")
|
||||||
end
|
end
|
||||||
@@ -1929,17 +1930,17 @@ HTML
|
|||||||
|
|
||||||
it "can properly allowlist iframes" do
|
it "can properly allowlist iframes" do
|
||||||
SiteSetting.allowed_iframes = "https://bob.com/a|http://silly.com?EMBED="
|
SiteSetting.allowed_iframes = "https://bob.com/a|http://silly.com?EMBED="
|
||||||
raw = <<~IFRAMES
|
raw = <<~HTML
|
||||||
<iframe src='https://www.google.com/maps/Embed?testing'></iframe>
|
<iframe src='https://www.google.com/maps/Embed?testing'></iframe>
|
||||||
<iframe src='https://bob.com/a?testing'></iframe>
|
<iframe src='https://bob.com/a?testing'></iframe>
|
||||||
<iframe src='HTTP://SILLY.COM?EMBED=111'></iframe>
|
<iframe src='HTTP://SILLY.COM?EMBED=111'></iframe>
|
||||||
IFRAMES
|
HTML
|
||||||
|
|
||||||
# we require explicit HTTPS here
|
# we require explicit HTTPS here
|
||||||
html = <<~IFRAMES
|
html = <<~HTML
|
||||||
<iframe src="https://bob.com/a?testing"></iframe>
|
<iframe src="https://bob.com/a?testing"></iframe>
|
||||||
<iframe src="HTTP://SILLY.COM?EMBED=111"></iframe>
|
<iframe src="HTTP://SILLY.COM?EMBED=111"></iframe>
|
||||||
IFRAMES
|
HTML
|
||||||
|
|
||||||
cooked = PrettyText.cook(raw).strip
|
cooked = PrettyText.cook(raw).strip
|
||||||
|
|
||||||
|
|||||||
@@ -551,9 +551,9 @@ describe Search do
|
|||||||
|
|
||||||
result = Search.execute('search term')
|
result = Search.execute('search term')
|
||||||
|
|
||||||
expect(result.posts.first.topic_title_headline).to eq(<<~TITLE.chomp)
|
expect(result.posts.first.topic_title_headline).to eq(<<~HTML.chomp)
|
||||||
Very very very very very very very long topic title with our <span class=\"#{Search::HIGHLIGHT_CSS_CLASS}\">search</span> <span class=\"#{Search::HIGHLIGHT_CSS_CLASS}\">term</span> in the middle of the title
|
Very very very very very very very long topic title with our <span class=\"#{Search::HIGHLIGHT_CSS_CLASS}\">search</span> <span class=\"#{Search::HIGHLIGHT_CSS_CLASS}\">term</span> in the middle of the title
|
||||||
TITLE
|
HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
it "limits the search headline to #{Search::GroupedSearchResults::BLURB_LENGTH} characters" do
|
it "limits the search headline to #{Search::GroupedSearchResults::BLURB_LENGTH} characters" do
|
||||||
|
|||||||
@@ -76,25 +76,25 @@ describe Discourse::VERSION do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "with a regular compatible list" do
|
context "with a regular compatible list" do
|
||||||
let(:version_list) { <<~VERSION_LIST
|
let(:version_list) { <<~YML
|
||||||
2.5.0.beta6: twofivebetasix
|
2.5.0.beta6: twofivebetasix
|
||||||
2.5.0.beta4: twofivebetafour
|
2.5.0.beta4: twofivebetafour
|
||||||
2.5.0.beta2: twofivebetatwo
|
2.5.0.beta2: twofivebetatwo
|
||||||
2.4.4.beta6: twofourfourbetasix
|
2.4.4.beta6: twofourfourbetasix
|
||||||
2.4.2.beta1: twofourtwobetaone
|
2.4.2.beta1: twofourtwobetaone
|
||||||
VERSION_LIST
|
YML
|
||||||
}
|
}
|
||||||
include_examples "test compatible resource"
|
include_examples "test compatible resource"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "handle a compatible resource out of order" do
|
context "handle a compatible resource out of order" do
|
||||||
let(:version_list) { <<~VERSION_LIST
|
let(:version_list) { <<~YML
|
||||||
2.4.2.beta1: twofourtwobetaone
|
2.4.2.beta1: twofourtwobetaone
|
||||||
2.5.0.beta4: twofivebetafour
|
2.5.0.beta4: twofivebetafour
|
||||||
2.5.0.beta6: twofivebetasix
|
2.5.0.beta6: twofivebetasix
|
||||||
2.5.0.beta2: twofivebetatwo
|
2.5.0.beta2: twofivebetatwo
|
||||||
2.4.4.beta6: twofourfourbetasix
|
2.4.4.beta6: twofourfourbetasix
|
||||||
VERSION_LIST
|
YML
|
||||||
}
|
}
|
||||||
include_examples "test compatible resource"
|
include_examples "test compatible resource"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ describe GroupSmtpMailer do
|
|||||||
end
|
end
|
||||||
|
|
||||||
let(:email) do
|
let(:email) do
|
||||||
<<~EOF
|
<<~EMAIL
|
||||||
Delivered-To: bugs@gmail.com
|
Delivered-To: bugs@gmail.com
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
From: John Doe <john@doe.com>
|
From: John Doe <john@doe.com>
|
||||||
@@ -41,7 +41,7 @@ describe GroupSmtpMailer do
|
|||||||
Hello,
|
Hello,
|
||||||
|
|
||||||
How are you doing?
|
How are you doing?
|
||||||
EOF
|
EMAIL
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:receiver) do
|
let(:receiver) do
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ describe ThemeField do
|
|||||||
<script>var b = 10</script>
|
<script>var b = 10</script>
|
||||||
HTML
|
HTML
|
||||||
|
|
||||||
extracted = <<~JavaScript
|
extracted = <<~JS
|
||||||
var a = 10
|
var a = 10
|
||||||
var b = 10
|
var b = 10
|
||||||
JavaScript
|
JS
|
||||||
|
|
||||||
theme_field = ThemeField.create!(theme_id: 1, target_id: 0, name: "header", value: html)
|
theme_field = ThemeField.create!(theme_id: 1, target_id: 0, name: "header", value: html)
|
||||||
theme_field.ensure_baked!
|
theme_field.ensure_baked!
|
||||||
|
|||||||
@@ -326,10 +326,10 @@ HTML
|
|||||||
expect(scss).to include("font-size:30px")
|
expect(scss).to include("font-size:30px")
|
||||||
|
|
||||||
# Escapes correctly. If not, compiling this would throw an exception
|
# Escapes correctly. If not, compiling this would throw an exception
|
||||||
setting.value = <<~MULTILINE
|
setting.value = <<~CSS
|
||||||
\#{$fakeinterpolatedvariable}
|
\#{$fakeinterpolatedvariable}
|
||||||
andanothervalue 'withquotes'; margin: 0;
|
andanothervalue 'withquotes'; margin: 0;
|
||||||
MULTILINE
|
CSS
|
||||||
|
|
||||||
theme.set_field(target: :common, name: :scss, value: 'body {font-size: quote($font-size)}')
|
theme.set_field(target: :common, name: :scss, value: 'body {font-size: quote($font-size)}')
|
||||||
theme.save!
|
theme.save!
|
||||||
|
|||||||
@@ -390,10 +390,10 @@ describe TopicEmbed do
|
|||||||
it "handles malformed links" do
|
it "handles malformed links" do
|
||||||
url = "https://somesource.com"
|
url = "https://somesource.com"
|
||||||
|
|
||||||
contents = <<~CONTENT
|
contents = <<~HTML
|
||||||
hello world new post <a href="mailto:somemail@somewhere.org>">hello</a>
|
hello world new post <a href="mailto:somemail@somewhere.org>">hello</a>
|
||||||
some image <img src="https:/><invalidimagesrc/">
|
some image <img src="https:/><invalidimagesrc/">
|
||||||
CONTENT
|
HTML
|
||||||
|
|
||||||
raw = TopicEmbed.absolutize_urls(url, contents)
|
raw = TopicEmbed.absolutize_urls(url, contents)
|
||||||
expect(raw).to eq(contents)
|
expect(raw).to eq(contents)
|
||||||
|
|||||||
@@ -454,14 +454,14 @@ RSpec.describe Admin::BackupsController do
|
|||||||
BackupRestore::S3BackupStore.any_instance.stubs(:temporary_upload_path).returns(
|
BackupRestore::S3BackupStore.any_instance.stubs(:temporary_upload_path).returns(
|
||||||
"temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz"
|
"temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz"
|
||||||
)
|
)
|
||||||
create_multipart_result = <<~BODY
|
create_multipart_result = <<~XML
|
||||||
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||||
<InitiateMultipartUploadResult>
|
<InitiateMultipartUploadResult>
|
||||||
<Bucket>s3-backup-bucket</Bucket>
|
<Bucket>s3-backup-bucket</Bucket>
|
||||||
<Key>temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz</Key>
|
<Key>temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz</Key>
|
||||||
<UploadId>#{mock_multipart_upload_id}</UploadId>
|
<UploadId>#{mock_multipart_upload_id}</UploadId>
|
||||||
</InitiateMultipartUploadResult>
|
</InitiateMultipartUploadResult>
|
||||||
BODY
|
XML
|
||||||
stub_request(:post, "https://s3-backup-bucket.s3.us-west-1.amazonaws.com/temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz?uploads").
|
stub_request(:post, "https://s3-backup-bucket.s3.us-west-1.amazonaws.com/temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz?uploads").
|
||||||
to_return(status: 200, body: create_multipart_result)
|
to_return(status: 200, body: create_multipart_result)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe 'groups' do
|
|||||||
in: :query,
|
in: :query,
|
||||||
type: :string,
|
type: :string,
|
||||||
example: 'api @blake #support tags:api after:2021-06-04 in:unseen in:open order:latest_topic',
|
example: 'api @blake #support tags:api after:2021-06-04 in:unseen in:open order:latest_topic',
|
||||||
description: <<~HEREDOC
|
description: <<~MD
|
||||||
The query string needs to be url encoded and is made up of the following options:
|
The query string needs to be url encoded and is made up of the following options:
|
||||||
- Search term. This is just a string. Usually it would be the first item in the query.
|
- Search term. This is just a string. Usually it would be the first item in the query.
|
||||||
- `@<username>`: Use the `@` followed by the username to specify posts by this user.
|
- `@<username>`: Use the `@` followed by the username to specify posts by this user.
|
||||||
@@ -44,7 +44,7 @@ describe 'groups' do
|
|||||||
curl -i -sS -X GET -G "http://localhost:4200/search.json" \\
|
curl -i -sS -X GET -G "http://localhost:4200/search.json" \\
|
||||||
--data-urlencode 'q=wordpress @scossar #fun after:2020-01-01'
|
--data-urlencode 'q=wordpress @scossar #fun after:2020-01-01'
|
||||||
```
|
```
|
||||||
HEREDOC
|
MD
|
||||||
)
|
)
|
||||||
parameter name: :page, in: :query, type: :integer, example: 1
|
parameter name: :page, in: :query, type: :integer, example: 1
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'generatePresignedPut'
|
operationId 'generatePresignedPut'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
Direct external uploads bypass the usual method of creating uploads
|
Direct external uploads bypass the usual method of creating uploads
|
||||||
via the POST /uploads route, and upload directly to an external provider,
|
via the POST /uploads route, and upload directly to an external provider,
|
||||||
which by default is S3. This route begins the process, and will return
|
which by default is S3. This route begins the process, and will return
|
||||||
@@ -66,7 +66,7 @@ describe 'uploads' do
|
|||||||
destination in the external storage service.
|
destination in the external storage service.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_generate_presigned_put_request')
|
expected_request_schema = load_spec_schema('upload_generate_presigned_put_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
@@ -108,7 +108,7 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'completeExternalUpload'
|
operationId 'completeExternalUpload'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
Completes an external upload initialized with /get-presigned-put. The
|
Completes an external upload initialized with /get-presigned-put. The
|
||||||
file will be moved from its temporary location in external storage to
|
file will be moved from its temporary location in external storage to
|
||||||
a final destination in the S3 bucket. An Upload record will also be
|
a final destination in the S3 bucket. An Upload record will also be
|
||||||
@@ -119,7 +119,7 @@ describe 'uploads' do
|
|||||||
file was uploaded. The file size will be compared for the same reason.
|
file was uploaded. The file size will be compared for the same reason.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_complete_external_upload_request')
|
expected_request_schema = load_spec_schema('upload_complete_external_upload_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
@@ -154,12 +154,12 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'createMultipartUpload'
|
operationId 'createMultipartUpload'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
Creates a multipart upload in the external storage provider, storing
|
Creates a multipart upload in the external storage provider, storing
|
||||||
a temporary reference to the external upload similar to /get-presigned-put.
|
a temporary reference to the external upload similar to /get-presigned-put.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_create_multipart_request')
|
expected_request_schema = load_spec_schema('upload_create_multipart_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
@@ -200,7 +200,7 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'batchPresignMultipartParts'
|
operationId 'batchPresignMultipartParts'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
Multipart uploads are uploaded in chunks or parts to individual presigned
|
Multipart uploads are uploaded in chunks or parts to individual presigned
|
||||||
URLs, similar to the one generated by /generate-presigned-put. The part
|
URLs, similar to the one generated by /generate-presigned-put. The part
|
||||||
numbers provided must be between 1 and 10000. The total number of parts
|
numbers provided must be between 1 and 10000. The total number of parts
|
||||||
@@ -215,7 +215,7 @@ describe 'uploads' do
|
|||||||
because this is needed to complete the multipart upload.
|
because this is needed to complete the multipart upload.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_batch_presign_multipart_parts_request')
|
expected_request_schema = load_spec_schema('upload_batch_presign_multipart_parts_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
@@ -255,13 +255,13 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'abortMultipart'
|
operationId 'abortMultipart'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
This endpoint aborts the multipart upload initiated with /create-multipart.
|
This endpoint aborts the multipart upload initiated with /create-multipart.
|
||||||
This should be used when cancelling the upload. It does not matter if parts
|
This should be used when cancelling the upload. It does not matter if parts
|
||||||
were already uploaded into the external storage provider.
|
were already uploaded into the external storage provider.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_abort_multipart_request')
|
expected_request_schema = load_spec_schema('upload_abort_multipart_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
@@ -299,7 +299,7 @@ describe 'uploads' do
|
|||||||
tags 'Uploads'
|
tags 'Uploads'
|
||||||
operationId 'completeMultipart'
|
operationId 'completeMultipart'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
description <<~HEREDOC
|
description <<~TEXT
|
||||||
Completes the multipart upload in the external store, and copies the
|
Completes the multipart upload in the external store, and copies the
|
||||||
file from its temporary location to its final location in the store.
|
file from its temporary location to its final location in the store.
|
||||||
All of the parts must have been uploaded to the external storage provider.
|
All of the parts must have been uploaded to the external storage provider.
|
||||||
@@ -307,7 +307,7 @@ describe 'uploads' do
|
|||||||
to its final location.
|
to its final location.
|
||||||
|
|
||||||
#{direct_uploads_disclaimer}
|
#{direct_uploads_disclaimer}
|
||||||
HEREDOC
|
TEXT
|
||||||
|
|
||||||
expected_request_schema = load_spec_schema('upload_complete_multipart_request')
|
expected_request_schema = load_spec_schema('upload_complete_multipart_request')
|
||||||
parameter name: :params, in: :body, schema: expected_request_schema
|
parameter name: :params, in: :body, schema: expected_request_schema
|
||||||
|
|||||||
@@ -125,13 +125,13 @@ RSpec.describe MetadataController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the right output' do
|
it 'returns the right output' do
|
||||||
SiteSetting.app_association_android = <<~EOF
|
SiteSetting.app_association_android = <<~JSON
|
||||||
[{
|
[{
|
||||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||||
"target" : { "namespace": "android_app", "package_name": "com.example.app",
|
"target" : { "namespace": "android_app", "package_name": "com.example.app",
|
||||||
"sha256_cert_fingerprints": ["hash_of_app_certificate"] }
|
"sha256_cert_fingerprints": ["hash_of_app_certificate"] }
|
||||||
}]
|
}]
|
||||||
EOF
|
JSON
|
||||||
get "/.well-known/assetlinks.json"
|
get "/.well-known/assetlinks.json"
|
||||||
|
|
||||||
expect(response.headers["Cache-Control"]).to eq('max-age=60, private')
|
expect(response.headers["Cache-Control"]).to eq('max-age=60, private')
|
||||||
@@ -150,13 +150,13 @@ RSpec.describe MetadataController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the right output' do
|
it 'returns the right output' do
|
||||||
SiteSetting.app_association_ios = <<~EOF
|
SiteSetting.app_association_ios = <<~JSON
|
||||||
{
|
{
|
||||||
"applinks": {
|
"applinks": {
|
||||||
"apps": []
|
"apps": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
JSON
|
||||||
get "/apple-app-site-association"
|
get "/apple-app-site-association"
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
|||||||
@@ -831,14 +831,14 @@ describe UploadsController do
|
|||||||
FileStore::S3Store.any_instance.stubs(:temporary_upload_path).returns(
|
FileStore::S3Store.any_instance.stubs(:temporary_upload_path).returns(
|
||||||
"uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png"
|
"uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png"
|
||||||
)
|
)
|
||||||
create_multipart_result = <<~BODY
|
create_multipart_result = <<~XML
|
||||||
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||||
<InitiateMultipartUploadResult>
|
<InitiateMultipartUploadResult>
|
||||||
<Bucket>s3-upload-bucket</Bucket>
|
<Bucket>s3-upload-bucket</Bucket>
|
||||||
<Key>uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png</Key>
|
<Key>uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png</Key>
|
||||||
<UploadId>#{mock_multipart_upload_id}</UploadId>
|
<UploadId>#{mock_multipart_upload_id}</UploadId>
|
||||||
</InitiateMultipartUploadResult>
|
</InitiateMultipartUploadResult>
|
||||||
BODY
|
XML
|
||||||
stub_request(
|
stub_request(
|
||||||
:post,
|
:post,
|
||||||
"https://s3-upload-bucket.s3.us-west-1.amazonaws.com/uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png?uploads"
|
"https://s3-upload-bucket.s3.us-west-1.amazonaws.com/uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png?uploads"
|
||||||
@@ -948,7 +948,7 @@ describe UploadsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def stub_list_multipart_request
|
def stub_list_multipart_request
|
||||||
list_multipart_result = <<~BODY
|
list_multipart_result = <<~XML
|
||||||
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||||
<ListPartsResult>
|
<ListPartsResult>
|
||||||
<Bucket>s3-upload-bucket</Bucket>
|
<Bucket>s3-upload-bucket</Bucket>
|
||||||
@@ -974,7 +974,7 @@ describe UploadsController do
|
|||||||
</Owner>
|
</Owner>
|
||||||
<StorageClass>STANDARD</StorageClass>
|
<StorageClass>STANDARD</StorageClass>
|
||||||
</ListPartsResult>
|
</ListPartsResult>
|
||||||
BODY
|
XML
|
||||||
stub_request(:get, "https://s3-upload-bucket.s3.us-west-1.amazonaws.com/#{external_upload_stub.key}?max-parts=1&uploadId=#{mock_multipart_upload_id}").to_return({ status: 200, body: list_multipart_result })
|
stub_request(:get, "https://s3-upload-bucket.s3.us-west-1.amazonaws.com/#{external_upload_stub.key}?max-parts=1&uploadId=#{mock_multipart_upload_id}").to_return({ status: 200, body: list_multipart_result })
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1092,7 +1092,7 @@ describe UploadsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def stub_list_multipart_request
|
def stub_list_multipart_request
|
||||||
list_multipart_result = <<~BODY
|
list_multipart_result = <<~XML
|
||||||
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||||
<ListPartsResult>
|
<ListPartsResult>
|
||||||
<Bucket>s3-upload-bucket</Bucket>
|
<Bucket>s3-upload-bucket</Bucket>
|
||||||
@@ -1118,7 +1118,7 @@ describe UploadsController do
|
|||||||
</Owner>
|
</Owner>
|
||||||
<StorageClass>STANDARD</StorageClass>
|
<StorageClass>STANDARD</StorageClass>
|
||||||
</ListPartsResult>
|
</ListPartsResult>
|
||||||
BODY
|
XML
|
||||||
stub_request(:get, "#{upload_base_url}/#{external_upload_stub.key}?max-parts=1&uploadId=#{mock_multipart_upload_id}").to_return({ status: 200, body: list_multipart_result })
|
stub_request(:get, "#{upload_base_url}/#{external_upload_stub.key}?max-parts=1&uploadId=#{mock_multipart_upload_id}").to_return({ status: 200, body: list_multipart_result })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -292,14 +292,14 @@ RSpec.describe ExternalUploadManager do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def copy_object_result
|
def copy_object_result
|
||||||
<<~BODY
|
<<~XML
|
||||||
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||||
<CopyObjectResult
|
<CopyObjectResult
|
||||||
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
|
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
|
||||||
<LastModified>2021-07-19T04:10:41.000Z</LastModified>
|
<LastModified>2021-07-19T04:10:41.000Z</LastModified>
|
||||||
<ETag>"#{etag}"</ETag>
|
<ETag>"#{etag}"</ETag>
|
||||||
</CopyObjectResult>
|
</CopyObjectResult>
|
||||||
BODY
|
XML
|
||||||
end
|
end
|
||||||
|
|
||||||
def stub_copy_object
|
def stub_copy_object
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ describe PostAlerter do
|
|||||||
|
|
||||||
post = Fabricate(:post, topic: pm, user: user1)
|
post = Fabricate(:post, topic: pm, user: user1)
|
||||||
TopicUser.change(user1.id, pm.id, notification_level: TopicUser.notification_levels[:regular])
|
TopicUser.change(user1.id, pm.id, notification_level: TopicUser.notification_levels[:regular])
|
||||||
quote_raw = <<~STRING
|
quote_raw = <<~MD
|
||||||
[quote="#{user1.username}, post:1, topic:#{pm.id}"]#{post.raw}[/quote]
|
[quote="#{user1.username}, post:1, topic:#{pm.id}"]#{post.raw}[/quote]
|
||||||
STRING
|
MD
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
create_post_with_alerts(
|
create_post_with_alerts(
|
||||||
@@ -190,9 +190,9 @@ describe PostAlerter do
|
|||||||
group.add(admin)
|
group.add(admin)
|
||||||
|
|
||||||
TopicUser.change(user2.id, pm.id, notification_level: TopicUser.notification_levels[:regular])
|
TopicUser.change(user2.id, pm.id, notification_level: TopicUser.notification_levels[:regular])
|
||||||
quote_raw = <<~STRING
|
quote_raw = <<~MD
|
||||||
[quote="#{user2.username}, post:1, topic:#{pm.id}"]#{op.raw}[/quote]
|
[quote="#{user2.username}, post:1, topic:#{pm.id}"]#{op.raw}[/quote]
|
||||||
STRING
|
MD
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
create_post_with_alerts(
|
create_post_with_alerts(
|
||||||
@@ -1566,7 +1566,7 @@ describe PostAlerter do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_post_with_incoming
|
def create_post_with_incoming
|
||||||
raw_mail = <<~MAIL
|
raw_mail = <<~EMAIL
|
||||||
From: Foo <foo@discourse.org>
|
From: Foo <foo@discourse.org>
|
||||||
To: discourse@example.com
|
To: discourse@example.com
|
||||||
Cc: bar@discourse.org, jim@othersite.com
|
Cc: bar@discourse.org, jim@othersite.com
|
||||||
@@ -1578,7 +1578,7 @@ describe PostAlerter do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
This is the first email.
|
This is the first email.
|
||||||
MAIL
|
EMAIL
|
||||||
|
|
||||||
Email::Receiver.new(raw_mail, {}).process!
|
Email::Receiver.new(raw_mail, {}).process!
|
||||||
end
|
end
|
||||||
@@ -1716,7 +1716,7 @@ describe PostAlerter do
|
|||||||
email = ActionMailer::Base.deliveries.last
|
email = ActionMailer::Base.deliveries.last
|
||||||
|
|
||||||
# the reply post from someone who was emailed
|
# the reply post from someone who was emailed
|
||||||
reply_raw_mail = <<~MAIL
|
reply_raw_mail = <<~EMAIL
|
||||||
From: Bar <bar@discourse.org>
|
From: Bar <bar@discourse.org>
|
||||||
To: discourse@example.com
|
To: discourse@example.com
|
||||||
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
||||||
@@ -1729,7 +1729,7 @@ describe PostAlerter do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
Hey here is my reply!
|
Hey here is my reply!
|
||||||
MAIL
|
EMAIL
|
||||||
|
|
||||||
reply_post_from_email = nil
|
reply_post_from_email = nil
|
||||||
expect {
|
expect {
|
||||||
@@ -1767,7 +1767,7 @@ describe PostAlerter do
|
|||||||
email = ActionMailer::Base.deliveries.last
|
email = ActionMailer::Base.deliveries.last
|
||||||
|
|
||||||
# the reply post from someone who was emailed
|
# the reply post from someone who was emailed
|
||||||
reply_raw_mail = <<~MAIL
|
reply_raw_mail = <<~EMAIL
|
||||||
From: Foo <foo@discourse.org>
|
From: Foo <foo@discourse.org>
|
||||||
To: discourse@example.com
|
To: discourse@example.com
|
||||||
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
||||||
@@ -1780,7 +1780,7 @@ describe PostAlerter do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
I am ~~Commander Shepherd~~ the OP and I approve of this message.
|
I am ~~Commander Shepherd~~ the OP and I approve of this message.
|
||||||
MAIL
|
EMAIL
|
||||||
|
|
||||||
reply_post_from_email = nil
|
reply_post_from_email = nil
|
||||||
expect {
|
expect {
|
||||||
@@ -1811,7 +1811,7 @@ describe PostAlerter do
|
|||||||
|
|
||||||
# this is a special case where we are not CC'ing on the original email,
|
# this is a special case where we are not CC'ing on the original email,
|
||||||
# only on the follow up email
|
# only on the follow up email
|
||||||
raw_mail = <<~MAIL
|
raw_mail = <<~EMAIL
|
||||||
From: Foo <foo@discourse.org>
|
From: Foo <foo@discourse.org>
|
||||||
To: discourse@example.com
|
To: discourse@example.com
|
||||||
Subject: Full email group username flow
|
Subject: Full email group username flow
|
||||||
@@ -1822,7 +1822,7 @@ describe PostAlerter do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
This is the first email.
|
This is the first email.
|
||||||
MAIL
|
EMAIL
|
||||||
|
|
||||||
incoming_email_post = Email::Receiver.new(raw_mail, {}).process!
|
incoming_email_post = Email::Receiver.new(raw_mail, {}).process!
|
||||||
topic = incoming_email_post.topic
|
topic = incoming_email_post.topic
|
||||||
@@ -1833,7 +1833,7 @@ describe PostAlerter do
|
|||||||
email = ActionMailer::Base.deliveries.last
|
email = ActionMailer::Base.deliveries.last
|
||||||
|
|
||||||
# the reply post from the OP, cc'ing new people in
|
# the reply post from the OP, cc'ing new people in
|
||||||
reply_raw_mail = <<~MAIL
|
reply_raw_mail = <<~EMAIL
|
||||||
From: Foo <foo@discourse.org>
|
From: Foo <foo@discourse.org>
|
||||||
To: discourse@example.com
|
To: discourse@example.com
|
||||||
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
Cc: someothernewcc@baz.com, finalnewcc@doom.com
|
||||||
@@ -1846,7 +1846,7 @@ describe PostAlerter do
|
|||||||
Content-Transfer-Encoding: 7bit
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
I am inviting my mates to this email party.
|
I am inviting my mates to this email party.
|
||||||
MAIL
|
EMAIL
|
||||||
|
|
||||||
reply_post_from_email = nil
|
reply_post_from_email = nil
|
||||||
expect {
|
expect {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def load_spec_schema(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def api_docs_description
|
def api_docs_description
|
||||||
<<~HEREDOC
|
<<~MD
|
||||||
This page contains the documentation on how to use Discourse through API calls.
|
This page contains the documentation on how to use Discourse through API calls.
|
||||||
|
|
||||||
> Note: For any endpoints not listed you can follow the
|
> Note: For any endpoints not listed you can follow the
|
||||||
@@ -71,11 +71,11 @@ def api_docs_description
|
|||||||
|
|
||||||
If an endpoint accepts a boolean be sure to specify it as a lowercase
|
If an endpoint accepts a boolean be sure to specify it as a lowercase
|
||||||
`true` or `false` value unless noted otherwise.
|
`true` or `false` value unless noted otherwise.
|
||||||
HEREDOC
|
MD
|
||||||
end
|
end
|
||||||
|
|
||||||
def direct_uploads_disclaimer
|
def direct_uploads_disclaimer
|
||||||
<<~HEREDOC
|
<<~MD
|
||||||
You must have the correct permissions and CORS settings configured in your
|
You must have the correct permissions and CORS settings configured in your
|
||||||
external provider. We support AWS S3 as the default. See:
|
external provider. We support AWS S3 as the default. See:
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ def direct_uploads_disclaimer
|
|||||||
|
|
||||||
An external file store must be set up and `enable_direct_s3_uploads` must
|
An external file store must be set up and `enable_direct_s3_uploads` must
|
||||||
be set to true for this endpoint to function.
|
be set to true for this endpoint to function.
|
||||||
HEREDOC
|
MD
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
|
|||||||
Reference in New Issue
Block a user