Replace base_uri with base_path (#10879)

DEV: Replace instances of Discourse.base_uri with Discourse.base_path

This is clearer because the base_uri is actually just a path prefix. This continues the work started in 555f467.
This commit is contained in:
Daniel Waterworth 2020-10-09 12:51:24 +01:00 committed by GitHub
parent 5e3130ac26
commit 721ee36425
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 74 additions and 70 deletions

View File

@ -329,7 +329,7 @@ class ApplicationController < ActionController::Base
current_user.reload
current_user.publish_notifications_state
cookie_args = {}
cookie_args[:path] = Discourse.base_uri if Discourse.base_uri.present?
cookie_args[:path] = Discourse.base_path if Discourse.base_path.present?
cookies.delete('cn', cookie_args)
end
end

View File

@ -45,7 +45,7 @@ class ExtraLocalesController < ApplicationController
end
def self.url(bundle)
"#{Discourse.base_uri}/extra-locales/#{bundle}?v=#{bundle_js_hash(bundle)}"
"#{Discourse.base_path}/extra-locales/#{bundle}?v=#{bundle_js_hash(bundle)}"
end
def self.client_overrides_exist?

View File

@ -45,8 +45,8 @@ class RobotsTxtController < ApplicationController
end
def self.fetch_default_robots_info
deny_paths = DISALLOWED_PATHS.map { |p| Discourse.base_uri + p }
deny_all = [ "#{Discourse.base_uri}/" ]
deny_paths = DISALLOWED_PATHS.map { |p| Discourse.base_path + p }
deny_all = [ "#{Discourse.base_path}/" ]
result = {
header: "# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file",

View File

@ -478,7 +478,7 @@ class TagsController < ::ApplicationController
permalink = Permalink.find_by_url(url)
if permalink.present? && permalink.category_id
redirect_to "#{Discourse::base_uri}/tags#{permalink.target_url}/#{params[:tag_id]}", status: :moved_permanently
redirect_to "#{Discourse.base_path}/tags#{permalink.target_url}/#{params[:tag_id]}", status: :moved_permanently
else
# redirect to 404
raise Discourse::NotFound

View File

@ -32,7 +32,7 @@ class Users::OmniauthCallbacksController < ApplicationController
# Save to redis, with a secret token, then redirect to confirmation screen
token = SecureRandom.hex
Discourse.redis.setex "#{Users::AssociateAccountsController::REDIS_PREFIX}_#{current_user.id}_#{token}", 10.minutes, auth.to_json
return redirect_to "#{Discourse.base_uri}/associate/#{token}"
return redirect_to "#{Discourse.base_path}/associate/#{token}"
else
@auth_result = authenticator.after_authenticate(auth)
DiscourseEvent.trigger(:after_auth, authenticator, @auth_result)
@ -55,14 +55,14 @@ class Users::OmniauthCallbacksController < ApplicationController
if parsed && # Valid
(parsed.host == nil || parsed.host == Discourse.current_hostname) && # Local
!parsed.path.starts_with?("#{Discourse.base_uri}/auth/") # Not /auth URL
!parsed.path.starts_with?("#{Discourse.base_path}/auth/") # Not /auth URL
@origin = +"#{parsed.path}"
@origin << "?#{parsed.query}" if parsed.query
end
end
if @origin.blank?
@origin = Discourse.base_uri("/")
@origin = Discourse.base_path("/")
end
@auth_result.destination_url = @origin
@ -76,7 +76,7 @@ class Users::OmniauthCallbacksController < ApplicationController
cookies['_bypass_cache'] = true
cookies[:authentication_data] = {
value: @auth_result.to_client_hash.to_json,
path: Discourse.base_uri("/")
path: Discourse.base_path("/")
}
redirect_to @origin
end

View File

@ -300,7 +300,7 @@ module ApplicationHelper
end
def login_path
"#{Discourse::base_uri}/login"
"#{Discourse.base_path}/login"
end
def mobile_view?
@ -488,7 +488,7 @@ module ApplicationHelper
setup_data = {
cdn: Rails.configuration.action_controller.asset_host,
base_url: Discourse.base_url,
base_uri: Discourse::base_uri,
base_uri: Discourse.base_path,
environment: Rails.env,
letter_avatar_version: LetterAvatar.version,
markdown_it_url: script_asset_path('markdown-it-bundle'),

View File

@ -98,11 +98,11 @@ module UserNotificationsHelper
end
def email_image_url(basename)
UrlHelper.absolute("#{Discourse.base_uri}/images/emails/#{basename}")
UrlHelper.absolute("#{Discourse.base_path}/images/emails/#{basename}")
end
def url_for_email(href)
URI(href).host.present? ? href : UrlHelper.absolute("#{Discourse.base_uri}#{href}")
URI(href).host.present? ? href : UrlHelper.absolute("#{Discourse.base_path}#{href}")
rescue URI::Error
href
end

View File

@ -200,7 +200,7 @@ class AdminDashboardData
end
def subfolder_ends_in_slash_check
I18n.t('dashboard.subfolder_ends_in_slash') if Discourse.base_uri =~ /\/$/
I18n.t('dashboard.subfolder_ends_in_slash') if Discourse.base_path =~ /\/$/
end
def pop3_polling_configuration

View File

@ -263,7 +263,7 @@ class Badge < ActiveRecord::Base
def long_description
key = "badges.#{i18n_name}.long_description"
I18n.t(key, default: self[:long_description] || '', base_uri: Discourse.base_uri, max_likes_per_day: SiteSetting.max_likes_per_day)
I18n.t(key, default: self[:long_description] || '', base_uri: Discourse.base_path, max_likes_per_day: SiteSetting.max_likes_per_day)
end
def long_description=(val)
@ -273,7 +273,7 @@ class Badge < ActiveRecord::Base
def description
key = "badges.#{i18n_name}.description"
I18n.t(key, default: self[:description] || '', base_uri: Discourse.base_uri, max_likes_per_day: SiteSetting.max_likes_per_day)
I18n.t(key, default: self[:description] || '', base_uri: Discourse.base_path, max_likes_per_day: SiteSetting.max_likes_per_day)
end
def description=(val)

View File

@ -724,7 +724,7 @@ class Category < ActiveRecord::Base
end
def full_slug(separator = "-")
start_idx = "#{Discourse.base_uri}/c/".size
start_idx = "#{Discourse.base_path}/c/".size
url[start_idx..-1].gsub("/", separator)
end
@ -735,7 +735,7 @@ class Category < ActiveRecord::Base
end
def url
@@url_cache[self.id] ||= "#{Discourse.base_uri}/c/#{slug_path.join('/')}/#{self.id}"
@@url_cache[self.id] ||= "#{Discourse.base_path}/c/#{slug_path.join('/')}/#{self.id}"
end
def url_with_id
@ -756,7 +756,7 @@ class Category < ActiveRecord::Base
def create_category_permalink
old_slug = saved_changes.transform_values(&:first)["slug"]
url = +"#{Discourse.base_uri}/c"
url = +"#{Discourse.base_path}/c"
url << "/#{parent_category.slug_path.join('/')}" if parent_category_id
url << "/#{old_slug}/#{id}"
url = Permalink.normalize_url(url)

View File

@ -73,7 +73,7 @@ class Emoji
def self.url_for(name)
name = name.delete_prefix(':').delete_suffix(':').gsub(/(.+):t([1-6])/, '\1/\2')
"#{Discourse.base_uri}/images/emoji/#{SiteSetting.emoji_set}/#{name}.png?v=#{EMOJI_VERSION}"
"#{Discourse.base_path}/images/emoji/#{SiteSetting.emoji_set}/#{name}.png?v=#{EMOJI_VERSION}"
end
def self.cache_key(name)
@ -115,7 +115,7 @@ class Emoji
emojis.each do |name, url|
result << Emoji.new.tap do |e|
e.name = name
url = (Discourse.base_uri + url) if url[/^\/[^\/]/]
url = (Discourse.base_path + url) if url[/^\/[^\/]/]
e.url = url
e.group = group || DEFAULT_GROUP
end
@ -135,7 +135,7 @@ class Emoji
def self.base_url
db = RailsMultisite::ConnectionManagement.current_db
"#{Discourse.base_uri}/uploads/#{db}/_emoji"
"#{Discourse.base_path}/uploads/#{db}/_emoji"
end
def self.replacement_code(code)

View File

@ -8,7 +8,7 @@ class JavascriptCache < ActiveRecord::Base
before_save :update_digest
def url
"#{GlobalSetting.cdn_url}#{Discourse.base_uri}/theme-javascripts/#{digest}.js?__ws=#{Discourse.current_hostname}"
"#{GlobalSetting.cdn_url}#{Discourse.base_path}/theme-javascripts/#{digest}.js?__ws=#{Discourse.current_hostname}"
end
private

View File

@ -78,7 +78,7 @@ class Permalink < ActiveRecord::Base
def target_url
return external_url if external_url
return "#{Discourse::base_uri}#{post.url}" if post
return "#{Discourse.base_path}#{post.url}" if post
return topic.relative_url if topic
return category.url if category
return tag.full_url if tag

View File

@ -1230,7 +1230,7 @@ class Topic < ActiveRecord::Base
# NOTE: These are probably better off somewhere else.
# Having a model know about URLs seems a bit strange.
def last_post_url
"#{Discourse.base_uri}/t/#{slug}/#{id}/#{posts_count}"
"#{Discourse.base_path}/t/#{slug}/#{id}/#{posts_count}"
end
def self.url(id, slug, post_number = nil)
@ -1244,7 +1244,7 @@ class Topic < ActiveRecord::Base
end
def self.relative_url(id, slug, post_number = nil)
url = +"#{Discourse.base_uri}/t/"
url = +"#{Discourse.base_path}/t/"
url << "#{slug}/" if slug.present?
url << id.to_s
url << "/#{post_number}" if post_number.to_i > 1

View File

@ -826,14 +826,14 @@ class User < ActiveRecord::Base
# TODO it may be worth caching this in a distributed cache, should be benched
if SiteSetting.external_system_avatars_enabled
url = SiteSetting.external_system_avatars_url.dup
url = +"#{Discourse::base_uri}#{url}" unless url =~ /^https?:\/\//
url = +"#{Discourse.base_path}#{url}" unless url =~ /^https?:\/\//
url.gsub! "{color}", letter_avatar_color(normalized_username)
url.gsub! "{username}", UrlHelper.encode_component(username)
url.gsub! "{first_letter}", UrlHelper.encode_component(normalized_username.grapheme_clusters.first)
url.gsub! "{hostname}", Discourse.current_hostname
url
else
"#{Discourse.base_uri}/letter_avatar/#{normalized_username}/{size}/#{LetterAvatar.version}.png"
"#{Discourse.base_path}/letter_avatar/#{normalized_username}/{size}/#{LetterAvatar.version}.png"
end
end

View File

@ -78,7 +78,7 @@ class UserAvatar < ActiveRecord::Base
def self.local_avatar_template(hostname, username, upload_id)
version = self.version(upload_id)
"#{Discourse.base_uri}/user_avatar/#{hostname}/#{username}/{size}/#{version}.png"
"#{Discourse.base_path}/user_avatar/#{hostname}/#{username}/{size}/#{version}.png"
end
def self.external_avatar_url(user_id, upload_id, size)

View File

@ -8,8 +8,8 @@
<%- end %>
<meta name="theme-color" content="#<%= ColorScheme.hex_for_name('header_background', scheme_id) %>">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=yes, viewport-fit=cover">
<%- if Discourse.base_uri.present? %>
<meta name="discourse-base-uri" content="<%= Discourse.base_uri %>">
<%- if Discourse.base_path.present? %>
<meta name="discourse-base-uri" content="<%= Discourse.base_path %>">
<% end %>
<%= canonical_link_tag %>
<%= render_sitelinks_search_tag %>

View File

@ -45,7 +45,7 @@
<%= render_google_tag_manager_head_code %>
<%= render_google_universal_analytics_code %>
<link rel="manifest" href="<%= Discourse.base_uri %>/manifest.webmanifest" crossorigin="use-credentials">
<link rel="manifest" href="<%= Discourse.base_path %>/manifest.webmanifest" crossorigin="use-credentials">
<%- if include_ios_native_app_banner? %>
<meta name="apple-itunes-app" content="app-id=<%= SiteSetting.ios_app_id %><%= ios_app_argument %>">
@ -59,7 +59,7 @@
<%= tag.meta id: 'data-discourse-setup', data: client_side_setup_data %>
<%- if !current_user && (data = cookies.delete(:authentication_data, path: Discourse.base_uri("/"))) %>
<%- if !current_user && (data = cookies.delete(:authentication_data, path: Discourse.base_path("/"))) %>
<meta id="data-authentication" data-authentication-data="<%= data %>">
<%- end %>
</head>

View File

@ -1,5 +1,5 @@
<%= @robots_info[:header] %>
<% if Discourse.base_uri.present? %>
<% if Discourse.base_path.present? %>
# This robots.txt file is not used. Please append the content below in the robots.txt file located at the root
<% end %>
#

View File

@ -5,9 +5,9 @@
# we return the X-Robots-Tag with noindex, nofollow which will ensure
# indexing is minimized and nothing shows up in Google search results
User-agent: googlebot
Allow: <%= Discourse.base_uri + "/" %>
Disallow: <%= Discourse.base_uri + "/uploads/*" %>
Allow: <%= Discourse.base_path + "/" %>
Disallow: <%= Discourse.base_path + "/uploads/*" %>
User-agent: *
Disallow: <%= Discourse.base_uri + "/" %>
Disallow: <%= Discourse.base_path + "/" %>

View File

@ -3,15 +3,15 @@
module ConfigurableUrls
def faq_path
SiteSetting.faq_url.blank? ? "#{Discourse::base_uri}/faq" : SiteSetting.faq_url
SiteSetting.faq_url.blank? ? "#{Discourse.base_path}/faq" : SiteSetting.faq_url
end
def tos_path
SiteSetting.tos_url.blank? ? "#{Discourse::base_uri}/tos" : SiteSetting.tos_url
SiteSetting.tos_url.blank? ? "#{Discourse.base_path}/tos" : SiteSetting.tos_url
end
def privacy_path
SiteSetting.privacy_policy_url.blank? ? "#{Discourse::base_uri}/privacy" : SiteSetting.privacy_policy_url
SiteSetting.privacy_policy_url.blank? ? "#{Discourse.base_path}/privacy" : SiteSetting.privacy_policy_url
end
end

View File

@ -40,7 +40,7 @@ class ContentSecurityPolicy
if can_use_s3_cdn && s3_cdn
s3_cdn + dir
elsif can_use_cdn && cdn
cdn + Discourse.base_uri + dir
cdn + Discourse.base_path + dir
else
base + dir
end

View File

@ -15,7 +15,7 @@ class ContentSecurityPolicy
# The EnforceHostname middleware ensures request.host_with_port can be trusted
protocol = (SiteSetting.force_https || request.ssl?) ? "https://" : "http://"
base_url = protocol + request.host_with_port + Discourse.base_uri
base_url = protocol + request.host_with_port + Discourse.base_path
theme_ids = env[:resolved_theme_ids]

View File

@ -380,10 +380,15 @@ module Discourse
SiteSetting.force_hostname.presence || RailsMultisite::ConnectionManagement.current_hostname
end
def self.base_uri(default_value = "")
def self.base_path(default_value = "")
ActionController::Base.config.relative_url_root.presence || default_value
end
def self.base_uri(default_value = "")
deprecate("Discourse.base_uri is deprecated, use Discourse.base_path instead")
base_path(default_value)
end
def self.base_protocol
SiteSetting.force_https? ? "https" : "http"
end
@ -401,7 +406,7 @@ module Discourse
end
def self.base_url
base_url_no_prefix + base_uri
base_url_no_prefix + base_path
end
def self.route_for(uri)
@ -415,8 +420,8 @@ module Discourse
return unless uri
path = +(uri.path || "")
if !uri.host || (uri.host == Discourse.current_hostname && path.start_with?(Discourse.base_uri))
path.slice!(Discourse.base_uri)
if !uri.host || (uri.host == Discourse.current_hostname && path.start_with?(Discourse.base_path))
path.slice!(Discourse.base_path)
return Rails.application.routes.recognize_path(path)
end
@ -426,7 +431,6 @@ module Discourse
end
class << self
alias_method :base_path, :base_uri
alias_method :base_url_no_path, :base_url_no_prefix
end

View File

@ -8,7 +8,7 @@ module FileStore
def store_file(file, path)
copy_file(file, "#{public_dir}#{path}")
"#{Discourse.base_uri}#{path}"
"#{Discourse.base_path}#{path}"
end
def remove_file(url, _)
@ -36,7 +36,7 @@ module FileStore
end
def relative_base_url
File.join(Discourse.base_uri, upload_path)
File.join(Discourse.base_path, upload_path)
end
def external?

View File

@ -200,7 +200,7 @@ module PrettyText
def self.paths_json
paths = {
baseUri: Discourse::base_uri,
baseUri: Discourse.base_path,
CDN: Rails.configuration.action_controller.asset_host,
}
@ -490,13 +490,13 @@ module PrettyText
case type
when USER_TYPE
element['href'] = "#{Discourse::base_uri}/u/#{UrlHelper.encode_component(name)}"
element['href'] = "#{Discourse.base_path}/u/#{UrlHelper.encode_component(name)}"
when GROUP_MENTIONABLE_TYPE
element['class'] = 'mention-group notify'
element['href'] = "#{Discourse::base_uri}/groups/#{UrlHelper.encode_component(name)}"
element['href'] = "#{Discourse.base_path}/groups/#{UrlHelper.encode_component(name)}"
when GROUP_TYPE
element['class'] = 'mention-group'
element['href'] = "#{Discourse::base_uri}/groups/#{UrlHelper.encode_component(name)}"
element['href'] = "#{Discourse.base_path}/groups/#{UrlHelper.encode_component(name)}"
end
end
end

View File

@ -38,7 +38,7 @@ class UrlHelper
def self.is_local(url)
url.present? && (
Discourse.store.has_been_uploaded?(url) ||
!!(url =~ Regexp.new("^#{Discourse.base_uri}/(assets|plugins|images)/")) ||
!!(url =~ Regexp.new("^#{Discourse.base_path}/(assets|plugins|images)/")) ||
url.start_with?(Discourse.asset_host || Discourse.base_url_no_prefix)
)
end

View File

@ -280,7 +280,7 @@ class Wizard
EmojiSetSiteSetting.values.each do |set|
imgs = emoji.map do |e|
"<img src='#{Discourse.base_uri}/images/emoji/#{set[:value]}/#{e}.png'>"
"<img src='#{Discourse.base_path}/images/emoji/#{set[:value]}/#{e}.png'>"
end
sets.add_choice(set[:value],

View File

@ -184,7 +184,7 @@ module DiscourseNarrativeBot
end
def i18n_post_args(extra = {})
{ base_uri: Discourse.base_uri }.merge(extra)
{ base_uri: Discourse.base_path }.merge(extra)
end
def valid_topic?(topic_id)

View File

@ -11,14 +11,14 @@ module DiscourseNarrativeBot
begin: {
init: {
next_state: :tutorial_bookmark,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.bookmark.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.bookmark.instructions", base_uri: Discourse.base_path) },
action: :say_hello
}
},
tutorial_bookmark: {
next_state: :tutorial_onebox,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.onebox.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.onebox.instructions", base_uri: Discourse.base_path) },
bookmark: {
action: :reply_to_bookmark
@ -32,7 +32,7 @@ module DiscourseNarrativeBot
tutorial_onebox: {
next_state: :tutorial_emoji,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.emoji.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.emoji.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_onebox
@ -45,7 +45,7 @@ module DiscourseNarrativeBot
next_instructions: Proc.new {
I18n.t("#{I18N_KEY}.mention.instructions",
discobot_username: self.discobot_username,
base_uri: Discourse.base_uri)
base_uri: Discourse.base_path)
},
reply: {
action: :reply_to_emoji
@ -55,7 +55,7 @@ module DiscourseNarrativeBot
tutorial_mention: {
prerequisite: Proc.new { SiteSetting.enable_mentions },
next_state: :tutorial_formatting,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.formatting.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.formatting.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_mention
@ -64,7 +64,7 @@ module DiscourseNarrativeBot
tutorial_formatting: {
next_state: :tutorial_quote,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.quoting.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.quoting.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_formatting
@ -73,7 +73,7 @@ module DiscourseNarrativeBot
tutorial_quote: {
next_state: :tutorial_images,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.images.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.images.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_quote
@ -85,7 +85,7 @@ module DiscourseNarrativeBot
tutorial_images: {
prerequisite: Proc.new { @user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
next_state: :tutorial_likes,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.likes.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.likes.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_image
},
@ -101,7 +101,7 @@ module DiscourseNarrativeBot
I18n.t("#{I18N_KEY}.flag.instructions",
guidelines_url: url_helpers(:guidelines_url),
about_url: url_helpers(:about_index_url),
base_uri: Discourse.base_uri)
base_uri: Discourse.base_path)
},
like: {
action: :reply_to_likes
@ -115,7 +115,7 @@ module DiscourseNarrativeBot
tutorial_flag: {
prerequisite: Proc.new { SiteSetting.allow_flagging_staff },
next_state: :tutorial_search,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.search.instructions", base_uri: Discourse.base_uri) },
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.search.instructions", base_uri: Discourse.base_path) },
flag: {
action: :reply_to_flag
},

View File

@ -108,7 +108,7 @@ after_initialize do
private
def fetch_avatar(user)
avatar_url = UrlHelper.absolute(Discourse.base_uri + user.avatar_template.gsub('{size}', '250'))
avatar_url = UrlHelper.absolute(Discourse.base_path + user.avatar_template.gsub('{size}', '250'))
FileHelper.download(
avatar_url.to_s,
max_file_size: SiteSetting.max_image_size_kb.kilobytes,

View File

@ -745,7 +745,7 @@ describe DiscourseNarrativeBot::NewUserNarrative do
it "should use correct path to images on subfolder installs" do
GlobalSetting.stubs(:relative_url_root).returns('/forum')
Discourse.stubs(:base_uri).returns("/forum")
Discourse.stubs(:base_path).returns("/forum")
post.update!(raw: skip_trigger)

View File

@ -69,7 +69,7 @@ describe Oneboxer do
expect(onebox).to include(%{data-post="2"})
expect(onebox).to include(PrettyText.avatar_img(replier.avatar_template, "tiny"))
short_url = "#{Discourse.base_uri}/t/#{public_topic.id}"
short_url = "#{Discourse.base_path}/t/#{public_topic.id}"
expect(preview(short_url, user, public_category)).to include(public_topic.title)
onebox = preview(public_moderator_action.url, user, public_category)

View File

@ -1363,7 +1363,7 @@ describe Post do
fab!(:attachment_upload_2) { Fabricate(:upload) }
fab!(:attachment_upload_3) { Fabricate(:upload, extension: nil) }
let(:base_url) { "#{Discourse.base_url_no_prefix}#{Discourse.base_uri}" }
let(:base_url) { "#{Discourse.base_url_no_prefix}#{Discourse.base_path}" }
let(:video_url) { "#{base_url}#{video_upload.url}" }
let(:audio_url) { "#{base_url}#{audio_upload.url}" }