FEATURE: Add site setting to show more detailed 404 errors. (#8014)

FEATURE: Add site setting to show more detailed 404 errors. (#8014)

If the setting is turned on, then the user will receive information about the subject: if it was deleted or requires some special access to a group (only if the group is public). Otherwise, the user will receive a generic #404 error message. For now, this change affects only the topics and categories controller.

This commit also tries to refactor some of the code related to error handling. To make error pages more consistent (design-wise), the actual error page will be rendered server-side.

diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index ce14d29..f459e4b 100644
--- a/app/assets/javascripts/discourse/controllers/topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic.js.es6
@@ -945,46 +945,6 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
       }
     },
 
-    joinGroup() {
-      const groupId = this.get("model.group.id");
-      if (groupId) {
-        if (this.get("model.group.allow_membership_requests")) {
-          const groupName = this.get("model.group.name");
-          return ajax(`/groups/${groupName}/request_membership`, {
-            type: "POST",
-            data: {
-              topic_id: this.get("model.id")
-            }
-          })
-            .then(() => {
-              bootbox.alert(
-                I18n.t("topic.group_request_sent", {
-                  group_name: this.get("model.group.full_name")
-                }),
-                () =>
-                  this.previousURL
-                    ? DiscourseURL.routeTo(this.previousURL)
-                    : DiscourseURL.routeTo("/")
-              );
-            })
-            .catch(popupAjaxError);
-        } else {
-          const topic = this.model;
-          return ajax(`/groups/${groupId}/members`, {
-            type: "PUT",
-            data: { user_id: this.get("currentUser.id") }
-          })
-            .then(() =>
-              topic.reload().then(() => {
-                topic.set("view_hidden", false);
-                topic.postStream.refresh();
-              })
-            )
-            .catch(popupAjaxError);
-        }
-      }
-    },
-
     replyAsNewTopic(post, quotedText) {
       const composerController = this.composer;
 
@@ -1182,7 +1142,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
     }
   },
 
-  hasError: Ember.computed.or("model.notFoundHtml", "model.message"),
+  hasError: Ember.computed.or("model.errorHtml", "model.errorMessage"),
   noErrorYet: Ember.computed.not("hasError"),
 
   categories: Ember.computed.alias("site.categoriesList"),
