mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 20:01:08 +08:00
FEATURE: add a way to map arbitrary urls to a topic, post, or category. Useful for sites that have migrated to Discourse and want to redirect from their old site to Discourse with 301 redirects.
This commit is contained in:
12
app/controllers/permalinks_controller.rb
Normal file
12
app/controllers/permalinks_controller.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class PermalinksController < ApplicationController
|
||||||
|
skip_before_filter :check_xhr, :preload_json
|
||||||
|
|
||||||
|
def show
|
||||||
|
permalink = Permalink.find_by_url(params[:url])
|
||||||
|
if permalink && permalink.target_url
|
||||||
|
redirect_to permalink.target_url, status: :moved_permanently
|
||||||
|
else
|
||||||
|
raise Discourse::NotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
21
app/models/permalink.rb
Normal file
21
app/models/permalink.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
class Permalink < ActiveRecord::Base
|
||||||
|
belongs_to :topic
|
||||||
|
belongs_to :post
|
||||||
|
belongs_to :category
|
||||||
|
|
||||||
|
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] == '/'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_url
|
||||||
|
return post.url if post
|
||||||
|
return topic.relative_url if topic
|
||||||
|
return category.url if category
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
@ -148,6 +148,10 @@ module Discourse
|
|||||||
require 'auth'
|
require 'auth'
|
||||||
Discourse.activate_plugins! unless Rails.env.test? and ENV['LOAD_PLUGINS'] != "1"
|
Discourse.activate_plugins! unless Rails.env.test? and ENV['LOAD_PLUGINS'] != "1"
|
||||||
|
|
||||||
|
initializer :add_last_routes, :after => :add_routing_paths do |app|
|
||||||
|
app.routes_reloader.paths << File.join(Rails.root, 'config', 'routes_last.rb')
|
||||||
|
end
|
||||||
|
|
||||||
config.after_initialize do
|
config.after_initialize do
|
||||||
# So open id logs somewhere sane
|
# So open id logs somewhere sane
|
||||||
OpenID::Util.logger = Rails.logger
|
OpenID::Util.logger = Rails.logger
|
||||||
|
@ -425,4 +425,5 @@ Discourse::Application.routes.draw do
|
|||||||
# special case for top
|
# special case for top
|
||||||
root to: "list#top", constraints: HomePageConstraint.new("top"), :as => "top_lists"
|
root to: "list#top", constraints: HomePageConstraint.new("top"), :as => "top_lists"
|
||||||
|
|
||||||
|
# See config/routes_last.rb for more
|
||||||
end
|
end
|
||||||
|
10
config/routes_last.rb
Normal file
10
config/routes_last.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# These routes must be loaded after all others.
|
||||||
|
# Routes are loaded in this order:
|
||||||
|
#
|
||||||
|
# 1. config/routes.rb
|
||||||
|
# 2. routes in engines
|
||||||
|
# 3. config/routes_last.rb
|
||||||
|
|
||||||
|
Discourse::Application.routes.draw do
|
||||||
|
get "*url", to: 'permalinks#show'
|
||||||
|
end
|
14
db/migrate/20140828172407_create_permalinks.rb
Normal file
14
db/migrate/20140828172407_create_permalinks.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class CreatePermalinks < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :permalinks do |t|
|
||||||
|
t.string :url, null: false
|
||||||
|
t.integer :topic_id
|
||||||
|
t.integer :post_id
|
||||||
|
t.integer :category_id
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :permalinks, :url
|
||||||
|
end
|
||||||
|
end
|
19
spec/controllers/permalinks_controller_spec.rb
Normal file
19
spec/controllers/permalinks_controller_spec.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe PermalinksController do
|
||||||
|
describe 'show' do
|
||||||
|
it "should redirect to a permalink's target_url with status 301" do
|
||||||
|
permalink = Fabricate(:permalink)
|
||||||
|
Permalink.any_instance.stubs(:target_url).returns('/t/the-topic-slug/42')
|
||||||
|
get :show, url: permalink.url
|
||||||
|
response.should redirect_to('/t/the-topic-slug/42')
|
||||||
|
response.status.should == 301
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'return 404 if permalink record does not exist' do
|
||||||
|
get :show, url: '/not/a/valid/url'
|
||||||
|
response.status.should == 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
3
spec/fabricators/permalink_fabricator.rb
Normal file
3
spec/fabricators/permalink_fabricator.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Fabricator(:permalink) do
|
||||||
|
url { sequence(:url) {|i| "my/#{i}/url" } }
|
||||||
|
end
|
72
spec/models/permalink_spec.rb
Normal file
72
spec/models/permalink_spec.rb
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe Permalink do
|
||||||
|
|
||||||
|
describe "new record" do
|
||||||
|
it "strips blanks" do
|
||||||
|
permalink = described_class.create(url: " my/old/url ")
|
||||||
|
permalink.url.should == "my/old/url"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "removes leading slash" do
|
||||||
|
permalink = described_class.create(url: "/my/old/url")
|
||||||
|
permalink.url.should == "my/old/url"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "target_url" do
|
||||||
|
|
||||||
|
let(:permalink) { Fabricate.build(:permalink) }
|
||||||
|
let(:topic) { Fabricate(:topic) }
|
||||||
|
let(:post) { Fabricate(:post, topic: topic) }
|
||||||
|
let(:category) { Fabricate(:category) }
|
||||||
|
subject(:target_url) { permalink.target_url }
|
||||||
|
|
||||||
|
it "returns a topic url when topic_id is set" do
|
||||||
|
permalink.topic_id = topic.id
|
||||||
|
target_url.should == topic.relative_url
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil when topic_id is set but topic is not found" do
|
||||||
|
permalink.topic_id = 99999
|
||||||
|
target_url.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a post url when post_id is set" do
|
||||||
|
permalink.post_id = post.id
|
||||||
|
target_url.should == post.url
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil when post_id is set but post is not found" do
|
||||||
|
permalink.post_id = 99999
|
||||||
|
target_url.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a post url when post_id and topic_id are both set" do
|
||||||
|
permalink.post_id = post.id
|
||||||
|
permalink.topic_id = topic.id
|
||||||
|
target_url.should == post.url
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a category url when category_id is set" do
|
||||||
|
permalink.category_id = category.id
|
||||||
|
target_url.should == category.url
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil when category_id is set but category is not found" do
|
||||||
|
permalink.category_id = 99999
|
||||||
|
target_url.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a post url when topic_id, post_id, and category_id are all set for some reason" do
|
||||||
|
permalink.post_id = post.id
|
||||||
|
permalink.topic_id = topic.id
|
||||||
|
permalink.category_id = category.id
|
||||||
|
target_url.should == post.url
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil when nothing is set" do
|
||||||
|
target_url.should be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue
Block a user