mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 14:23:39 +08:00
FEATURE: permalink normalization
Optionally allow admins to apply regex based normalization to permalinks prior to matching. This allows us to drop query string, or cleanly ignore slugs, etc.
This commit is contained in:
parent
d20324ece8
commit
b772d96f7a
|
@ -5,13 +5,74 @@ class Permalink < ActiveRecord::Base
|
|||
|
||||
before_validation :normalize_url
|
||||
|
||||
def normalize_url
|
||||
if self.url
|
||||
self.url = self.url.strip
|
||||
self.url = self.url[1..-1] if url[0,1] == '/'
|
||||
class Normalizer
|
||||
attr_reader :source
|
||||
|
||||
def initialize(source)
|
||||
@source = source
|
||||
if source.present?
|
||||
@rules = source.split("|").map do |rule|
|
||||
parse_rule(rule)
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
def parse_rule(rule)
|
||||
return unless rule =~ /\/.*\//
|
||||
|
||||
escaping = false
|
||||
regex = ""
|
||||
sub = ""
|
||||
c = 0
|
||||
|
||||
rule.chars.each do |l|
|
||||
c += 1 if !escaping && l == "/"
|
||||
escaping = l == "\\"
|
||||
|
||||
if c > 1
|
||||
sub << l
|
||||
else
|
||||
regex << l
|
||||
end
|
||||
end
|
||||
|
||||
if regex.length > 1
|
||||
[Regexp.new(regex[1..-1]), sub[1..-1] || ""] rescue nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def normalize(url)
|
||||
return url unless @rules
|
||||
@rules.each do |(regex,sub)|
|
||||
url = url.sub(regex,sub)
|
||||
end
|
||||
|
||||
url
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.normalize_url(url)
|
||||
if url
|
||||
url = url.strip
|
||||
url = url[1..-1] if url[0,1] == '/'
|
||||
end
|
||||
|
||||
normalizations = SiteSetting.permalink_normalizations
|
||||
|
||||
@normalizer = Normalizer.new(normalizations) unless @normalizer && @normalizer.source == normalizations
|
||||
@normalizer.normalize(url)
|
||||
end
|
||||
|
||||
def self.find_by_url(url)
|
||||
find_by(url: normalize_url(url))
|
||||
end
|
||||
|
||||
def normalize_url
|
||||
self.url = Permalink.normalize_url(url) if url
|
||||
end
|
||||
|
||||
def target_url
|
||||
return external_url if external_url
|
||||
return post.url if post
|
||||
|
|
|
@ -1139,6 +1139,8 @@ en:
|
|||
|
||||
suppress_uncategorized_badge: "Don't show the badge for uncategorized topics in topic lists."
|
||||
|
||||
permalink_normalizations: "Apply the following regex before matching permalinks, for example: /(\\/topic.*)\\?.*/\\1 will strip query strings from topic routes. Format is regex+string use \\1 etc. to access captures"
|
||||
|
||||
global_notice: "Display an URGENT, EMERGENCY global banner notice to all visitors, change to blank to hide it (HTML allowed)."
|
||||
|
||||
disable_edit_notifications: "Disables edit notifications by the system user when 'download_remote_images_to_local' is active."
|
||||
|
|
|
@ -806,6 +806,10 @@ uncategorized:
|
|||
default: 'ascii'
|
||||
enum: 'SlugSetting'
|
||||
|
||||
permalink_normalizations:
|
||||
default: ''
|
||||
type: list
|
||||
|
||||
# Search
|
||||
min_search_term_length:
|
||||
client: true
|
||||
|
|
|
@ -10,6 +10,17 @@ describe PermalinksController do
|
|||
expect(response.status).to eq(301)
|
||||
end
|
||||
|
||||
it "should apply normalizations" do
|
||||
SiteSetting.permalink_normalizations = "/(.*)\\?.*/\\1"
|
||||
|
||||
permalink = Fabricate(:permalink, url: '/topic/bla', external_url: '/topic/100')
|
||||
|
||||
get :show, url: permalink.url, test: "hello"
|
||||
|
||||
expect(response).to redirect_to('/topic/100')
|
||||
expect(response.status).to eq(301)
|
||||
end
|
||||
|
||||
it 'return 404 if permalink record does not exist' do
|
||||
get :show, url: '/not/a/valid/url'
|
||||
expect(response.status).to eq(404)
|
||||
|
|
|
@ -2,6 +2,16 @@ require "spec_helper"
|
|||
|
||||
describe Permalink do
|
||||
|
||||
describe "normalization" do
|
||||
it "correctly normalizes" do
|
||||
normalizer = Permalink::Normalizer.new("/(\\/hello.*)\\?.*/\\1|/(\\/bye.*)\\?.*/\\1")
|
||||
|
||||
expect(normalizer.normalize("/hello?a=1")).to eq("/hello")
|
||||
expect(normalizer.normalize("/bye?test=1")).to eq("/bye")
|
||||
expect(normalizer.normalize("/bla?a=1")).to eq("/bla?a=1")
|
||||
end
|
||||
end
|
||||
|
||||
describe "new record" do
|
||||
it "strips blanks" do
|
||||
permalink = described_class.create(url: " my/old/url ")
|
||||
|
|
Loading…
Reference in New Issue
Block a user