diff --git a/app/assets/javascripts/discourse/models/post-stream.js.es6 b/app/assets/javascripts/discourse/models/post-stream.js.es6
index 346226b..a3b42bc 100644
--- a/app/assets/javascripts/discourse/models/post-stream.js.es6
+++ b/app/assets/javascripts/discourse/models/post-stream.js.es6
@@ -1067,31 +1067,16 @@ export default RestModel.extend({
   // Handles an error loading a topic based on a HTTP status code. Updates
   // the text to the correct values.
   errorLoading(result) {
-    const status = result.jqXHR.status;
-
     const topic = this.topic;
     this.set("loadingFilter", false);
     topic.set("errorLoading", true);
 
-    // If the result was 404 the post is not found
-    // If it was 410 the post is deleted and the user should not see it
-    if (status === 404 || status === 410) {
-      topic.set("notFoundHtml", result.jqXHR.responseText);
-      return;
-    }
-
-    // If the result is 403 it means invalid access
-    if (status === 403) {
-      topic.set("noRetry", true);
-      if (Discourse.User.current()) {
-        topic.set("message", I18n.t("topic.invalid_access.description"));
-      } else {
-        topic.set("message", I18n.t("topic.invalid_access.login_required"));
-      }
-      return;
+    const json = result.jqXHR.responseJSON;
+    if (json && json.extras && json.extras.html) {
+      topic.set("errorHtml", json.extras.html);
+    } else {
+      topic.set("errorMessage", I18n.t("topic.server_error.description"));
+      topic.set("noRetry", result.jqXHR.status === 403);
     }
-
-    // Otherwise supply a generic error message
-    topic.set("message", I18n.t("topic.server_error.description"));
   }
 });
diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6
index d44afe9..1af3697 100644
--- a/app/assets/javascripts/discourse/models/topic.js.es6
+++ b/app/assets/javascripts/discourse/models/topic.js.es6
@@ -17,16 +17,15 @@ import {
 } from "ember-addons/ember-computed-decorators";
 
 export function loadTopicView(topic, args) {
-  const topicId = topic.get("id");
   const data = _.merge({}, args);
-  const url = `${Discourse.getURL("/t/")}${topicId}`;
+  const url = `${Discourse.getURL("/t/")}${topic.id}`;
   const jsonUrl = (data.nearPost ? `${url}/${data.nearPost}` : url) + ".json";
 
   delete data.nearPost;
   delete data.__type;
   delete data.store;
 
-  return PreloadStore.getAndRemove(`topic_${topicId}`, () =>
+  return PreloadStore.getAndRemove(`topic_${topic.id}`, () =>
     ajax(jsonUrl, { data })
   ).then(json => {
     topic.updateFromJson(json);
diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6
index c1db98d..aadf72e 100644
--- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6
@@ -198,6 +198,18 @@ export default (filterArg, params) => {
     },
 
     actions: {
+      error(err) {
+        const json = err.jqXHR.responseJSON;
+        if (json && json.extras && json.extras.html) {
+          this.controllerFor("discovery").set(
+            "errorHtml",
+            err.jqXHR.responseJSON.extras.html
+          );
+        } else {
+          this.replaceWith("exception");
+        }
+      },
+
       setNotification(notification_level) {
         this.currentModel.setNotification(notification_level);
       },
diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs
index c6242e9..6801ab3 100644
--- a/app/assets/javascripts/discourse/templates/discovery.hbs
+++ b/app/assets/javascripts/discourse/templates/discovery.hbs
@@ -1,32 +1,36 @@
-<div class="container">
-  {{discourse-banner user=currentUser banner=site.banner}}
-</div>
-
-<div class="list-controls">
+{{#if errorHtml}}
+  {{{errorHtml}}}
+{{else}}
   <div class="container">
-    {{outlet "navigation-bar"}}
+    {{discourse-banner user=currentUser banner=site.banner}}
   </div>
-</div>
 
-{{conditional-loading-spinner condition=loading}}
+  <div class="list-controls">
+    <div class="container">
+      {{outlet "navigation-bar"}}
+    </div>
+  </div>
 
-<div class="container list-container {{if loading "hidden"}}">
-  <div class="row">
-    <div class="full-width">
-      <div id="header-list-area">
-        {{outlet "header-list-container"}}
+  {{conditional-loading-spinner condition=loading}}
+
+  <div class="container list-container {{if loading "hidden"}}">
+    <div class="row">
+      <div class="full-width">
+        <div id="header-list-area">
+          {{outlet "header-list-container"}}
+        </div>
       </div>
     </div>
-  </div>
-  <div class="row">
-    <div class="full-width">
-      <div id="list-area">
-        {{plugin-outlet name="discovery-list-container-top"
-                        args=(hash category=category listLoading=loading)}}
-        {{outlet "list-container"}}
+    <div class="row">
+      <div class="full-width">
+        <div id="list-area">
+          {{plugin-outlet name="discovery-list-container-top"
+                          args=(hash category=category listLoading=loading)}}
+          {{outlet "list-container"}}
+        </div>
       </div>
     </div>
   </div>
-</div>
 
-{{plugin-outlet name="discovery-below"}}
+  {{plugin-outlet name="discovery-below"}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index 07691df..9d77e4a 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -1,133 +1,102 @@
 {{#discourse-topic multiSelect=multiSelect enteredAt=enteredAt topic=model hasScrolled=hasScrolled}}
-  {{#if model.view_hidden}}

[... diff too long, it was truncated ...]

GitHub sha: fdb1d340

This commit has been mentioned on Discourse Meta. There might be relevant details there: