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:
Jarek Radosz 2022-02-28 20:50:55 +01:00 committed by GitHub
parent 7c4be7f649
commit 2fc70c5572
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 392 additions and 392 deletions

View File

@ -45,14 +45,14 @@ class PostsController < ApplicationController
opts[:limit] = MARKDOWN_TOPIC_PAGE_SIZE
topic_view = TopicView.new(params[:topic_id], current_user, opts)
content = topic_view.posts.map do |p|
<<~HEREDOC
<<~MD
#{p.user.username} | #{p.updated_at} | ##{p.post_number}
#{p.raw}
-------------------------
HEREDOC
MD
end
render plain: content.join
end

View File

@ -247,7 +247,7 @@ class SessionController < ApplicationController
rescue ActiveRecord::RecordInvalid => e
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}
#{e.record.errors.to_h}
@ -256,7 +256,7 @@ class SessionController < ApplicationController
SSO Diagnostics:
#{sso.diagnostics}
EOF
TEXT
end
text = nil

View File

@ -303,11 +303,11 @@ module Jobs
# Simulate the args being dumped/parsed through JSON
parsed_opts = JSON.parse(JSON.dump(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.
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).
MSG
TEXT
end
opts = parsed_opts

View File

@ -59,7 +59,7 @@ class ReviewableSerializer < ApplicationSerializer
def self.create_attribute(name, field)
attribute(name)
class_eval <<~GETTER
class_eval <<~RUBY
def #{name}
#{field}
end
@ -67,7 +67,7 @@ class ReviewableSerializer < ApplicationSerializer
def include_#{name}?
#{name}.present?
end
GETTER
RUBY
end
# This is easier than creating an AMS method for each attribute

View File

@ -11,7 +11,7 @@ class UserActionManager
end
[:notification, :post, :topic, :post_action].each do |type|
self.class_eval(<<~METHODS)
self.class_eval(<<~RUBY)
def self.#{type}_created(*args)
return if @disabled
#{type}_rows(*args).each { |row| UserAction.log_action!(row) }
@ -20,7 +20,7 @@ class UserActionManager
return if @disabled
#{type}_rows(*args).each { |row| UserAction.remove_action!(row) }
end
METHODS
RUBY
end
private

View File

@ -39,7 +39,7 @@ if ENV["TRACE_PG_CONNECTIONS"]
def log_access(&blk)
@access_log_mutex.synchronize do
if !@accessor_thread.nil?
Rails.logger.error <<~STRING
Rails.logger.error <<~TEXT
PG Clash: A connection is being accessed from two locations
#{@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&.backtrace&.join("\n")}
STRING
TEXT
if ENV["ON_PG_CLASH"] == "byebug"
require "byebug"

View File

@ -5,7 +5,7 @@
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)
puts <<END
puts <<~TEXT
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
experience problems, like links in emails using #{Discourse.current_hostname}.
END
TEXT
raise "Invalid host_names in database.yml"
end
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
before starting the rails server in production mode:
rake assets:precompile
END
TEXT
raise "Assets have not been precompiled"
end

View File

@ -11,10 +11,10 @@ class FixIncorrectUserHistory < ActiveRecord::Migration[4.2]
# this is a :auto_trust_level_change mislabeled as :check_email
# impersonate that was actually delete topic
condition = <<CLAUSE
(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)
CLAUSE
condition = <<~SQL
(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)
SQL
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

View File

@ -1011,13 +1011,13 @@ module Email
def forwarded_email_quote_forwarded(destination, user)
embedded = embedded_email_raw
raw = <<~EOF
raw = <<~MD
#{@before_embedded}
[quote]
#{PlainTextToMarkdown.new(embedded).to_markdown}
[/quote]
EOF
MD
return true if forwarded_email_create_topic(destination: destination, user: user, raw: raw, title: subject)
end

View File

@ -18,7 +18,7 @@ class Barber::Precompiler
# very hacky but lets us use ES6. I'm ashamed of this code -RW
transpiled = transpiled[transpiled.index('var RawHandlebars = ')...transpiled.index('export ')]
@precompiler = StringIO.new <<~END
@precompiler = StringIO.new <<~JS
var __RawHandlebars;
(function() {
#{transpiled};
@ -30,7 +30,7 @@ class Barber::Precompiler
return __RawHandlebars.precompile(string, false).toString();
}
};
END
JS
end
@precompiler
@ -111,10 +111,10 @@ class Ember::Handlebars::Template
"define('#{module_name}', ['exports'], function(__exports__){ __exports__['default'] = #{template} });"
when :global
if raw
return <<~RAW_TEMPLATE
return <<~JS
var __t = #{template};
requirejs('discourse-common/lib/raw-templates').addRawTemplate(#{path_for(template_name, config)}, __t);
RAW_TEMPLATE
JS
end
target = global_template_target('Ember.TEMPLATES', template_name, config)

View File

@ -121,7 +121,7 @@ class Migration::SafeMigrate
def self.protect!(sql)
if sql =~ /^\s*(?:drop\s+table|alter\s+table.*rename\s+to)\s+/i
$stdout.puts("", <<~STR)
$stdout.puts("", <<~TEXT)
WARNING
-------------------------------------------------------------------------------------
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
in use by live applications.
STR
TEXT
raise Discourse::InvalidMigration, "Attempt was made to drop a table"
elsif sql =~ /^\s*alter\s+table.*(?:rename|drop)\s+/i
$stdout.puts("", <<~STR)
$stdout.puts("", <<~TEXT)
WARNING
-------------------------------------------------------------------------------------
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
in use by live applications.
STR
TEXT
raise Discourse::InvalidMigration, "Attempt was made to rename or delete column"
end
end

View File

@ -218,14 +218,14 @@ module Onebox
def card_html
escaped_url = ::Onebox::Helpers.normalize_url_for_output(data[:player])
<<~RAW
<<~HTML
<iframe src="#{escaped_url}"
width="#{data[:player_width] || "100%"}"
height="#{data[:player_height]}"
scrolling="no"
frameborder="0">
</iframe>
RAW
HTML
end
def article_html

View File

@ -24,7 +24,7 @@ def plugin_initialization_guard(&block)
end
end.reverse.join("\n")
STDERR.puts <<~MESSAGE
STDERR.puts <<~TEXT
#{stack_trace}
** INCOMPATIBLE PLUGIN **
@ -33,9 +33,9 @@ def plugin_initialization_guard(&block)
#{plugin_path}
Please try removing this plugin and rebuilding again!
MESSAGE
TEXT
else
STDERR.puts <<~MESSAGE
STDERR.puts <<~TEXT
** PLUGIN FAILURE **
You are unable to build Discourse due to this error during plugin
@ -44,7 +44,7 @@ def plugin_initialization_guard(&block)
#{error}
#{error.backtrace.join("\n")}
MESSAGE
TEXT
end
exit 1
end

View File

@ -34,23 +34,23 @@ module Stylesheet
contents = +""
if body_font.present?
contents << <<~EOF
contents << <<~CSS
#{font_css(body_font)}
:root {
--font-family: #{body_font[:stack]};
}
EOF
CSS
end
if heading_font.present?
contents << <<~EOF
contents << <<~CSS
#{font_css(heading_font)}
:root {
--heading-font-family: #{heading_font[:stack]};
}
EOF
CSS
end
contents
@ -70,14 +70,14 @@ module Stylesheet
end
contents << font_css(font)
contents << <<~EOF
contents << <<~CSS
.body-font-#{font[:key].tr("_", "-")} {
font-family: #{font[:stack]};
}
.heading-font-#{font[:key].tr("_", "-")} h2 {
font-family: #{font[:stack]};
}
EOF
CSS
end
contents
@ -184,11 +184,11 @@ module Stylesheet
fields.map do |field|
value = field.value
if value.present?
contents << <<~COMMENT
contents << <<~SCSS
// Theme: #{field.theme.name}
// Target: #{field.target_name} #{field.name}
// Last Edited: #{field.updated_at}
COMMENT
SCSS
contents << value
end
@ -216,13 +216,13 @@ module Stylesheet
fonts_dir = UrlHelper.absolute("#{Discourse.base_path}/fonts")
font[:variants].each do |variant|
src = variant[:src] ? variant[:src] : "url(\"#{fonts_dir}/#{variant[:filename]}?v=#{DiscourseFonts::VERSION}\") format(\"#{variant[:format]}\")"
contents << <<~EOF
contents << <<~CSS
@font-face {
font-family: #{font[:name]};
src: #{src};
font-weight: #{variant[:weight]};
}
EOF
CSS
end
end

View File

@ -15,10 +15,10 @@ task 'assets:precompile:before' do
if EMBER_CLI && !(ENV["EMBER_CLI_COMPILE_DONE"] == "1")
# 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 && \
EMBER_CLI_COMPILE_DONE=1 bin/rake assets:precompile
SCRIPT
SH
end
# Ensure we ALWAYS do a clean build
@ -124,9 +124,9 @@ def compress_node(from, to)
source_map_url = "#{File.basename(to)}.map"
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"
EOS
SH
STDERR.puts cmd
result = `#{cmd} 2>&1`

View File

@ -65,7 +65,7 @@ task 'emails:test', [:email] => [:environment] do |_, args|
smtp = Discourse::Application.config.action_mailer.smtp_settings
if smtp[:address].match(/smtp\.gmail\.com/)
puts <<~STR
puts <<~TEXT
#{smtp}
============================== 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
========================= CONTINUING TEST ============================
STR
TEXT
end
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
if e.to_s.match(/execution expired/)
message = <<~STR
message = <<~TEXT
======================================== ERROR ========================================
Connection to port #{smtp[:port]} failed.
====================================== SOLUTION =======================================
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.
=======================================================================================
STR
TEXT
elsif e.to_s.match(/530.*STARTTLS/)
# We can't run a preliminary test with STARTTLS, we'll just try sending the test email.
message = "OK"
elsif e.to_s.match(/535/)
message = <<~STR
message = <<~TEXT
======================================== ERROR ========================================
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.
Check them and try again.
=======================================================================================
STR
TEXT
elsif e.to_s.match(/Connection refused/)
message = <<~STR
message = <<~TEXT
======================================== ERROR ========================================
CONNECTION REFUSED
@ -132,10 +132,10 @@ task 'emails:test', [:email] => [:environment] do |_, args|
Check the port and your networking configuration.
=======================================================================================
STR
TEXT
elsif e.to_s.match(/service not known/)
message = <<~STR
message = <<~TEXT
======================================== ERROR ========================================
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.
Check it and try again.
=======================================================================================
STR
TEXT
else
message = <<~STR
message = <<~TEXT
======================================== 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/
(And a solution, if you find one!)
=======================================================================================
STR
TEXT
end
end
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
case email_log
when SkippedEmailLog
puts <<~STR
puts <<~TEXT
Mail was not sent.
Reason: #{email_log.reason}
STR
TEXT
when EmailLog
puts <<~STR
puts <<~TEXT
Mail accepted by SMTP server.
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.
Check the SMTP server logs for the above Message ID to see why it
failed to deliver the message.
STR
TEXT
when nil
puts <<~STR
puts <<~TEXT
Mail was not sent.
Verify the status of the `disable_emails` site setting.
STR
TEXT
else
puts <<~STR
puts <<~TEXT
SCRIPT BUG: Got back a #{email_log.class}
#{email_log.inspect}
Mail may or may not have been sent. Check the destination mailbox.
STR
TEXT
end
rescue => error
puts "Sending mail failed."
@ -211,11 +211,11 @@ task 'emails:test', [:email] => [:environment] do |_, args|
end
if SiteSetting.disable_emails != 'no'
puts <<~STR
puts <<~TEXT
### WARNING
The `disable_emails` site setting is currently set to #{SiteSetting.disable_emails}.
Consider changing it to 'no' before performing any further troubleshooting.
STR
TEXT
end
end

View File

@ -22,7 +22,7 @@ def html_for_section(group)
" {{replace-emoji \":#{icon['name']}:\" (hash lazy=true#{class_attr})}}"
end
<<~SECTION
<<~HTML
<div class="section" data-section="#{group["name"]}">
<div class="section-header">
<span class="title">{{i18n "emoji_picker.#{group["name"]}"}}</span>
@ -31,14 +31,14 @@ def html_for_section(group)
#{icons.join("\n").strip}
</div>
</div>
SECTION
HTML
end
def write_template(path, task_name, template)
header = <<~HEADER
header = <<~JS
// DO NOT EDIT THIS FILE!!!
// Update it by running `rake javascript:#{task_name}`
HEADER
JS
basename = File.basename(path)
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
@ -50,10 +50,10 @@ def write_template(path, task_name, template)
end
def write_hbs_template(path, task_name, template)
header = <<~HEADER
header = <<~HBS
{{!-- DO NOT EDIT THIS FILE!!! --}}
{{!-- Update it by running `rake javascript:#{task_name}` --}}
HEADER
HBS
basename = File.basename(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"))
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">
{{replace-emoji ":#{group["tabicon"]}:"}}
</button>
BUTTON
HTML
end
emoji_sections = groups_json.map { |group| html_for_section(group) }

View File

@ -3,7 +3,7 @@
# Generates posts and topics
class Populate < Thor
desc "posts", "Generate posts"
long_desc <<-LONGDESC
long_desc <<-MD
Create topics with any number of posts, or add posts to an existing topic.
Examples:
@ -20,7 +20,7 @@ class Populate < Thor
> $ 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 :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"

View File

@ -118,7 +118,7 @@ task "themes:qunit", :type, :value do |t, args|
type = args[:type]
value = args[:value]
if !%w(name url id).include?(type) || value.blank?
raise <<~MSG
raise <<~TEXT
Wrong arguments type:#{type.inspect}, value:#{value.inspect}"
Usage:
`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>]"`
OR
`bundle exec rake "themes:qunit[id,<theme_id>]"`
MSG
TEXT
end
ENV["THEME_#{type.upcase}"] = value.to_s
ENV["QUNIT_RAILS_ENV"] ||= 'development' # qunit:test will switch to `test` by default

View File

@ -165,11 +165,11 @@ def clean_up_uploads
exit 1
end
puts <<~OUTPUT
puts <<~TEXT
This task will remove upload records and files permanently.
Would you like to take a full backup before the clean up? (Y/N)
OUTPUT
TEXT
if STDIN.gets.chomp.downcase == 'y'
puts "Starting backup..."
@ -420,7 +420,7 @@ task "uploads:analyze", [:cache_path, :limit] => :environment do |_, args|
uploads_count = Upload.count
optimized_images_count = OptimizedImage.count
puts <<~REPORT
puts <<~TEXT
Report for '#{current_db}'
-----------#{'-' * current_db.length}
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}
------------------------------------#{'-' * paths_count.to_s.length}
REPORT
TEXT
helper = Class.new do
include ActionView::Helpers::NumberHelper

