diff --git a/backend/package-lock.json b/backend/package-lock.json index cf01bd6e..e7f8c0bc 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -34,6 +34,7 @@ "lodash.isequal": "^4.5.0", "lodash.pick": "^4.4.0", "moment-timezone": "^0.5.21", + "multer": "^1.4.3", "mysql": "^2.16.0", "node-fetch": "^2.6.5", "parse-color": "^1.0.0", @@ -65,6 +66,7 @@ "@types/js-yaml": "^3.12.1", "@types/lodash.at": "^4.6.3", "@types/moment-timezone": "^0.5.6", + "@types/multer": "^1.4.7", "@types/node": "^14.0.14", "@types/node-fetch": "^2.5.12", "@types/passport": "^1.0.0", @@ -428,6 +430,15 @@ "moment": ">=2.14.0" } }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "14.0.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz", @@ -631,6 +642,11 @@ "node": ">= 6.0.0" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1310,8 +1326,7 @@ "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "node_modules/bufferutil": { "version": "4.0.3", @@ -1322,6 +1337,39 @@ "node-gyp-build": "^4.2.0" } }, + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/busboy/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/busboy/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/busboy/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "node_modules/bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -1748,6 +1796,20 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "node_modules/concordance": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.0.tgz", @@ -2072,6 +2134,39 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dicer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/dicer/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/dicer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3461,6 +3556,17 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", @@ -3485,6 +3591,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -4869,6 +4993,14 @@ "duplexer": "~0.1.1" } }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -5291,6 +5423,11 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -5940,6 +6077,14 @@ "@babel/runtime-corejs3": "^7.8.3" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -6394,6 +6539,15 @@ "moment": ">=2.14.0" } }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/node": { "version": "14.0.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz", @@ -6570,6 +6724,11 @@ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -7093,8 +7252,7 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "bufferutil": { "version": "4.0.3", @@ -7104,6 +7262,38 @@ "node-gyp-build": "^4.2.0" } }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -7430,6 +7620,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "concordance": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.0.tgz", @@ -7680,6 +7881,38 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8750,6 +8983,14 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", @@ -8768,6 +9009,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -9847,6 +10103,11 @@ "duplexer": "~0.1.1" } }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -10175,6 +10436,11 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -10651,6 +10917,11 @@ "@babel/runtime-corejs3": "^7.8.3" } }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/backend/package.json b/backend/package.json index cded8fd8..d8a01466 100644 --- a/backend/package.json +++ b/backend/package.json @@ -49,6 +49,7 @@ "lodash.isequal": "^4.5.0", "lodash.pick": "^4.4.0", "moment-timezone": "^0.5.21", + "multer": "^1.4.3", "mysql": "^2.16.0", "node-fetch": "^2.6.5", "parse-color": "^1.0.0", @@ -80,6 +81,7 @@ "@types/js-yaml": "^3.12.1", "@types/lodash.at": "^4.6.3", "@types/moment-timezone": "^0.5.6", + "@types/multer": "^1.4.7", "@types/node": "^14.0.14", "@types/node-fetch": "^2.5.12", "@types/passport": "^1.0.0", diff --git a/backend/src/api/auth.ts b/backend/src/api/auth.ts index b59da332..c1d19b09 100644 --- a/backend/src/api/auth.ts +++ b/backend/src/api/auth.ts @@ -81,7 +81,7 @@ export function initAuth(app: express.Express) { passport.use( "api-token", new CustomStrategy(async (req, cb) => { - const apiKey = req.header("X-Api-Key"); + const apiKey = req.header("X-Api-Key") || req.body?.["X-Api-Key"]; if (!apiKey) return cb("API key missing"); const userId = await apiLogins.getUserIdByApiKey(apiKey); diff --git a/backend/src/api/guilds/importExport.ts b/backend/src/api/guilds/importExport.ts index 0da4f1d2..019c5369 100644 --- a/backend/src/api/guilds/importExport.ts +++ b/backend/src/api/guilds/importExport.ts @@ -7,6 +7,7 @@ import { z } from "zod"; import { Case } from "../../data/entities/Case"; import { rateLimit } from "../rateLimits"; import { MINUTES } from "../../utils"; +import moment from "moment-timezone"; const caseHandlingModeSchema = z.union([ z.literal("replace"), @@ -167,7 +168,13 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) { } } while (cases.length === exportBatchSize); - res.json(data); + const filename = `export_${req.params.guildId}_${moment().format("YYYY-MM-DD_HH-mm-ss")}.json`; + const serialized = JSON.stringify(data, null, 2); + + res.setHeader("Content-Disposition", `attachment; filename=${filename}`); + res.setHeader("Content-Type", "application/octet-stream"); + res.setHeader("Content-Length", serialized.length); + res.send(serialized); }, ); diff --git a/backend/src/api/start.ts b/backend/src/api/start.ts index 22fa0368..4dfb9136 100644 --- a/backend/src/api/start.ts +++ b/backend/src/api/start.ts @@ -7,6 +7,7 @@ import { initDocs } from "./docs"; import { initGuildsAPI } from "./guilds/index"; import { clientError, error, notFound } from "./responses"; import { startBackgroundTasks } from "./tasks"; +import multer from "multer"; const app = express(); @@ -20,6 +21,7 @@ app.use( limit: "10mb", }), ); +app.use(multer().none()); initAuth(app); initGuildsAPI(app); diff --git a/dashboard/src/api.ts b/dashboard/src/api.ts index 2a5fa858..f6cfd5e5 100644 --- a/dashboard/src/api.ts +++ b/dashboard/src/api.ts @@ -66,3 +66,31 @@ export function post(resource: string, params: QueryParamObject = {}) { }, }); } + +type FormPostOpts = { + target?: string; +}; + +export function formPost(resource: string, body: Record = {}, opts: FormPostOpts = {}) { + body["X-Api-Key"] = RootStore.state.auth.apiKey; + const form = document.createElement("form"); + form.action = `${apiUrl}/${resource}`; + form.method = "POST"; + form.enctype = "multipart/form-data"; + if (opts.target != null) { + form.target = opts.target; + } + for (const [key, value] of Object.entries(body)) { + const input = document.createElement("input"); + input.type = "hidden"; + input.name = key; + input.value = value; + form.appendChild(input); + } + document.body.appendChild(form); + form.submit(); + + setTimeout(() => { + document.body.removeChild(form); + }, 1); +} diff --git a/dashboard/src/components/dashboard/GuildImportExport.vue b/dashboard/src/components/dashboard/GuildImportExport.vue index a71c287b..1f335199 100644 --- a/dashboard/src/components/dashboard/GuildImportExport.vue +++ b/dashboard/src/components/dashboard/GuildImportExport.vue @@ -7,11 +7,9 @@

