diff --git a/app/assets/javascripts/discourse/lib/url.js b/app/assets/javascripts/discourse/lib/url.js index 7892abafd9c..a475c4aec37 100644 --- a/app/assets/javascripts/discourse/lib/url.js +++ b/app/assets/javascripts/discourse/lib/url.js @@ -24,7 +24,6 @@ const SERVER_SIDE_ONLY = [ /^\/posts\/\d+\/raw/, /^\/raw\/\d+/, /^\/wizard/, - /^\/go\//, // EXPERIMENTAL: https://meta.discourse.org/t/-/142605 /\.rss$/, /\.json$/, /^\/admin\/upgrade$/, diff --git a/app/assets/javascripts/discourse/routes/unknown.js b/app/assets/javascripts/discourse/routes/unknown.js index 3df278df6fe..28cba698d00 100644 --- a/app/assets/javascripts/discourse/routes/unknown.js +++ b/app/assets/javascripts/discourse/routes/unknown.js @@ -1,8 +1,22 @@ -import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; +import DiscourseURL from "discourse/lib/url"; +import DiscourseRoute from "discourse/routes/discourse"; export default DiscourseRoute.extend({ - model() { - return ajax("/404-body", { dataType: "html" }); + model(params, transition) { + const path = params.path; + return ajax("/permalink-check.json", { + data: { path } + }).then(results => { + if (results.found) { + // Avoid polluting the history stack for external links + transition.abort(); + DiscourseURL.routeTo(results.target_url); + return ""; + } else { + // 404 body HTML + return results.html; + } + }); } }); diff --git a/app/controllers/permalinks_controller.rb b/app/controllers/permalinks_controller.rb index 260979614e2..33f8d04c406 100644 --- a/app/controllers/permalinks_controller.rb +++ b/app/controllers/permalinks_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class PermalinksController < ApplicationController - skip_before_action :check_xhr, :preload_json + skip_before_action :check_xhr, :preload_json, only: [:show] def show url = request.fullpath @@ -17,4 +17,28 @@ class PermalinksController < ApplicationController end end + def check + begin + raise Discourse::NotFound if params[:path].blank? + + permalink = Permalink.find_by_url(params[:path]) + + raise Discourse::NotFound unless permalink + + data = { + found: true, + internal: permalink.external_url.nil?, + target_url: permalink.target_url, + } + + render json: MultiJson.dump(data) + rescue Discourse::NotFound + data = { + found: false, + html: build_not_found_page(status: 200), + } + render json: MultiJson.dump(data) + end + end + end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 27d207efb74..4382448fea5 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4578,7 +4578,7 @@ en: permalink: title: "Permalinks" - description: "Please note this only applies to external sources, links posted on your forum will not be redirected." + description: "Redirections to apply for URLs not known by the forum." url: "URL" topic_id: "Topic ID" topic_title: "Topic" diff --git a/config/routes.rb b/config/routes.rb index 7cde4b038e1..8306dcc40ac 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -954,6 +954,8 @@ Discourse::Application.routes.draw do resources :csp_reports, only: [:create] + get "/permalink-check", to: 'permalinks#check' + get "*url", to: 'permalinks#show', constraints: PermalinkConstraint.new end end diff --git a/test/javascripts/acceptance/unknown-test.js.es6 b/test/javascripts/acceptance/unknown-test.js.es6 index 3283d362ee1..abc4b0d9557 100644 --- a/test/javascripts/acceptance/unknown-test.js.es6 +++ b/test/javascripts/acceptance/unknown-test.js.es6 @@ -1,8 +1,49 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Unknown"); -QUnit.test("Unknown URL", async assert => { - assert.expect(1); +QUnit.test("Permalink Unknown URL", async assert => { await visit("/url-that-doesn't-exist"); assert.ok(exists(".page-not-found"), "The not found content is present"); }); + +QUnit.test("Permalink URL to a Topic", async assert => { + pretender.get("/permalink-check.json", () => { + return [ + 200, + { "Content-Type": "application/json" }, + { + found: true, + internal: true, + target_url: "/t/internationalization-localization/280" + } + ]; + }); + + await visit("/viewtopic.php?f=8&t=280"); + assert.ok(exists(".topic-post")); +}); + +QUnit.test("Permalink URL to a static page", async assert => { + pretender.get("/permalink-check.json", () => { + return [ + 200, + { "Content-Type": "application/json" }, + { + found: true, + internal: true, + target_url: "/faq" + } + ]; + }); + + await visit("/not-the-url-for-faq"); + + // body is outside of #ember-testing-container and needs to be targeted + // through document instead of find + assert.ok( + document.querySelector("body.static-faq"), + "routed to the faq page" + ); + assert.ok(exists(".body-page")); +}); diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index 934b6a652b2..d5e92e55ed5 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -267,12 +267,11 @@ export function applyDefaultHandlers(pretender) { pretender.put("/t/:id/recover", success); pretender.put("/t/:id/publish", success); - pretender.get("/404-body", () => { - return [ - 200, - { "Content-Type": "text/html" }, - "