docbrown/app/lib/url.rb
Daniel Uber 21e9966ccb
Relax tag validation restriction to permit non-ascii strings (#14710)
* Relax tag validation restriction to permit alphanumeric strings

Non-word symbols like musical notes are still blocked, but most
languages should work.

* Handle redirect after tag edit

The URI.parse(tag.name) was not updated in #13720

Move reused logic into tag_path method in URL module.

* FactoryBot generated tags are non-ascii

This should help expose any cases where we're mistakenly counting on
ascii-only content in tags by causing all generated tags without a
specified name to be of the form `tag你好#{n}` instead of `tag#{n}`.

* Revert "FactoryBot generated tags are non-ascii"

This reverts commit ed1035cd1e91619b2c1599e521b6ddf962c97f80.

It was useful to see how many places the path knowledge is in the
tests (a lot of requests have GET /t/tag.name and need to have GET
URL.tag_path instead).

https://app.travis-ci.com/github/forem/forem/builds/237542600 has the
results.

Reverting because those test-side changes seem like a secondary
concern to the change in this PR (I'll file a follow on issue)
2021-09-14 14:03:54 -05:00

87 lines
2.3 KiB
Ruby

# Utilities methods to safely build app wide URLs
module URL
def self.protocol
ApplicationConfig["APP_PROTOCOL"]
end
def self.domain
if Rails.application&.initialized? && Settings::General.respond_to?(:app_domain)
Settings::General.app_domain
else
ApplicationConfig["APP_DOMAIN"]
end
end
def self.url(uri = nil)
base_url = "#{protocol}#{domain}"
return base_url unless uri
URI.parse(base_url).merge(uri).to_s
end
# Creates an article URL
#
# @param article [Article] the article to create the URL for
def self.article(article)
url(article.path)
end
# Creates a comment URL
#
# @param comment [Comment] the comment to create the URL for
def self.comment(comment)
url(comment.path)
end
# Creates a reaction URL
#
# A reaction URL is the URL of its reactable.
#
# @param reactable [Reaction] the reaction to create the URL for
def self.reaction(reaction)
url(reaction.reactable.path)
end
# Creates a tag URL
#
# @param tag [Tag] the tag to create the URL for
def self.tag(tag, page = 1)
url([tag_path(tag), ("/page/#{page}" if page > 1)].join)
end
def self.tag_path(tag)
"/t/#{CGI.escape(tag.name)}"
end
# Creates a user URL
#
# @param user [User] the user to create the URL for
def self.user(user)
url(user.username)
rescue URI::InvalidURIError # invalid username containing spaces will result in an error
nil
end
# Creates an Image URL - a shortcut for the .image_url helper
#
# @param image_name [String] the image file name
# @param host [String] (optional) the host for the image URL you'd like to use
def self.local_image(image_name, host: nil)
host ||= ActionController::Base.asset_host || url(nil)
ActionController::Base.helpers.image_url(image_name, host: host)
end
# Creates a deep link URL (for mobile) to a page in the current Forem and it
# relies on a UDL server to bounce back mobile users to the local `/r/mobile`
# fallback page. More details here: https://github.com/forem/udl-server
#
# @param path [String] the target path to deep link
def self.deep_link(path)
target_path = CGI.escape(url("/r/mobile?deep_link=#{path}"))
"https://udl.forem.com/?r=#{target_path}"
end
def self.organization(organization)
url(organization.slug)
end
end