Accept `exception` in JSON error responses
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 13 Apr 2023 14:44:16 +0000 (16:44 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 14 Apr 2023 11:54:51 +0000 (13:54 +0200)
This is a replacement for the separate file, line, stacktrace and previous
fields and matches the HTML version of these error responses.

ts/WoltLabSuite/Core/Ajax/Data.ts
ts/WoltLabSuite/Core/Ajax/Error.ts
ts/WoltLabSuite/Core/Ajax/Request.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Error.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Request.js

index 4f6100fd87681e19623f31d88ec2a8c7dcf24c11..fbcbfdd568c190e14b62e064c291603a8d5cc866 100644 (file)
@@ -92,6 +92,7 @@ interface PreviousException {
 
 export interface AjaxResponseException extends ResponseData {
   exceptionID?: string;
+  exception?: string | null;
   previous?: PreviousException[];
   file?: string;
   line?: number;
index cad30a89117086a6f20749fe12447f3528704123..16b8352e29b0c236ba7c0464fdc357cc56fc91f5 100644 (file)
@@ -10,6 +10,7 @@
 import { dialogFactory } from "../Component/Dialog";
 import * as Core from "../Core";
 import * as Language from "../Language";
+import { escapeHTML } from "../StringUtil";
 
 type ErrorResponsePrevious = {
   message: string;
@@ -18,6 +19,7 @@ type ErrorResponsePrevious = {
 
 type ErrorResponse = {
   exceptionID?: string;
+  exception?: string | null;
   file?: string;
   line?: number;
   message: string;
@@ -71,7 +73,9 @@ async function getErrorHtml(error: ApiError): Promise<string | HTMLIFrameElement
           details += `<br><p>File:</p><p>${json.file} in line ${json.line}</p>`;
         }
 
-        if (json.stacktrace) {
+        if (json.exception) {
+          details += `<br>Exception: <div style="white-space: pre;">${escapeHTML(json.exception)}</div>`;
+        } else if (json.stacktrace) {
           details += `<br><p>Stacktrace:</p><p>${json.stacktrace}</p>`;
         } else if (json.exceptionID) {
           details += `<br><p>Exception ID: <code>${json.exceptionID}</code></p>`;
index b5cce8b8809c371c4c713e750821553cda42de3b..dc995a2ada338da42e543018e3de4e20a2675e93 100644 (file)
@@ -14,6 +14,7 @@ import * as Core from "../Core";
 import DomChangeListener from "../Dom/Change/Listener";
 import * as Language from "../Language";
 import { dialogFactory } from "../Component/Dialog";
+import { escapeHTML } from "../StringUtil";
 
 let _didInit = false;
 let _ignoreAllErrors = false;
@@ -323,7 +324,9 @@ class AjaxRequest {
         details += `<br><p>File:</p><p>${data.file} in line ${data.line}</p>`;
       }
 
-      if (data.stacktrace) {
+      if (data.exception) {
+        details += `<br>Exception: <div style="white-space: pre;">${escapeHTML(data.exception)}</div>`;
+      } else if (data.stacktrace) {
         details += `<br><p>Stacktrace:</p><p>${data.stacktrace}</p>`;
       } else if (data.exceptionID) {
         details += `<br><p>Exception ID: <code>${data.exceptionID}</code></p>`;
index 0326f26666d6075c8ee2ba41f7f75853278d05bc..ac3b283a2e924761e81e6833834b0dac8c7731f0 100644 (file)
@@ -6,7 +6,7 @@
  * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @since 5.5
  */
-define(["require", "exports", "tslib", "../Component/Dialog", "../Core", "../Language"], function (require, exports, tslib_1, Dialog_1, Core, Language) {
+define(["require", "exports", "tslib", "../Component/Dialog", "../Core", "../Language", "../StringUtil"], function (require, exports, tslib_1, Dialog_1, Core, Language, StringUtil_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.registerGlobalRejectionHandler = exports.InvalidJson = exports.ExpectedJson = exports.StatusNotOk = exports.ConnectionError = exports.ApiError = void 0;
@@ -55,7 +55,10 @@ define(["require", "exports", "tslib", "../Component/Dialog", "../Core", "../Lan
                     if (json.file && json.line) {
                         details += `<br><p>File:</p><p>${json.file} in line ${json.line}</p>`;
                     }
-                    if (json.stacktrace) {
+                    if (json.exception) {
+                        details += `<br>Exception: <div style="white-space: pre;">${(0, StringUtil_1.escapeHTML)(json.exception)}</div>`;
+                    }
+                    else if (json.stacktrace) {
                         details += `<br><p>Stacktrace:</p><p>${json.stacktrace}</p>`;
                     }
                     else if (json.exceptionID) {
index 15b75b91b4dbf5180bf5b2b9f54a17b0a01b1f91..a149f8403ce54b4807dcbbfd282a5d3f48314d85 100644 (file)
@@ -7,7 +7,7 @@
  * @copyright  2001-2019 WoltLab GmbH
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
-define(["require", "exports", "tslib", "./Status", "../Core", "../Dom/Change/Listener", "../Language", "../Component/Dialog"], function (require, exports, tslib_1, AjaxStatus, Core, Listener_1, Language, Dialog_1) {
+define(["require", "exports", "tslib", "./Status", "../Core", "../Dom/Change/Listener", "../Language", "../Component/Dialog", "../StringUtil"], function (require, exports, tslib_1, AjaxStatus, Core, Listener_1, Language, Dialog_1, StringUtil_1) {
     "use strict";
     AjaxStatus = tslib_1.__importStar(AjaxStatus);
     Core = tslib_1.__importStar(Core);
@@ -276,7 +276,10 @@ define(["require", "exports", "tslib", "./Status", "../Core", "../Dom/Change/Lis
                 if (data.file && data.line) {
                     details += `<br><p>File:</p><p>${data.file} in line ${data.line}</p>`;
                 }
-                if (data.stacktrace) {
+                if (data.exception) {
+                    details += `<br>Exception: <div style="white-space: pre;">${(0, StringUtil_1.escapeHTML)(data.exception)}</div>`;
+                }
+                else if (data.stacktrace) {
                     details += `<br><p>Stacktrace:</p><p>${data.stacktrace}</p>`;
                 }
                 else if (data.exceptionID) {