Export server data

- - + -

Error: {{ exportError }}

-

Creating export file...

+

Opened data export in new window!

 

Import server data

@@ -41,7 +39,7 @@ import { mapState } from "vuex"; import { ApiPermissions, hasPermission } from "@shared/apiPermissions"; import { AuthState, GuildState } from "../../store/types"; -import { ApiError } from "../../api"; +import { ApiError, formPost } from "../../api"; import moment from "moment"; export default { @@ -81,8 +79,6 @@ export default { importCaseMode: "bumpImportedCases", exporting: false, - exportError: null, - exportData: null, }; }, methods: { @@ -122,37 +118,9 @@ export default { return; } - if (this.exportData) { - return; - } - - this.exportError = null; this.exporting = true; - try { - this.exportData = await this.$store.dispatch("guilds/exportData", { - guildId: this.$route.params.guildId, - }); - } catch (err) { - this.exportError = err.body?.error ?? String(err); - return; - } finally { - this.exporting = false; - } - }, - downloadExportFile() { - if (!this.exportData) { - return; - } - - const dl = document.createElement("a"); - dl.setAttribute("href", `data:application/json,${encodeURIComponent(JSON.stringify(this.exportData, null, 2))}`); - dl.setAttribute("download", `export_${this.$route.params.guildId}_${moment().format("YYYY-MM-DD_HH-mm-ss")}.json`); - dl.style.display = "none"; - - document.body.appendChild(dl); - dl.click(); - document.body.removeChild(dl); + formPost(`guilds/${this.$route.params.guildId}/export`, {}, { target: "_blank" }); }, }, };