View File

@ -28,13 +28,13 @@ describe PrettyText do
end
it 'can replace spoilers in emails' do
md = PrettyText.cook(<<~EOF)
md = PrettyText.cook(<<~MD)
hello
[details="Summary"]
world
[/details]
EOF
MD
md = PrettyText.format_for_email(md, post)
html = "<p>hello</p>\n\nSummary <a href=\"#{post.full_url}\">(click for more details)</a>"
@ -42,7 +42,7 @@ describe PrettyText do
end
it 'properly handles multiple spoiler blocks in a post' do
md = PrettyText.cook(<<~EOF)
md = PrettyText.cook(<<~MD)
[details="First"]
body secret stuff very long
[/details]
@ -55,7 +55,7 @@ describe PrettyText do
[details="Third"]
body secret stuff very long
[/details]
EOF
MD
md = PrettyText.format_for_email(md, post)
expect(md).not_to include('secret stuff')
@ -65,12 +65,12 @@ describe PrettyText do
end
it 'escapes summary text' do
md = PrettyText.cook(<<~EOF)
md = PrettyText.cook(<<~MD)
<script>alert('hello')</script>
[details="<script>alert('hello')</script>"]
<script>alert('hello')</script>
[/details]
EOF
MD
md = PrettyText.format_for_email(md, post)
expect(md).not_to include('<script>')

View File

@ -8,9 +8,9 @@ RSpec.describe "Local Dates" do
end
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"]
TXT
MD
cooked = post.cooked
@ -28,9 +28,9 @@ RSpec.describe "Local Dates" do
end
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"]
TXT
MD
cooked = post.cooked
@ -39,9 +39,9 @@ RSpec.describe "Local Dates" do
end
it 'requires the right attributes to convert to a local date' do
post = Fabricate(:post, raw: <<~TXT)
post = Fabricate(:post, raw: <<~MD)
[date]
TXT
MD
cooked = post.cooked
@ -50,9 +50,9 @@ RSpec.describe "Local Dates" do
end
it 'requires the right attributes to convert to a local date' do
post = Fabricate(:post, raw: <<~TXT)
post = Fabricate(:post, raw: <<~MD)
[date]
TXT
MD
cooked = post.cooked

View File

@ -163,11 +163,11 @@ module DiscourseNarrativeBot
def start_advanced_track
raw = I18n.t("#{I18N_KEY}.start_message", i18n_post_args(username: @user.username))
raw = <<~RAW
raw = <<~MD
#{raw}
#{instance_eval(&@next_instructions)}
RAW
MD
opts = {
title: I18n.t("#{I18N_KEY}.title"),
@ -197,11 +197,11 @@ module DiscourseNarrativeBot
fake_delay
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.edit.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
reply_to(@post, raw)
end
@ -227,11 +227,11 @@ module DiscourseNarrativeBot
fake_delay
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.delete.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
PostCreator.create!(self.discobot_user,
raw: raw,
@ -252,11 +252,11 @@ module DiscourseNarrativeBot
fake_delay
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.recover.reply", i18n_post_args(deletion_after: SiteSetting.delete_removed_posts_after))}
#{instance_eval(&@next_instructions)}
RAW
MD
PostCreator.create!(self.discobot_user,
raw: raw,
@ -279,11 +279,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(topic_id)
if Nokogiri::HTML5.fragment(@post.cooked).css('.hashtag').size > 0
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.category_hashtag.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
reply_to(@post, raw)
@ -308,11 +308,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(@topic_id)
fake_delay
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.change_topic_notification_level.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -330,11 +330,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(topic_id)
if Nokogiri::HTML5.fragment(@post.cooked).css(".poll").size > 0
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.poll.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
reply_to(@post, raw)

View File

@ -175,11 +175,11 @@ module DiscourseNarrativeBot
MessageBus.publish('/new_user_narrative/tutorial_search', {}, user_ids: [@user.id])
raw = <<~RAW
raw = <<~MD
#{post.raw}
#{I18n.t("#{I18N_KEY}.search.hidden_message", i18n_post_args.merge(search_answer: NewUserNarrative.search_answer))}
RAW
MD
PostRevisor.new(post, topic).revise!(
self.discobot_user,
@ -206,11 +206,11 @@ module DiscourseNarrativeBot
)
)
raw = <<~RAW
raw = <<~MD
#{raw}
#{instance_eval(&@next_instructions)}
RAW
MD
title = I18n.t("#{I18N_KEY}.hello.title", title: SiteSetting.title)
if SiteSetting.max_emojis_in_title == 0
@ -259,11 +259,11 @@ module DiscourseNarrativeBot
profile_page_url = url_helpers(:user_url, username: @user.username)
bookmark_url = "#{profile_page_url}/activity/bookmarks"
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.bookmark.reply", i18n_post_args(bookmark_url: bookmark_url))}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -279,11 +279,11 @@ module DiscourseNarrativeBot
@post.post_analyzer.cook(@post.raw, {})
if @post.post_analyzer.found_oneboxes?
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.onebox.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -315,11 +315,11 @@ module DiscourseNarrativeBot
fake_delay
like_post(post)
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
reply = reply_to(@post, raw)
enqueue_timeout_job(@user)
@ -350,11 +350,11 @@ module DiscourseNarrativeBot
set_state_data(:post_id, @post.id)
if get_state_data(:liked)
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.images.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
like_post(@post)
else
@ -405,11 +405,11 @@ module DiscourseNarrativeBot
)
if post_liked
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.likes.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -426,11 +426,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(post_topic_id)
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)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -452,11 +452,11 @@ module DiscourseNarrativeBot
doc = Nokogiri::HTML5.fragment(@post.cooked)
if doc.css(".quote").size > 0
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.quoting.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -478,11 +478,11 @@ module DiscourseNarrativeBot
doc = Nokogiri::HTML5.fragment(@post.cooked)
if doc.css(".emoji").size > 0
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.emoji.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -502,11 +502,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(post_topic_id)
if bot_mentioned?(@post)
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.mention.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay
@ -552,11 +552,11 @@ module DiscourseNarrativeBot
return unless valid_topic?(post_topic_id)
return unless @post.user.id == -2
raw = <<~RAW
raw = <<~MD
#{I18n.t("#{I18N_KEY}.flag.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
MD
fake_delay

View File

@ -36,7 +36,7 @@ class Onebox::Engine::YoutubeOnebox
# Put in the LazyYT div instead of the iframe
escaped_title = ERB::Util.html_escape(video_title)
<<~EOF
<<~HTML
<div class="onebox lazyYT lazyYT-container"
data-youtube-id="#{video_id}"
data-youtube-title="#{escaped_title}"
@ -49,7 +49,7 @@ class Onebox::Engine::YoutubeOnebox
title="#{escaped_title}">
</a>
</div>
EOF
HTML
else
yt_onebox_to_html
end

View File

@ -39,12 +39,12 @@ describe NewPostManager do
end
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]
* 1
* 2
[/poll]
RAW
MD
result = NewPostManager.new(user, params).perform

View File

@ -1,12 +1,12 @@
# frozen_string_literal: true
require "pg"
usage = <<-END
usage = <<-TEXT
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 100 move all timestamps forward by 100 days
ruby db_timestamp_updater.rb -100 move all timestamps backward by 100 days
END
TEXT
class TimestampsUpdater
def initialize(schema, ignore_tables)

View File

@ -9,7 +9,7 @@ class DiscourseCLI < Thor
end
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.
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 --regex "\[\/?color(=[^\]]*)*]" "" # removing "color" bbcodes
LONGDESC
TEXT
option :global, type: :boolean
option :regex, type: :boolean
def remap(from, to)

View File

@ -85,11 +85,11 @@ def crawl_topics
begin
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"
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".
MSG
TEXT
end
rescue Selenium::WebDriver::Error::NoSuchElementError
# 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
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.
Use the --force option to import anyway.
MSG
TEXT
end
end

View File

@ -114,28 +114,28 @@ class ImportScripts::IpboardSQL < ImportScripts::Base
rescue Exception => e
puts '=' * 50
puts e.message
puts <<EOM
Cannot log in to database.
puts <<~TEXT
Cannot log in to database.
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
You should set these variables:
You should set these variables:
export DB_HOST="localhost"
export DB_NAME="ipboard"
export DB_PW="ipboard"
export DB_USER="ipboard"
export TABLE_PREFIX="ipb_"
export IMPORT_AFTER="1970-01-01"
export URL="http://example.com"
export UPLOADS=
export USERDIR="user"
export DB_HOST="localhost"
export DB_NAME="ipboard"
export DB_PW="ipboard"
export DB_USER="ipboard"
export TABLE_PREFIX="ipb_"
export IMPORT_AFTER="1970-01-01"
export URL="http://example.com"
export UPLOADS=
export USERDIR="user"
Exiting.
EOM
Exiting.
TEXT
exit
end
end

View File

@ -43,25 +43,25 @@ class ImportScripts::Modx < ImportScripts::Base
rescue Exception => e
puts '=' * 50
puts e.message
puts <<EOM
Cannot connect in to database.
puts <<~TEXT
Cannot connect in to database.
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
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_NAME="modx"
export DB_PW="modx"
export DB_USER="modx"
export TABLE_PREFIX="modx_"
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
export DB_HOST="localhost"
export DB_NAME="modx"
export DB_PW="modx"
export DB_USER="modx"
export TABLE_PREFIX="modx_"
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
Exiting.
EOM
Exiting.
TEXT
exit
end
@ -446,12 +446,12 @@ FROM #{TABLE_PREFIX}discuss_users
# keep track of closed topics
closed_topic_ids = []
topics = mysql_query <<-MYSQL
topics = mysql_query <<-SQL
SELECT t.threadid threadid, firstpostid, open
FROM #{TABLE_PREFIX}thread t
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
ORDER BY t.threadid
MYSQL
SQL
topics.each do |topic|
topic_id = "thread-#{topic["threadid"]}"
closed_topic_ids << topic_id if topic["open"] == 0

View File

@ -58,27 +58,27 @@ class ImportScripts::MylittleforumSQL < ImportScripts::Base
rescue Exception => e
puts '=' * 50
puts e.message
puts <<EOM
Cannot log in to database.
puts <<~TEXT
Cannot log in to database.
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
You should set these variables:
You should set these variables:
export DB_HOST="localhost"
export DB_NAME="mylittleforum"
export DB_PW=""
export DB_USER="root"
export TABLE_PREFIX="forum_"
export IMPORT_AFTER="1970-01-01"
export IMAGE_BASE="http://www.example.com/forum"
export BASE="forum"
export DB_HOST="localhost"
export DB_NAME="mylittleforum"
export DB_PW=""
export DB_USER="root"
export TABLE_PREFIX="forum_"
export IMPORT_AFTER="1970-01-01"
export IMAGE_BASE="http://www.example.com/forum"
export BASE="forum"
Exiting.
EOM
Exiting.
TEXT
exit
end
end

View File

@ -26,10 +26,10 @@ module ImportScripts::PhpBB3
require_relative 'database_3_1'
Database_3_1.new(@database_client, @database_settings)
else
raise UnsupportedVersionError, <<~MSG
raise UnsupportedVersionError, <<~TEXT
Unsupported version (#{version}) of phpBB detected.
Currently only version 3.0, 3.1 and 3.2 are supported by this importer.
MSG
TEXT
end
end

View File

@ -53,25 +53,25 @@ class ImportScripts::VBulletin < ImportScripts::Base
rescue Exception => e
puts '=' * 50
puts e.message
puts <<EOM
Cannot connect in to database.
puts <<~TEXT
Cannot connect in to database.
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
database: #{DB_NAME}
Hostname: #{DB_HOST}
Username: #{DB_USER}
Password: #{DB_PW}
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_NAME="vbulletin"
export DB_PW=""
export DB_USER="root"
export TABLE_PREFIX="vb_"
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
export DB_HOST="localhost"
export DB_NAME="vbulletin"
export DB_PW=""
export DB_USER="root"
export TABLE_PREFIX="vb_"
export ATTACHMENT_DIR '/path/to/your/attachment/folder'
Exiting.
EOM
Exiting.
TEXT
exit
end
@ -674,12 +674,12 @@ EOM
# keep track of closed topics
closed_topic_ids = []
topics = mysql_query <<-MYSQL
topics = mysql_query <<-SQL
SELECT t.threadid threadid, firstpostid, open
FROM #{TABLE_PREFIX}thread t
JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid
ORDER BY t.threadid
MYSQL
SQL
topics.each do |topic|
topic_id = "thread-#{topic["threadid"]}"
closed_topic_ids << topic_id if topic["open"] == 0

View File

@ -100,9 +100,9 @@ end
puts 'Done! File moves are staged and ready for commit.'
puts 'Suggested commit message:'
puts '-' * 20
puts <<~MESSAGE
puts <<~TEXT
DEV: Promote historic post_deploy migrations
This commit promotes all post_deploy migrations which existed in Discourse #{previous_stable_version} (timestamp <= #{promote_threshold})
MESSAGE
TEXT
puts '-' * 20

View File

@ -8,7 +8,7 @@ Fabricator(:incoming_email) do
imap_sync false
created_via 0
raw <<~RAW
raw <<~EMAIL
Return-Path: <foo@example.com>
From: Foo <foo@example.com>
To: someone@else.com
@ -20,5 +20,5 @@ Fabricator(:incoming_email) do
Content-Transfer-Encoding: quoted-printable
The body contains "Hello world" too.
RAW
EMAIL
end

View File

@ -102,20 +102,20 @@ Fabricator(:post_with_uploads, from: :post) do
end
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>
<img src="/#{Discourse.store.upload_path}/original/1X/1234567890123456.jpg">
<a href="http://www.google.com">Google</a>
<img src="http://foo.bar/image.png">
<a class="attachment" href="/#{Discourse.store.upload_path}/original/1X/af2c2618032c679333bebf745e75f9088748d737.txt">text.txt</a> (20 Bytes)
:smile:
RAW
MD
end
Fabricator(:post_with_external_links, from: :post) do
user
topic
raw <<~RAW
raw <<~MD
Here's a link to twitter: http://twitter.com
And a link to google: http://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 one with a hash http://discourse.org#faq
And one with a two hash http://discourse.org#a#b
RAW
MD
end
Fabricator(:private_message_post, from: :post) do

View File

@ -25,13 +25,13 @@ describe 'Coding style' do
js_files = list_js_files('app/assets/javascripts')
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
prefer to use this.foo
Offenses:
#{offenses.join("\n")}
MSG
TEXT
end
end
@ -41,7 +41,7 @@ describe 'Coding style' do
constant_name_regex = /#{Regexp.escape(constant_name)}/
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
#{method_name} in order to help with restoring backups.
@ -49,7 +49,7 @@ describe 'Coding style' do
Offenses:
#{offenses.join("\n")}
MSG
TEXT
end
def is_valid?(file, method_name_regex, constant_name_regex)

View File

@ -25,36 +25,36 @@ describe Jobs::OldKeysReminder do
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.title).to eq('Reminder about old credentials')
expect(post.raw).to eq(<<-MSG.rstrip)
Hello! This is a routine yearly security reminder from your Discourse instance.
expect(post.raw).to eq(<<~TEXT.rstrip)
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)}
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
api key description - #{api_key.created_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)}
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.
MSG
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
TEXT
post.topic.destroy
freeze_time 4.years.from_now
described_class.new.execute({})
post = Post.last
expect(post.topic.title).to eq('Reminder about old credentials')
expect(post.raw).to eq(<<-MSG.rstrip)
Hello! This is a routine yearly security reminder from your Discourse instance.
expect(post.raw).to eq(<<~TEXT.rstrip)
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)}
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)}
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)}
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)}
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)}
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.
MSG
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
TEXT
end
it 'does not send message when send_old_credential_reminder_days is set to 0 or no old keys' do

View File

@ -122,12 +122,12 @@ describe Jobs::PullHotlinkedImages do
stub_request(:get, "http://test.localhost/uploads/short-url/z2QSs1KJWoj51uYhDjb6ifCzxH6.gif")
.to_return(status: 200, body: "")
post = Fabricate(:post, raw: <<~RAW)
post = Fabricate(:post, raw: <<~MD)
<h1></h1>
<a href="https://somelink.com">
<img alt="somelink" src="#{image_url}" />
</a>
RAW
MD
expect do
Jobs::PullHotlinkedImages.new.execute(post_id: post.id)
@ -135,12 +135,12 @@ describe Jobs::PullHotlinkedImages do
upload = post.uploads.last
expect(post.reload.raw).to eq(<<~RAW.chomp)
expect(post.reload.raw).to eq(<<~MD.chomp)
<h1></h1>
<a href="https://somelink.com">
![somelink](#{upload.short_url})
</a>
RAW
MD
end
it 'replaces correct image URL' do
@ -371,12 +371,12 @@ describe Jobs::PullHotlinkedImages do
end
it 'all combinations' do
post = Fabricate(:post, raw: <<~BODY)
post = Fabricate(:post, raw: <<~MD)
<img src='#{image_url}'>
#{url}
<img src='#{broken_image_url}'>
<a href='#{url}'><img src='#{large_image_url}'></a>
BODY
MD
stub_image_size
2.times do

View File

@ -327,13 +327,13 @@ describe ContentSecurityPolicy do
it 'is extended automatically when themes reference external scripts' do
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/myscript2.js?with=query'></script>
<script src='//example2.com/protocol-less-script.js'></script>
<script src='domain-only.com'></script>
<script>console.log('inline script')</script>
SCRIPT
HTML
theme.set_field(target: :desktop, name: "header", value: "")
theme.save!

View File

@ -14,10 +14,10 @@ describe Email::AuthenticationResults do
it "parses 'Service Provided, Authentication Done' correctly" do
# https://tools.ietf.org/html/rfc8601#appendix-B.3
results = described_class.new(<<~EOF
results = described_class.new(<<~RAW
example.com;
spf=pass smtp.mailfrom=example.net
EOF
RAW
).results
expect(results[0][:authserv_id]).to eq "example.com"
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
# https://tools.ietf.org/html/rfc8601#appendix-B.4
results = described_class.new([<<~EOF ,
results = described_class.new([<<~RAW ,
example.com;
auth=pass (cram-md5) smtp.auth=sender@example.net;
spf=pass smtp.mailfrom=example.net
EOF
<<~EOF ,
RAW
<<~RAW ,
example.com; iprev=pass
policy.iprev=192.0.2.200
EOF
RAW
]).results
expect(results[0][:authserv_id]).to eq "example.com"
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
# https://tools.ietf.org/html/rfc8601#appendix-B.5
results = described_class.new([<<~EOF ,
results = described_class.new([<<~RAW ,
example.com;
dkim=pass (good signature) header.d=example.com
EOF
<<~EOF ,
RAW
<<~RAW ,
example.com;
auth=pass (cram-md5) smtp.auth=sender@example.com;
spf=fail smtp.mailfrom=example.com
EOF
RAW
]).results
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
# https://tools.ietf.org/html/rfc8601#appendix-B.6
results = described_class.new([<<~EOF ,
results = described_class.new([<<~RAW ,
example.com;
dkim=pass reason="good signature"
header.i=@mail-router.example.net;
dkim=fail reason="bad signature"
header.i=@newyork.example.com
EOF
<<~EOF ,
RAW
<<~RAW ,
example.net;
dkim=pass (good signature) header.i=@newyork.example.com
EOF
RAW
]).results
expect(results[0][:authserv_id]).to eq "example.com"
@ -136,12 +136,12 @@ describe Email::AuthenticationResults do
it "parses 'Comment-Heavy Example' correctly" do
# 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);
dkim (Because I like it) / 1 (One yay) = (wait for it) fail
policy (A dot can go here) . (like that) expired
(this surprised me) = (as I wasn't expecting it) 1362471462
EOF
RAW
).results
expect(results[0][:authserv_id]).to eq "foo.example.net"
@ -163,12 +163,12 @@ describe Email::AuthenticationResults do
end
it "parses header with multiple props correctly" do
results = described_class.new(<<~EOF
results = described_class.new(<<~RAW
mx.google.com;
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;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=email.example.com
EOF
RAW
).results
expect(results[0][:authserv_id]).to eq "mx.google.com"

View File

@ -808,7 +808,7 @@ describe Email::Receiver do
post = Post.last
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?
[quote]
@ -823,8 +823,7 @@ describe Email::Receiver do
XoXo
[/quote]
EOF
)
RAW
end
end
@ -976,7 +975,7 @@ describe Email::Receiver do
let!(:post) { Fabricate(:post, topic: topic) }
def process_mail_with_message_id(message_id)
mail_string = <<~REPLY
mail_string = <<~EMAIL
Return-Path: <two@foo.com>
From: Two <two@foo.com>
To: one@foo.com
@ -989,7 +988,7 @@ describe Email::Receiver do
Content-Transfer-Encoding: 7bit
This is email reply testing with Message-ID formats.
REPLY
EMAIL
Email::Receiver.new(mail_string).process!
end
@ -1867,7 +1866,7 @@ describe Email::Receiver do
context "#select_body" do
let(:email) {
<<~EOF
<<~EMAIL
MIME-Version: 1.0
Date: Tue, 01 Jan 2019 00:00:00 +0300
Subject: An email with whitespaces
@ -1916,11 +1915,11 @@ describe Email::Receiver do
This is going to be stripped too.
Bye!
EOF
EMAIL
}
let(:stripped_text) {
<<~EOF
<<~MD
This is a 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.
Bye!
EOF
MD
}
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
SiteSetting.strip_incoming_email_lines = true
email = <<~EOF
email = <<~EMAIL
Date: Tue, 01 Jan 2019 00:00:00 +0300
Subject: An email with whitespaces
From: Foo <foo@discourse.org>
@ -1986,7 +1985,7 @@ describe Email::Receiver do
--
my signature
EOF
EMAIL
receiver = Email::Receiver.new(email)
text, _elided, _format = receiver.select_body
@ -2004,7 +2003,7 @@ describe Email::Receiver do
message_id: digest_message_id
)}
let(:email) {
<<~EOF
<<~EMAIL
MIME-Version: 1.0
Date: Tue, 01 Jan 2019 00:00:00 +0300
From: someone <#{user.email}>
@ -2017,7 +2016,7 @@ describe Email::Receiver do
hello there! I like the digest!
EOF
EMAIL
}
before do
@ -2034,7 +2033,7 @@ describe Email::Receiver do
let(:user) { Fabricate(:user) }
let(:group) { Fabricate(:group, users: [user]) }
let (:email_1) { <<~EOF
let (:email_1) { <<~EMAIL
MIME-Version: 1.0
Date: Wed, 01 Jan 2019 12:00:00 +0200
Message-ID: <7aN1uwcokt2xkfG3iYrpKmiuVhy4w9b5@mail.gmail.com>
@ -2052,7 +2051,7 @@ describe Email::Receiver do
Vivamus semper lacinia scelerisque. Cras urna magna, porttitor nec
libero quis, congue viverra sapien. Nulla sodales ac tellus a
suscipit.
EOF
EMAIL
}
let (:post_2) {
@ -2064,7 +2063,7 @@ describe Email::Receiver do
)
}
let (:email_3) { <<~EOF
let (:email_3) { <<~EMAIL
MIME-Version: 1.0
Date: Wed, 01 Jan 2019 12:00:00 +0200
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
iaculis mi, at hendrerit nisi turpis sit amet metus. Nulla egestas
ante eget nisi luctus consectetur.
EOF
EMAIL
}
def receive(email_string)

View File

@ -16,28 +16,28 @@ describe EmailCook do
end
it "doesn't add linebreaks to long lines" do
long = plaintext(<<~LONG_EMAIL)
long = plaintext(<<~EMAIL)
Hello,
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.
Vestibulum feugiat mi vitae turpis tempor dignissim.
LONG_EMAIL
EMAIL
long_cooked = (+<<~LONG_COOKED).strip!
long_cooked = (+<<~HTML).strip!
Hello,
<br>
<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.
Vestibulum feugiat mi vitae turpis tempor dignissim.
<br>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end
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
risus.
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.
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
risus.
<br>Nulla ac faucibus quam, quis cursus lorem. Sed rutrum eget nunc sed accumsan.
@ -56,13 +56,13 @@ describe EmailCook do
<br>
<br>Stet clita kasd gubergren.
<br>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end
it "escapes HTML" do
long = plaintext(<<~LONG_EMAIL)
long = plaintext(<<~EMAIL)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<form name="f1" method="post" action="test.html" onsubmit="javascript:showAlert()">
@ -70,9 +70,9 @@ describe EmailCook do
</form>
Nunc convallis volutpat risus.
LONG_EMAIL
EMAIL
long_cooked = (+<<~LONG_COOKED).strip!
long_cooked = (+<<~HTML).strip!
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<br>
<br>&lt;form name=&quot;f1&quot; method=&quot;post&quot; action=&quot;test.html&quot; onsubmit=&quot;javascript:showAlert()&quot;&gt;
@ -81,29 +81,29 @@ describe EmailCook do
<br>
<br>Nunc convallis volutpat risus.
<br>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end
it "replaces indentation of more than 2 spaces with corresponding amount of non-breaking spaces" do
nbsp = "\u00A0"
long = plaintext(<<~LONG_EMAIL)
long = plaintext(<<~EMAIL)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
this is intended by 4 spaces
this is intended by 1 space
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.
<br>
<br>#{nbsp}#{nbsp}#{nbsp}#{nbsp}this is intended by 4 spaces
<br> this is intended by 1 space
<br>no indentation, but lots of spaces
<br>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end
@ -129,7 +129,7 @@ describe EmailCook do
end
it "it works and does not interpret Markdown in plaintext and elided" do
long = <<~LONG_EMAIL
long = <<~EMAIL
[plaintext]
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
[/plaintext]
@ -139,9 +139,9 @@ describe EmailCook do
[elided]
At vero eos *et accusam* et justo duo dolores et ea rebum.
[/elided]
LONG_EMAIL
EMAIL
long_cooked = <<~LONG_COOKED
long_cooked = <<~HTML
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
<br><img src='some_image.png' width='100' height='100'>
<br><br>
@ -152,22 +152,22 @@ describe EmailCook do
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
</details>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end
it "works without attachments" do
long = <<~LONG_EMAIL
long = <<~EMAIL
[plaintext]
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.
[/plaintext]
[elided]
At vero eos *et accusam* et justo duo dolores et ea rebum.
[/elided]
LONG_EMAIL
EMAIL
long_cooked = <<~LONG_COOKED
long_cooked = <<~HTML
*Lorem ipsum* dolor sit amet, consectetur adipiscing elit.<br>
<br><br>
@ -177,7 +177,7 @@ describe EmailCook do
At vero eos *et accusam* et justo duo dolores et ea rebum.<br>
</details>
LONG_COOKED
HTML
expect(cook(long)).to eq(long_cooked)
end

View File

@ -353,7 +353,7 @@ describe PrettyText do
expect(PrettyText.cook("[quote]\ntest")).not_to include('aside')
expect(PrettyText.cook("[quote]\ntest\n[/quote]z")).not_to include('aside')
nested = <<~QUOTE
nested = <<~MD
[quote]
a
[quote]
@ -361,7 +361,7 @@ describe PrettyText do
[/quote]
c
[/quote]
QUOTE
MD
cooked = PrettyText.cook(nested)
expect(cooked.scan('aside').length).to eq(4)
@ -799,9 +799,9 @@ describe PrettyText do
context "emojis" 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\">
EOS
HTML
expect(PrettyText.excerpt(html, 7)).to eq(":bike: &hellip;")
expect(PrettyText.excerpt(html, 8)).to eq(":bike: &hellip;")
expect(PrettyText.excerpt(html, 9)).to eq(":bike: &hellip;")
@ -914,7 +914,7 @@ describe PrettyText do
end
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">
<header class="source">
<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>
</article>
</aside>
EOF
HTML
expect(PrettyText.extract_links(onebox).map(&:url)).to contain_exactly("https://twitter.com/EDBPostgres/status/1402528437441634306")
end
@ -938,12 +938,13 @@ describe PrettyText do
end
it "handles custom bbcode excerpt" do
raw = <<~RAW
raw = <<~MD
[excerpt]
hello [site](https://site.com)
[/excerpt]
more stuff
RAW
MD
post = Fabricate(:post, raw: raw)
expect(post.excerpt).to eq("hello <a href=\"https://site.com\" rel=\"noopener nofollow ugc\">site</a>")
end
@ -1929,17 +1930,17 @@ HTML
it "can properly allowlist iframes" do
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://bob.com/a?testing'></iframe>
<iframe src='HTTP://SILLY.COM?EMBED=111'></iframe>
IFRAMES
HTML
# we require explicit HTTPS here
html = <<~IFRAMES
html = <<~HTML
<iframe src="https://bob.com/a?testing"></iframe>
<iframe src="HTTP://SILLY.COM?EMBED=111"></iframe>
IFRAMES
HTML
cooked = PrettyText.cook(raw).strip

View File

@ -551,9 +551,9 @@ describe Search do
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
TITLE
HTML
end
it "limits the search headline to #{Search::GroupedSearchResults::BLURB_LENGTH} characters" do

View File

@ -76,25 +76,25 @@ describe Discourse::VERSION do
end
context "with a regular compatible list" do
let(:version_list) { <<~VERSION_LIST
let(:version_list) { <<~YML
2.5.0.beta6: twofivebetasix
2.5.0.beta4: twofivebetafour
2.5.0.beta2: twofivebetatwo
2.4.4.beta6: twofourfourbetasix
2.4.2.beta1: twofourtwobetaone
VERSION_LIST
YML
}
include_examples "test compatible resource"
end
context "handle a compatible resource out of order" do
let(:version_list) { <<~VERSION_LIST
let(:version_list) { <<~YML
2.4.2.beta1: twofourtwobetaone
2.5.0.beta4: twofivebetafour
2.5.0.beta6: twofivebetasix
2.5.0.beta2: twofivebetatwo
2.4.4.beta6: twofourfourbetasix
VERSION_LIST
YML
}
include_examples "test compatible resource"
end

View File

@ -28,7 +28,7 @@ describe GroupSmtpMailer do
end
let(:email) do
<<~EOF
<<~EMAIL
Delivered-To: bugs@gmail.com
MIME-Version: 1.0
From: John Doe <john@doe.com>
@ -41,7 +41,7 @@ describe GroupSmtpMailer do
Hello,
How are you doing?
EOF
EMAIL
end
let(:receiver) do

View File

@ -92,10 +92,10 @@ describe ThemeField do
<script>var b = 10</script>
HTML
extracted = <<~JavaScript
extracted = <<~JS
var a = 10
var b = 10
JavaScript
JS
theme_field = ThemeField.create!(theme_id: 1, target_id: 0, name: "header", value: html)
theme_field.ensure_baked!

View File

@ -326,10 +326,10 @@ HTML
expect(scss).to include("font-size:30px")
# Escapes correctly. If not, compiling this would throw an exception
setting.value = <<~MULTILINE
setting.value = <<~CSS
\#{$fakeinterpolatedvariable}
andanothervalue 'withquotes'; margin: 0;
MULTILINE
CSS
theme.set_field(target: :common, name: :scss, value: 'body {font-size: quote($font-size)}')
theme.save!

View File

@ -390,10 +390,10 @@ describe TopicEmbed do
it "handles malformed links" do
url = "https://somesource.com"
contents = <<~CONTENT
contents = <<~HTML
hello world new post <a href="mailto:somemail@somewhere.org>">hello</a>
some image <img src="https:/><invalidimagesrc/">
CONTENT
HTML
raw = TopicEmbed.absolutize_urls(url, contents)
expect(raw).to eq(contents)

View File

@ -454,14 +454,14 @@ RSpec.describe Admin::BackupsController do
BackupRestore::S3BackupStore.any_instance.stubs(:temporary_upload_path).returns(
"temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz"
)
create_multipart_result = <<~BODY
create_multipart_result = <<~XML
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
<InitiateMultipartUploadResult>
<Bucket>s3-backup-bucket</Bucket>
<Key>temp/default/#{test_bucket_prefix}/28fccf8259bbe75b873a2bd2564b778c/2u98j832nx93272x947823.gz</Key>
<UploadId>#{mock_multipart_upload_id}</UploadId>
</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").
to_return(status: 200, body: create_multipart_result)
end

View File

@ -20,7 +20,7 @@ describe 'groups' do
in: :query,
type: :string,
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:
- 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.
@ -44,7 +44,7 @@ describe 'groups' do
curl -i -sS -X GET -G "http://localhost:4200/search.json" \\
--data-urlencode 'q=wordpress @scossar #fun after:2020-01-01'
```
HEREDOC
MD
)
parameter name: :page, in: :query, type: :integer, example: 1

View File

@ -52,7 +52,7 @@ describe 'uploads' do
tags 'Uploads'
operationId 'generatePresignedPut'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
Direct external uploads bypass the usual method of creating uploads
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
@ -66,7 +66,7 @@ describe 'uploads' do
destination in the external storage service.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_generate_presigned_put_request')
parameter name: :params, in: :body, schema: expected_request_schema
@ -108,7 +108,7 @@ describe 'uploads' do
tags 'Uploads'
operationId 'completeExternalUpload'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
Completes an external upload initialized with /get-presigned-put. The
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
@ -119,7 +119,7 @@ describe 'uploads' do
file was uploaded. The file size will be compared for the same reason.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_complete_external_upload_request')
parameter name: :params, in: :body, schema: expected_request_schema
@ -154,12 +154,12 @@ describe 'uploads' do
tags 'Uploads'
operationId 'createMultipartUpload'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
Creates a multipart upload in the external storage provider, storing
a temporary reference to the external upload similar to /get-presigned-put.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_create_multipart_request')
parameter name: :params, in: :body, schema: expected_request_schema
@ -200,7 +200,7 @@ describe 'uploads' do
tags 'Uploads'
operationId 'batchPresignMultipartParts'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
Multipart uploads are uploaded in chunks or parts to individual presigned
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
@ -215,7 +215,7 @@ describe 'uploads' do
because this is needed to complete the multipart upload.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_batch_presign_multipart_parts_request')
parameter name: :params, in: :body, schema: expected_request_schema
@ -255,13 +255,13 @@ describe 'uploads' do
tags 'Uploads'
operationId 'abortMultipart'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
This endpoint aborts the multipart upload initiated with /create-multipart.
This should be used when cancelling the upload. It does not matter if parts
were already uploaded into the external storage provider.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_abort_multipart_request')
parameter name: :params, in: :body, schema: expected_request_schema
@ -299,7 +299,7 @@ describe 'uploads' do
tags 'Uploads'
operationId 'completeMultipart'
consumes 'application/json'
description <<~HEREDOC
description <<~TEXT
Completes the multipart upload in the external store, and copies the
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.
@ -307,7 +307,7 @@ describe 'uploads' do
to its final location.
#{direct_uploads_disclaimer}
HEREDOC
TEXT
expected_request_schema = load_spec_schema('upload_complete_multipart_request')
parameter name: :params, in: :body, schema: expected_request_schema

View File

@ -125,13 +125,13 @@ RSpec.describe MetadataController do
end
it 'returns the right output' do
SiteSetting.app_association_android = <<~EOF
SiteSetting.app_association_android = <<~JSON
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target" : { "namespace": "android_app", "package_name": "com.example.app",
"sha256_cert_fingerprints": ["hash_of_app_certificate"] }
}]
EOF
JSON
get "/.well-known/assetlinks.json"
expect(response.headers["Cache-Control"]).to eq('max-age=60, private')
@ -150,13 +150,13 @@ RSpec.describe MetadataController do
end
it 'returns the right output' do
SiteSetting.app_association_ios = <<~EOF
SiteSetting.app_association_ios = <<~JSON
{
"applinks": {
"apps": []
}
}
EOF
JSON
get "/apple-app-site-association"
expect(response.status).to eq(200)

View File

@ -831,14 +831,14 @@ describe UploadsController do
FileStore::S3Store.any_instance.stubs(:temporary_upload_path).returns(
"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
<InitiateMultipartUploadResult>
<Bucket>s3-upload-bucket</Bucket>
<Key>uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png</Key>
<UploadId>#{mock_multipart_upload_id}</UploadId>
</InitiateMultipartUploadResult>
BODY
XML
stub_request(
:post,
"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
def stub_list_multipart_request
list_multipart_result = <<~BODY
list_multipart_result = <<~XML
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
<ListPartsResult>
<Bucket>s3-upload-bucket</Bucket>
@ -974,7 +974,7 @@ describe UploadsController do
</Owner>
<StorageClass>STANDARD</StorageClass>
</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 })
end
@ -1092,7 +1092,7 @@ describe UploadsController do
end
def stub_list_multipart_request
list_multipart_result = <<~BODY
list_multipart_result = <<~XML
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
<ListPartsResult>
<Bucket>s3-upload-bucket</Bucket>
@ -1118,7 +1118,7 @@ describe UploadsController do
</Owner>
<StorageClass>STANDARD</StorageClass>
</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 })
end

View File

@ -292,14 +292,14 @@ RSpec.describe ExternalUploadManager do
end
def copy_object_result
<<~BODY
<<~XML
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
<CopyObjectResult
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
<LastModified>2021-07-19T04:10:41.000Z</LastModified>
<ETag>&quot;#{etag}&quot;</ETag>
</CopyObjectResult>
BODY
XML
end
def stub_copy_object

View File

@ -175,9 +175,9 @@ describe PostAlerter do
post = Fabricate(:post, topic: pm, user: user1)
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]
STRING
MD
expect {
create_post_with_alerts(
@ -190,9 +190,9 @@ describe PostAlerter do
group.add(admin)
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]
STRING
MD
expect {
create_post_with_alerts(
@ -1566,7 +1566,7 @@ describe PostAlerter do
end
def create_post_with_incoming
raw_mail = <<~MAIL
raw_mail = <<~EMAIL
From: Foo <foo@discourse.org>
To: discourse@example.com
Cc: bar@discourse.org, jim@othersite.com
@ -1578,7 +1578,7 @@ describe PostAlerter do
Content-Transfer-Encoding: 7bit
This is the first email.
MAIL
EMAIL
Email::Receiver.new(raw_mail, {}).process!
end
@ -1716,7 +1716,7 @@ describe PostAlerter do
email = ActionMailer::Base.deliveries.last
# the reply post from someone who was emailed
reply_raw_mail = <<~MAIL
reply_raw_mail = <<~EMAIL
From: Bar <bar@discourse.org>
To: discourse@example.com
Cc: someothernewcc@baz.com, finalnewcc@doom.com
@ -1729,7 +1729,7 @@ describe PostAlerter do
Content-Transfer-Encoding: 7bit
Hey here is my reply!
MAIL
EMAIL
reply_post_from_email = nil
expect {
@ -1767,7 +1767,7 @@ describe PostAlerter do
email = ActionMailer::Base.deliveries.last
# the reply post from someone who was emailed
reply_raw_mail = <<~MAIL
reply_raw_mail = <<~EMAIL
From: Foo <foo@discourse.org>
To: discourse@example.com
Cc: someothernewcc@baz.com, finalnewcc@doom.com
@ -1780,7 +1780,7 @@ describe PostAlerter do
Content-Transfer-Encoding: 7bit
I am ~~Commander Shepherd~~ the OP and I approve of this message.
MAIL
EMAIL
reply_post_from_email = nil
expect {
@ -1811,7 +1811,7 @@ describe PostAlerter do
# this is a special case where we are not CC'ing on the original email,
# only on the follow up email
raw_mail = <<~MAIL
raw_mail = <<~EMAIL
From: Foo <foo@discourse.org>
To: discourse@example.com
Subject: Full email group username flow
@ -1822,7 +1822,7 @@ describe PostAlerter do
Content-Transfer-Encoding: 7bit
This is the first email.
MAIL
EMAIL
incoming_email_post = Email::Receiver.new(raw_mail, {}).process!
topic = incoming_email_post.topic
@ -1833,7 +1833,7 @@ describe PostAlerter do
email = ActionMailer::Base.deliveries.last
# the reply post from the OP, cc'ing new people in
reply_raw_mail = <<~MAIL
reply_raw_mail = <<~EMAIL
From: Foo <foo@discourse.org>
To: discourse@example.com
Cc: someothernewcc@baz.com, finalnewcc@doom.com
@ -1846,7 +1846,7 @@ describe PostAlerter do
Content-Transfer-Encoding: 7bit
I am inviting my mates to this email party.
MAIL
EMAIL
reply_post_from_email = nil
expect {

View File

@ -14,7 +14,7 @@ def load_spec_schema(name)
end
def api_docs_description
<<~HEREDOC
<<~MD
This page contains the documentation on how to use Discourse through API calls.
> 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
`true` or `false` value unless noted otherwise.
HEREDOC
MD
end
def direct_uploads_disclaimer
<<~HEREDOC
<<~MD
You must have the correct permissions and CORS settings configured in your
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
be set to true for this endpoint to function.
HEREDOC
MD
end
RSpec.configure do |config|