diff --git a/CTFd/themes/admin/assets/css/admin.scss b/CTFd/themes/admin/assets/css/admin.scss index 910bdb91..a30273e0 100644 --- a/CTFd/themes/admin/assets/css/admin.scss +++ b/CTFd/themes/admin/assets/css/admin.scss @@ -66,3 +66,11 @@ tbody tr:hover { tr[data-href] { cursor: pointer; } + +.sort-col { + cursor: pointer; +} + +input[type="checkbox"] { + cursor: pointer; +} diff --git a/CTFd/themes/admin/assets/js/pages/challenges.js b/CTFd/themes/admin/assets/js/pages/challenges.js index e69de29b..bb1ae451 100644 --- a/CTFd/themes/admin/assets/js/pages/challenges.js +++ b/CTFd/themes/admin/assets/js/pages/challenges.js @@ -0,0 +1,80 @@ +import "./main"; +import CTFd from "core/CTFd"; +import $ from "jquery"; +import { ezAlert, ezQuery } from "core/ezq"; + +function deleteSelectedChallenges(event) { + let challengeIDs = $("input[data-challenge-id]:checked").map(function() { + return $(this).data("challenge-id"); + }); + let target = challengeIDs.length === 1 ? "challenge" : "challenges"; + + ezQuery({ + title: "Delete Challenges", + body: `Are you sure you want to delete ${challengeIDs.length} ${target}?`, + success: function() { + const reqs = []; + for (var chalID of challengeIDs) { + reqs.push( + CTFd.fetch(`/api/v1/challenges/${chalID}`, { + method: "DELETE" + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +function bulkEditChallenges(event) { + let challengeIDs = $("input[data-challenge-id]:checked").map(function() { + return $(this).data("challenge-id"); + }); + + ezAlert({ + title: "Edit Challenges", + body: $(` +
+
+ + +
+
+ + +
+
+ + +
+
+ `), + button: "Submit", + success: function() { + let data = $("#challenges-bulk-edit").serializeJSON(true); + const reqs = []; + for (var chalID of challengeIDs) { + reqs.push( + CTFd.fetch(`/api/v1/challenges/${chalID}`, { + method: "PATCH", + body: JSON.stringify(data) + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +$(() => { + $("#challenges-delete-button").click(deleteSelectedChallenges); + $("#challenges-edit-button").click(bulkEditChallenges); +}); diff --git a/CTFd/themes/admin/assets/js/pages/pages.js b/CTFd/themes/admin/assets/js/pages/pages.js index de5f81c8..4b6eab85 100644 --- a/CTFd/themes/admin/assets/js/pages/pages.js +++ b/CTFd/themes/admin/assets/js/pages/pages.js @@ -1,37 +1,33 @@ import "./main"; import CTFd from "core/CTFd"; import $ from "jquery"; -import { htmlEntities } from "core/utils"; import { ezQuery } from "core/ezq"; -function deletePage(event) { - const elem = $(this); - const name = elem.attr("page-route"); - const page_id = elem.attr("page-id"); +function deleteSelectedUsers(event) { + let pageIDs = $("input[data-page-id]:checked").map(function() { + return $(this).data("page-id"); + }); + let target = pageIDs.length === 1 ? "page" : "pages"; + ezQuery({ - title: "Delete " + htmlEntities(name), - body: "Are you sure you want to delete {0}?".format( - "" + htmlEntities(name) + "" - ), + title: "Delete Pages", + body: `Are you sure you want to delete ${pageIDs.length} ${target}?`, success: function() { - CTFd.fetch("/api/v1/pages/" + page_id, { - method: "DELETE" - }) - .then(function(response) { - return response.json(); - }) - .then(function(response) { - if (response.success) { - elem - .parent() - .parent() - .remove(); - } - }); + const reqs = []; + for (var pageID of pageIDs) { + reqs.push( + CTFd.fetch(`/api/v1/pages/${pageID}`, { + method: "DELETE" + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); } }); } $(() => { - $(".delete-page").click(deletePage); + $("#pages-delete-button").click(deleteSelectedUsers); }); diff --git a/CTFd/themes/admin/assets/js/pages/scoreboard.js b/CTFd/themes/admin/assets/js/pages/scoreboard.js index 3eab3284..436523b0 100644 --- a/CTFd/themes/admin/assets/js/pages/scoreboard.js +++ b/CTFd/themes/admin/assets/js/pages/scoreboard.js @@ -1,6 +1,7 @@ import "./main"; import CTFd from "core/CTFd"; import $ from "jquery"; +import { ezAlert, ezQuery } from "core/ezq"; const api_func = { users: (x, y) => CTFd.api.patch_user_public({ userId: x }, y), @@ -37,6 +38,48 @@ function toggleAccount() { }); } +function toggleSelectedAccounts(accountIDs, action) { + const params = { + hidden: action === "hidden" ? true : false + }; + const reqs = []; + for (var accId of accountIDs) { + reqs.push(api_func[CTFd.config.userMode](accId, params)); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); +} + +function bulkToggleAccounts(event) { + let accountIDs = $("input[data-account-id]:checked").map(function() { + return $(this).data("account-id"); + }); + + ezAlert({ + title: "Toggle Visibility", + body: $(` +
+
+ + +
+
+ `), + button: "Submit", + success: function() { + let data = $("#scoreboard-bulk-edit").serializeJSON(true); + let state = data.visibility; + toggleSelectedAccounts(accountIDs, state); + } + }); +} + $(() => { $(".scoreboard-toggle").click(toggleAccount); + $("#scoreboard-edit-button").click(bulkToggleAccounts); }); diff --git a/CTFd/themes/admin/assets/js/pages/submissions.js b/CTFd/themes/admin/assets/js/pages/submissions.js index 3f34ddad..82c6fb3f 100644 --- a/CTFd/themes/admin/assets/js/pages/submissions.js +++ b/CTFd/themes/admin/assets/js/pages/submissions.js @@ -40,6 +40,28 @@ function deleteCorrectSubmission(event) { }); } +function deleteSelectedSubmissions(event) { + let submissionIDs = $("input[data-submission-id]:checked").map(function() { + return $(this).data("submission-id"); + }); + let target = submissionIDs.length === 1 ? "submission" : "submissions"; + + ezQuery({ + title: "Delete Submissions", + body: `Are you sure you want to delete ${submissionIDs.length} ${target}?`, + success: function() { + const reqs = []; + for (var subId of submissionIDs) { + reqs.push(CTFd.api.delete_submission({ submissionId: subId })); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + $(() => { $(".delete-correct-submission").click(deleteCorrectSubmission); + $("#submission-delete-button").click(deleteSelectedSubmissions); }); diff --git a/CTFd/themes/admin/assets/js/pages/teams.js b/CTFd/themes/admin/assets/js/pages/teams.js index e69de29b..2a5e1fb4 100644 --- a/CTFd/themes/admin/assets/js/pages/teams.js +++ b/CTFd/themes/admin/assets/js/pages/teams.js @@ -0,0 +1,80 @@ +import "./main"; +import CTFd from "core/CTFd"; +import $ from "jquery"; +import { ezAlert, ezQuery } from "core/ezq"; + +function deleteSelectedTeams(event) { + let teamIDs = $("input[data-team-id]:checked").map(function() { + return $(this).data("team-id"); + }); + let target = teamIDs.length === 1 ? "team" : "teams"; + + ezQuery({ + title: "Delete Teams", + body: `Are you sure you want to delete ${teamIDs.length} ${target}?`, + success: function() { + const reqs = []; + for (var teamID of teamIDs) { + reqs.push( + CTFd.fetch(`/api/v1/teams/${teamID}`, { + method: "DELETE" + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +function bulkEditTeams(event) { + let teamIDs = $("input[data-team-id]:checked").map(function() { + return $(this).data("team-id"); + }); + + ezAlert({ + title: "Edit Teams", + body: $(` +
+
+ + +
+
+ + +
+
+ `), + button: "Submit", + success: function() { + let data = $("#teams-bulk-edit").serializeJSON(true); + const reqs = []; + for (var teamID of teamIDs) { + reqs.push( + CTFd.fetch(`/api/v1/teams/${teamID}`, { + method: "PATCH", + body: JSON.stringify(data) + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +$(() => { + $("#teams-delete-button").click(deleteSelectedTeams); + $("#teams-edit-button").click(bulkEditTeams); +}); diff --git a/CTFd/themes/admin/assets/js/pages/users.js b/CTFd/themes/admin/assets/js/pages/users.js index 09198c2b..47dea5a0 100644 --- a/CTFd/themes/admin/assets/js/pages/users.js +++ b/CTFd/themes/admin/assets/js/pages/users.js @@ -1 +1,88 @@ import "./main"; +import CTFd from "core/CTFd"; +import $ from "jquery"; +import { ezAlert, ezQuery } from "core/ezq"; + +function deleteSelectedUsers(event) { + let userIDs = $("input[data-user-id]:checked").map(function() { + return $(this).data("user-id"); + }); + let target = userIDs.length === 1 ? "user" : "users"; + + ezQuery({ + title: "Delete Users", + body: `Are you sure you want to delete ${userIDs.length} ${target}?`, + success: function() { + const reqs = []; + for (var userID of userIDs) { + reqs.push( + CTFd.fetch(`/api/v1/users/${userID}`, { + method: "DELETE" + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +function bulkEditUsers(event) { + let userIDs = $("input[data-user-id]:checked").map(function() { + return $(this).data("user-id"); + }); + + ezAlert({ + title: "Edit Users", + body: $(` +
+
+ + +
+
+ + +
+
+ + +
+
+ `), + button: "Submit", + success: function() { + let data = $("#users-bulk-edit").serializeJSON(true); + const reqs = []; + for (var userID of userIDs) { + reqs.push( + CTFd.fetch(`/api/v1/users/${userID}`, { + method: "PATCH", + body: JSON.stringify(data) + }) + ); + } + Promise.all(reqs).then(responses => { + window.location.reload(); + }); + } + }); +} + +$(() => { + $("#users-delete-button").click(deleteSelectedUsers); + $("#users-edit-button").click(bulkEditUsers); +}); diff --git a/CTFd/themes/admin/assets/js/styles.js b/CTFd/themes/admin/assets/js/styles.js index 7f5e3321..ee3ad6f3 100644 --- a/CTFd/themes/admin/assets/js/styles.js +++ b/CTFd/themes/admin/assets/js/styles.js @@ -1,4 +1,5 @@ import "bootstrap/dist/js/bootstrap.bundle"; +import { makeSortableTables } from "core/utils"; import $ from "jquery"; export default () => { @@ -45,6 +46,27 @@ export default () => { return false; }); + $("[data-checkbox]").click(function(e) { + if ($(e.target).is("input[type=checkbox]")) { + e.stopImmediatePropagation(); + return; + } + let checkbox = $(this).find("input[type=checkbox]"); + // Doing it this way with an event allows data-checkbox-all to work + checkbox.click(); + e.stopImmediatePropagation(); + }); + + $("[data-checkbox-all]").on("click change", function(e) { + const checked = $(this).prop("checked"); + const idx = $(this).index() + 1; + $(this) + .closest("table") + .find(`tr td:nth-child(${idx}) input[type=checkbox]`) + .prop("checked", checked); + e.stopImmediatePropagation(); + }); + $("tr[data-href] a, tr[data-href] button").click(function(e) { // TODO: This is a hack to allow modal close buttons to work if (!$(this).attr("data-dismiss")) { @@ -52,6 +74,7 @@ export default () => { } }); + makeSortableTables(); $('[data-toggle="tooltip"]').tooltip(); }); }; diff --git a/CTFd/themes/admin/static/css/admin.dev.css b/CTFd/themes/admin/static/css/admin.dev.css index b6e34eaf..e015e2d3 100644 --- a/CTFd/themes/admin/static/css/admin.dev.css +++ b/CTFd/themes/admin/static/css/admin.dev.css @@ -1,4 +1,4 @@ html{position:relative;min-height:100%}body{margin-bottom:60px}.footer{position:absolute;bottom:1px;width:100%;height:60px;line-height:normal !important;z-index:-20} -#score-graph{height:450px;display:block;clear:both}#solves-graph{display:block;height:350px}#keys-pie-graph{height:400px;display:block}#categories-pie-graph{height:400px;display:block}#solve-percentages-graph{height:400px;display:block}.no-decoration{color:inherit !important;text-decoration:none !important}.no-decoration:hover{color:inherit !important;text-decoration:none !important}.table td,.table th{vertical-align:inherit}pre{white-space:pre-wrap;margin:0;padding:0}.form-control{position:relative;display:block;border-radius:0;font-weight:400;font-family:"Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;-webkit-appearance:none}tbody tr:hover{background-color:rgba(0,0,0,0.1) !important}tr[data-href]{cursor:pointer} +#score-graph{height:450px;display:block;clear:both}#solves-graph{display:block;height:350px}#keys-pie-graph{height:400px;display:block}#categories-pie-graph{height:400px;display:block}#solve-percentages-graph{height:400px;display:block}.no-decoration{color:inherit !important;text-decoration:none !important}.no-decoration:hover{color:inherit !important;text-decoration:none !important}.table td,.table th{vertical-align:inherit}pre{white-space:pre-wrap;margin:0;padding:0}.form-control{position:relative;display:block;border-radius:0;font-weight:400;font-family:"Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;-webkit-appearance:none}tbody tr:hover{background-color:rgba(0,0,0,0.1) !important}tr[data-href]{cursor:pointer}.sort-col{cursor:pointer}input[type="checkbox"]{cursor:pointer} diff --git a/CTFd/themes/admin/static/css/admin.min.css b/CTFd/themes/admin/static/css/admin.min.css index d207c511..75edc2ee 100644 --- a/CTFd/themes/admin/static/css/admin.min.css +++ b/CTFd/themes/admin/static/css/admin.min.css @@ -1 +1 @@ -html{position:relative;min-height:100%}body{margin-bottom:60px}.footer{position:absolute;bottom:1px;width:100%;height:60px;line-height:normal!important;z-index:-20}#score-graph{height:450px;display:block;clear:both}#solves-graph{display:block;height:350px}#categories-pie-graph,#keys-pie-graph,#solve-percentages-graph{height:400px;display:block}.no-decoration,.no-decoration:hover{color:inherit!important;text-decoration:none!important}.table td,.table th{vertical-align:inherit}pre{white-space:pre-wrap;margin:0;padding:0}.form-control{position:relative;display:block;border-radius:0;font-weight:400;font-family:Avenir Next,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-appearance:none}tbody tr:hover{background-color:rgba(0,0,0,.1)!important}tr[data-href]{cursor:pointer} \ No newline at end of file +html{position:relative;min-height:100%}body{margin-bottom:60px}.footer{position:absolute;bottom:1px;width:100%;height:60px;line-height:normal!important;z-index:-20}#score-graph{height:450px;display:block;clear:both}#solves-graph{display:block;height:350px}#categories-pie-graph,#keys-pie-graph,#solve-percentages-graph{height:400px;display:block}.no-decoration,.no-decoration:hover{color:inherit!important;text-decoration:none!important}.table td,.table th{vertical-align:inherit}pre{white-space:pre-wrap;margin:0;padding:0}.form-control{position:relative;display:block;border-radius:0;font-weight:400;font-family:Avenir Next,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-appearance:none}tbody tr:hover{background-color:rgba(0,0,0,.1)!important}.sort-col,input[type=checkbox],tr[data-href]{cursor:pointer} \ No newline at end of file diff --git a/CTFd/themes/admin/static/js/core.dev.js b/CTFd/themes/admin/static/js/core.dev.js index 516e1cc2..371db0c3 100644 --- a/CTFd/themes/admin/static/js/core.dev.js +++ b/CTFd/themes/admin/static/js/core.dev.js @@ -1,4 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["default~pages/challenge~pages/configs~pages/editor~pages/main~pages/notifications~pages/pages~pages/~0fc9fcae"],{ +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["default~pages/challenge~pages/challenges~pages/configs~pages/editor~pages/main~pages/notifications~p~d5a3cc0a"],{ /***/ "./CTFd/themes/admin/assets/js/pages/main.js": /*!***************************************************!*\ @@ -20,7 +20,7 @@ eval("\n\nvar _CTFd = _interopRequireDefault(__webpack_require__(/*! core/CTFd * /***/ (function(module, exports, __webpack_require__) { ; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\n__webpack_require__(/*! bootstrap/dist/js/bootstrap.bundle */ \"./node_modules/bootstrap/dist/js/bootstrap.bundle.js\");\n\nvar _jquery = _interopRequireDefault(__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar _default = function _default() {\n // TODO: This is kind of a hack to mimic a React-like state construct.\n // It should be removed once we have a real front-end framework in place.\n (0, _jquery.default)(\":input\").each(function () {\n (0, _jquery.default)(this).data(\"initial\", (0, _jquery.default)(this).val());\n });\n (0, _jquery.default)(\".form-control\").bind({\n focus: function focus() {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n },\n blur: function blur() {\n if ((0, _jquery.default)(this).val() === \"\") {\n (0, _jquery.default)(this).removeClass(\"input-filled-valid\");\n }\n }\n });\n (0, _jquery.default)(\".modal\").on(\"show.bs.modal\", function (e) {\n (0, _jquery.default)(\".form-control\").each(function () {\n if ((0, _jquery.default)(this).val()) {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n }\n });\n });\n (0, _jquery.default)(function () {\n (0, _jquery.default)(\".form-control\").each(function () {\n if ((0, _jquery.default)(this).val()) {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n }\n });\n (0, _jquery.default)(\"tr[data-href]\").click(function () {\n var sel = getSelection().toString();\n\n if (!sel) {\n var href = (0, _jquery.default)(this).attr(\"data-href\");\n\n if (href) {\n window.location = href;\n }\n }\n\n return false;\n });\n (0, _jquery.default)(\"tr[data-href] a, tr[data-href] button\").click(function (e) {\n // TODO: This is a hack to allow modal close buttons to work\n if (!(0, _jquery.default)(this).attr(\"data-dismiss\")) {\n e.stopPropagation();\n }\n });\n (0, _jquery.default)('[data-toggle=\"tooltip\"]').tooltip();\n });\n};\n\nexports.default = _default;\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/styles.js?"); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\n__webpack_require__(/*! bootstrap/dist/js/bootstrap.bundle */ \"./node_modules/bootstrap/dist/js/bootstrap.bundle.js\");\n\nvar _utils = __webpack_require__(/*! core/utils */ \"./CTFd/themes/core/assets/js/utils.js\");\n\nvar _jquery = _interopRequireDefault(__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar _default = function _default() {\n // TODO: This is kind of a hack to mimic a React-like state construct.\n // It should be removed once we have a real front-end framework in place.\n (0, _jquery.default)(\":input\").each(function () {\n (0, _jquery.default)(this).data(\"initial\", (0, _jquery.default)(this).val());\n });\n (0, _jquery.default)(\".form-control\").bind({\n focus: function focus() {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n },\n blur: function blur() {\n if ((0, _jquery.default)(this).val() === \"\") {\n (0, _jquery.default)(this).removeClass(\"input-filled-valid\");\n }\n }\n });\n (0, _jquery.default)(\".modal\").on(\"show.bs.modal\", function (e) {\n (0, _jquery.default)(\".form-control\").each(function () {\n if ((0, _jquery.default)(this).val()) {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n }\n });\n });\n (0, _jquery.default)(function () {\n (0, _jquery.default)(\".form-control\").each(function () {\n if ((0, _jquery.default)(this).val()) {\n (0, _jquery.default)(this).addClass(\"input-filled-valid\");\n }\n });\n (0, _jquery.default)(\"tr[data-href]\").click(function () {\n var sel = getSelection().toString();\n\n if (!sel) {\n var href = (0, _jquery.default)(this).attr(\"data-href\");\n\n if (href) {\n window.location = href;\n }\n }\n\n return false;\n });\n (0, _jquery.default)(\"[data-checkbox]\").click(function (e) {\n if ((0, _jquery.default)(e.target).is(\"input[type=checkbox]\")) {\n e.stopImmediatePropagation();\n return;\n }\n\n var checkbox = (0, _jquery.default)(this).find(\"input[type=checkbox]\"); // Doing it this way with an event allows data-checkbox-all to work\n\n checkbox.click();\n e.stopImmediatePropagation();\n });\n (0, _jquery.default)(\"[data-checkbox-all]\").on(\"click change\", function (e) {\n var checked = (0, _jquery.default)(this).prop(\"checked\");\n var idx = (0, _jquery.default)(this).index() + 1;\n (0, _jquery.default)(this).closest(\"table\").find(\"tr td:nth-child(\".concat(idx, \") input[type=checkbox]\")).prop(\"checked\", checked);\n e.stopImmediatePropagation();\n });\n (0, _jquery.default)(\"tr[data-href] a, tr[data-href] button\").click(function (e) {\n // TODO: This is a hack to allow modal close buttons to work\n if (!(0, _jquery.default)(this).attr(\"data-dismiss\")) {\n e.stopPropagation();\n }\n });\n (0, _utils.makeSortableTables)();\n (0, _jquery.default)('[data-toggle=\"tooltip\"]').tooltip();\n });\n};\n\nexports.default = _default;\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/styles.js?"); /***/ }), @@ -128,7 +128,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n /***/ (function(module, exports, __webpack_require__) { ; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.WindowController = WindowController;\nexports.colorHash = colorHash;\nexports.htmlEntities = htmlEntities;\nexports.cumulativeSum = cumulativeSum;\nexports.init_notification_counter = init_notification_counter;\nexports.set_notification_counter = set_notification_counter;\nexports.inc_notification_counter = inc_notification_counter;\nexports.dec_notification_counter = dec_notification_counter;\nexports.clear_notification_counter = clear_notification_counter;\nexports.copyToClipboard = copyToClipboard;\n\nvar _jquery = _interopRequireDefault(__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n_jquery.default.fn.serializeJSON = function (omit_nulls) {\n var params = {};\n var form = (0, _jquery.default)(this);\n var values = form.serializeArray();\n values = values.concat(form.find(\"input[type=checkbox]:checked\").map(function () {\n return {\n name: this.name,\n value: true\n };\n }).get());\n values = values.concat(form.find(\"input[type=checkbox]:not(:checked)\").map(function () {\n return {\n name: this.name,\n value: false\n };\n }).get());\n values.map(function (x) {\n if (omit_nulls) {\n if (x.value !== null && x.value !== \"\") {\n params[x.name] = x.value;\n } else {\n var input = form.find(\":input[name=\".concat(x.name, \"]\"));\n\n if (input.data(\"initial\") !== input.val()) {\n params[x.name] = x.value;\n }\n }\n } else {\n params[x.name] = x.value;\n }\n });\n return params;\n}; //http://stackoverflow.com/a/2648463 - wizardry!\n\n\nString.prototype.format = String.prototype.f = function () {\n var s = this,\n i = arguments.length;\n\n while (i--) {\n s = s.replace(new RegExp(\"\\\\{\" + i + \"\\\\}\", \"gm\"), arguments[i]);\n }\n\n return s;\n}; //http://stackoverflow.com/a/7616484\n\n\nString.prototype.hashCode = function () {\n var hash = 0,\n i,\n chr,\n len;\n if (this.length == 0) return hash;\n\n for (i = 0, len = this.length; i < len; i++) {\n chr = this.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n\n return hash;\n}; // https://gist.github.com/neilj/4146038\n// https://fastmail.blog/2012/11/26/inter-tab-communication-using-local-storage/\n\n\nfunction WindowController() {\n this.id = Math.random();\n this.isMaster = false;\n this.others = {};\n window.addEventListener(\"storage\", this, false);\n window.addEventListener(\"unload\", this, false);\n this.broadcast(\"hello\");\n var that = this;\n\n var check = function check() {\n that.check();\n that._checkTimeout = setTimeout(check, 9000);\n };\n\n var ping = function ping() {\n that.sendPing();\n that._pingTimeout = setTimeout(ping, 17000);\n };\n\n this._checkTimeout = setTimeout(check, 500);\n this._pingTimeout = setTimeout(ping, 17000);\n}\n\nWindowController.prototype.destroy = function () {\n clearTimeout(this._pingTimeout);\n clearTimeout(this._checkTimeout);\n window.removeEventListener(\"storage\", this, false);\n window.removeEventListener(\"unload\", this, false);\n this.broadcast(\"bye\");\n};\n\nWindowController.prototype.handleEvent = function (event) {\n if (event.type === \"unload\") {\n this.destroy();\n } else if (event.key === \"broadcast\") {\n try {\n var data = JSON.parse(event.newValue);\n\n if (data.id !== this.id) {\n this[data.type](data);\n }\n } catch (error) {}\n }\n};\n\nWindowController.prototype.sendPing = function () {\n this.broadcast(\"ping\");\n};\n\nWindowController.prototype.hello = function (event) {\n this.ping(event);\n\n if (event.id < this.id) {\n this.check();\n } else {\n this.sendPing();\n }\n};\n\nWindowController.prototype.ping = function (event) {\n this.others[event.id] = +new Date();\n};\n\nWindowController.prototype.bye = function (event) {\n delete this.others[event.id];\n this.check();\n};\n\nWindowController.prototype.check = function (event) {\n var now = +new Date(),\n takeMaster = true,\n id;\n\n for (id in this.others) {\n if (this.others[id] + 23000 < now) {\n delete this.others[id];\n } else if (id < this.id) {\n takeMaster = false;\n }\n }\n\n if (this.isMaster !== takeMaster) {\n this.isMaster = takeMaster;\n this.masterDidChange();\n }\n};\n\nWindowController.prototype.masterDidChange = function () {};\n\nWindowController.prototype.broadcast = function (type, data) {\n var event = {\n id: this.id,\n type: type\n };\n\n for (var x in data) {\n event[x] = data[x];\n }\n\n try {\n localStorage.setItem(\"broadcast\", JSON.stringify(event));\n } catch (error) {\n console.log(error);\n }\n};\n\nfunction colorHash(str) {\n var hash = 0;\n\n for (var i = 0; i < str.length; i++) {\n hash = str.charCodeAt(i) + ((hash << 5) - hash);\n }\n\n var colour = \"#\";\n\n for (var _i = 0; _i < 3; _i++) {\n var value = hash >> _i * 8 & 0xff;\n colour += (\"00\" + value.toString(16)).substr(-2);\n }\n\n return colour;\n}\n\nfunction htmlEntities(string) {\n return (0, _jquery.default)(\"
\").text(string).html();\n}\n\nfunction cumulativeSum(arr) {\n var result = arr.concat();\n\n for (var i = 0; i < arr.length; i++) {\n result[i] = arr.slice(0, i + 1).reduce(function (p, i) {\n return p + i;\n });\n }\n\n return result;\n}\n\nvar storage = window.localStorage;\nvar counter_key = \"unread_notifications\";\n\nfunction init_notification_counter() {\n var count = storage.getItem(counter_key);\n\n if (count === null) {\n storage.setItem(counter_key, 0);\n } else {\n if (count > 0) {\n (0, _jquery.default)(\".badge-notification\").text(count);\n }\n }\n}\n\nfunction set_notification_counter(count) {\n storage.setItem(counter_key, count);\n}\n\nfunction inc_notification_counter() {\n var count = storage.getItem(counter_key) || 0;\n storage.setItem(counter_key, ++count);\n (0, _jquery.default)(\".badge-notification\").text(count);\n}\n\nfunction dec_notification_counter() {\n var count = storage.getItem(counter_key) || 0;\n\n if (count > 0) {\n storage.setItem(counter_key, --count);\n (0, _jquery.default)(\".badge-notification\").text(count);\n } // Always clear if count is 0\n\n\n if (count == 0) {\n clear_notification_counter();\n }\n}\n\nfunction clear_notification_counter() {\n storage.setItem(counter_key, 0);\n (0, _jquery.default)(\".badge-notification\").empty();\n}\n\nfunction copyToClipboard(event, selector) {\n // Select element\n (0, _jquery.default)(selector).select(); // Copy to clipboard\n\n document.execCommand(\"copy\"); // Show tooltip to user\n\n (0, _jquery.default)(event.target).tooltip({\n title: \"Copied!\",\n trigger: \"manual\"\n });\n (0, _jquery.default)(event.target).tooltip(\"show\");\n setTimeout(function () {\n (0, _jquery.default)(event.target).tooltip(\"hide\");\n }, 1500);\n}\n\n//# sourceURL=webpack:///./CTFd/themes/core/assets/js/utils.js?"); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.WindowController = WindowController;\nexports.colorHash = colorHash;\nexports.htmlEntities = htmlEntities;\nexports.cumulativeSum = cumulativeSum;\nexports.init_notification_counter = init_notification_counter;\nexports.set_notification_counter = set_notification_counter;\nexports.inc_notification_counter = inc_notification_counter;\nexports.dec_notification_counter = dec_notification_counter;\nexports.clear_notification_counter = clear_notification_counter;\nexports.copyToClipboard = copyToClipboard;\nexports.makeSortableTables = makeSortableTables;\n\nvar _jquery = _interopRequireDefault(__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n_jquery.default.fn.serializeJSON = function (omit_nulls) {\n var params = {};\n var form = (0, _jquery.default)(this);\n var values = form.serializeArray();\n values = values.concat(form.find(\"input[type=checkbox]:checked\").map(function () {\n return {\n name: this.name,\n value: true\n };\n }).get());\n values = values.concat(form.find(\"input[type=checkbox]:not(:checked)\").map(function () {\n return {\n name: this.name,\n value: false\n };\n }).get());\n values.map(function (x) {\n if (omit_nulls) {\n if (x.value !== null && x.value !== \"\") {\n params[x.name] = x.value;\n } else {\n var input = form.find(\":input[name=\".concat(x.name, \"]\"));\n\n if (input.data(\"initial\") !== input.val()) {\n params[x.name] = x.value;\n }\n }\n } else {\n params[x.name] = x.value;\n }\n });\n return params;\n}; //http://stackoverflow.com/a/2648463 - wizardry!\n\n\nString.prototype.format = String.prototype.f = function () {\n var s = this,\n i = arguments.length;\n\n while (i--) {\n s = s.replace(new RegExp(\"\\\\{\" + i + \"\\\\}\", \"gm\"), arguments[i]);\n }\n\n return s;\n}; //http://stackoverflow.com/a/7616484\n\n\nString.prototype.hashCode = function () {\n var hash = 0,\n i,\n chr,\n len;\n if (this.length == 0) return hash;\n\n for (i = 0, len = this.length; i < len; i++) {\n chr = this.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n\n return hash;\n}; // https://gist.github.com/neilj/4146038\n// https://fastmail.blog/2012/11/26/inter-tab-communication-using-local-storage/\n\n\nfunction WindowController() {\n this.id = Math.random();\n this.isMaster = false;\n this.others = {};\n window.addEventListener(\"storage\", this, false);\n window.addEventListener(\"unload\", this, false);\n this.broadcast(\"hello\");\n var that = this;\n\n var check = function check() {\n that.check();\n that._checkTimeout = setTimeout(check, 9000);\n };\n\n var ping = function ping() {\n that.sendPing();\n that._pingTimeout = setTimeout(ping, 17000);\n };\n\n this._checkTimeout = setTimeout(check, 500);\n this._pingTimeout = setTimeout(ping, 17000);\n}\n\nWindowController.prototype.destroy = function () {\n clearTimeout(this._pingTimeout);\n clearTimeout(this._checkTimeout);\n window.removeEventListener(\"storage\", this, false);\n window.removeEventListener(\"unload\", this, false);\n this.broadcast(\"bye\");\n};\n\nWindowController.prototype.handleEvent = function (event) {\n if (event.type === \"unload\") {\n this.destroy();\n } else if (event.key === \"broadcast\") {\n try {\n var data = JSON.parse(event.newValue);\n\n if (data.id !== this.id) {\n this[data.type](data);\n }\n } catch (error) {}\n }\n};\n\nWindowController.prototype.sendPing = function () {\n this.broadcast(\"ping\");\n};\n\nWindowController.prototype.hello = function (event) {\n this.ping(event);\n\n if (event.id < this.id) {\n this.check();\n } else {\n this.sendPing();\n }\n};\n\nWindowController.prototype.ping = function (event) {\n this.others[event.id] = +new Date();\n};\n\nWindowController.prototype.bye = function (event) {\n delete this.others[event.id];\n this.check();\n};\n\nWindowController.prototype.check = function (event) {\n var now = +new Date(),\n takeMaster = true,\n id;\n\n for (id in this.others) {\n if (this.others[id] + 23000 < now) {\n delete this.others[id];\n } else if (id < this.id) {\n takeMaster = false;\n }\n }\n\n if (this.isMaster !== takeMaster) {\n this.isMaster = takeMaster;\n this.masterDidChange();\n }\n};\n\nWindowController.prototype.masterDidChange = function () {};\n\nWindowController.prototype.broadcast = function (type, data) {\n var event = {\n id: this.id,\n type: type\n };\n\n for (var x in data) {\n event[x] = data[x];\n }\n\n try {\n localStorage.setItem(\"broadcast\", JSON.stringify(event));\n } catch (error) {\n console.log(error);\n }\n};\n\nfunction colorHash(str) {\n var hash = 0;\n\n for (var i = 0; i < str.length; i++) {\n hash = str.charCodeAt(i) + ((hash << 5) - hash);\n }\n\n var colour = \"#\";\n\n for (var _i = 0; _i < 3; _i++) {\n var value = hash >> _i * 8 & 0xff;\n colour += (\"00\" + value.toString(16)).substr(-2);\n }\n\n return colour;\n}\n\nfunction htmlEntities(string) {\n return (0, _jquery.default)(\"
\").text(string).html();\n}\n\nfunction cumulativeSum(arr) {\n var result = arr.concat();\n\n for (var i = 0; i < arr.length; i++) {\n result[i] = arr.slice(0, i + 1).reduce(function (p, i) {\n return p + i;\n });\n }\n\n return result;\n}\n\nvar storage = window.localStorage;\nvar counter_key = \"unread_notifications\";\n\nfunction init_notification_counter() {\n var count = storage.getItem(counter_key);\n\n if (count === null) {\n storage.setItem(counter_key, 0);\n } else {\n if (count > 0) {\n (0, _jquery.default)(\".badge-notification\").text(count);\n }\n }\n}\n\nfunction set_notification_counter(count) {\n storage.setItem(counter_key, count);\n}\n\nfunction inc_notification_counter() {\n var count = storage.getItem(counter_key) || 0;\n storage.setItem(counter_key, ++count);\n (0, _jquery.default)(\".badge-notification\").text(count);\n}\n\nfunction dec_notification_counter() {\n var count = storage.getItem(counter_key) || 0;\n\n if (count > 0) {\n storage.setItem(counter_key, --count);\n (0, _jquery.default)(\".badge-notification\").text(count);\n } // Always clear if count is 0\n\n\n if (count == 0) {\n clear_notification_counter();\n }\n}\n\nfunction clear_notification_counter() {\n storage.setItem(counter_key, 0);\n (0, _jquery.default)(\".badge-notification\").empty();\n}\n\nfunction copyToClipboard(event, selector) {\n // Select element\n (0, _jquery.default)(selector).select(); // Copy to clipboard\n\n document.execCommand(\"copy\"); // Show tooltip to user\n\n (0, _jquery.default)(event.target).tooltip({\n title: \"Copied!\",\n trigger: \"manual\"\n });\n (0, _jquery.default)(event.target).tooltip(\"show\");\n setTimeout(function () {\n (0, _jquery.default)(event.target).tooltip(\"hide\");\n }, 1500);\n}\n\nfunction makeSortableTables() {\n (0, _jquery.default)(\"th.sort-col\").append(\" \");\n (0, _jquery.default)(\"th.sort-col\").click(function () {\n var table = (0, _jquery.default)(this).parents(\"table\").eq(0);\n var rows = table.find(\"tr:gt(0)\").toArray().sort(comparer((0, _jquery.default)(this).index()));\n this.asc = !this.asc;\n\n if (!this.asc) {\n rows = rows.reverse();\n }\n\n for (var i = 0; i < rows.length; i++) {\n table.append(rows[i]);\n }\n });\n\n function comparer(index) {\n return function (a, b) {\n var valA = getCellValue(a, index),\n valB = getCellValue(b, index);\n return _jquery.default.isNumeric(valA) && _jquery.default.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB);\n };\n }\n\n function getCellValue(row, index) {\n return (0, _jquery.default)(row).children(\"td\").eq(index).text();\n }\n}\n\n//# sourceURL=webpack:///./CTFd/themes/core/assets/js/utils.js?"); /***/ }), diff --git a/CTFd/themes/admin/static/js/pages/challenge.dev.js b/CTFd/themes/admin/static/js/pages/challenge.dev.js index d84a106f..9c5a418e 100644 --- a/CTFd/themes/admin/static/js/pages/challenge.dev.js +++ b/CTFd/themes/admin/static/js/pages/challenge.dev.js @@ -147,7 +147,7 @@ /******/ /******/ /******/ // add entry module to deferred list -/******/ deferredModules.push(["./CTFd/themes/admin/assets/js/pages/challenge.js","helpers","vendor","default~pages/challenge~pages/configs~pages/editor~pages/main~pages/notifications~pages/pages~pages/~0fc9fcae"]); +/******/ deferredModules.push(["./CTFd/themes/admin/assets/js/pages/challenge.js","helpers","vendor","default~pages/challenge~pages/challenges~pages/configs~pages/editor~pages/main~pages/notifications~p~d5a3cc0a"]); /******/ // run deferred modules when ready /******/ return checkDeferredModules(); /******/ }) diff --git a/CTFd/themes/admin/static/js/pages/challenge.min.js b/CTFd/themes/admin/static/js/pages/challenge.min.js index 17618b66..b3900ca4 100644 --- a/CTFd/themes/admin/static/js/pages/challenge.min.js +++ b/CTFd/themes/admin/static/js/pages/challenge.min.js @@ -1 +1 @@ -!function(d){function e(e){for(var t,o,n=e[0],s=e[1],a=e[2],i=0,l=[];i -- ");for(var s in o.append(n),t)t.hasOwnProperty(s)&&(n=(0,a.default)("".format(s,t[s].name)),o.append(n));(0,a.default)("#flag-edit-modal").modal()}),(0,a.default)("#flag-edit-modal form").submit(function(e){e.preventDefault();var t=(0,a.default)(this).serializeJSON(!0);t.challenge=CHALLENGE_ID,i.default.fetch("/api/v1/flags",{method:"POST",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(e){window.location.reload()})}),(0,a.default)("#flag-edit-modal").modal()},t.editFlagModal=function(e){e.preventDefault();var n=(0,a.default)(this).attr("flag-id"),s=(0,a.default)(this).parent().parent();a.default.get(i.default.config.urlRoot+"/api/v1/flags/"+n,function(e){var o=e.data;a.default.get(i.default.config.urlRoot+o.templates.update,function(e){(0,a.default)("#edit-flags form").empty(),(0,a.default)("#edit-flags form").off();var t=l.default.compile(e);(0,a.default)("#edit-flags form").append(t.render(o)),(0,a.default)("#edit-flags form").submit(function(e){e.preventDefault();var t=(0,a.default)("#edit-flags form").serializeJSON();i.default.fetch("/api/v1/flags/"+n,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(e){e.success&&((0,a.default)(s).find(".flag-content").text(e.data.content),(0,a.default)("#edit-flags").modal("toggle"))})}),(0,a.default)("#edit-flags").modal()})})},t.flagTypeSelect=function(e){e.preventDefault();var t=(0,a.default)(this).find("option:selected").text();a.default.get(i.default.config.urlRoot+"/api/v1/flags/types/"+t,function(e){var t=e.data;a.default.get(i.default.config.urlRoot+t.templates.create,function(e){var t=l.default.compile(e);(0,a.default)("#create-keys-entry-div").html(t.render()),(0,a.default)("#create-keys-button-div").show()})})};var a=s(o("./node_modules/jquery/dist/jquery.js")),i=s(o("./CTFd/themes/core/assets/js/CTFd.js")),l=s(o("./node_modules/nunjucks/browser/nunjucks.js")),n=o("./CTFd/themes/core/assets/js/ezq.js");function s(e){return e&&e.__esModule?e:{default:e}}},"./CTFd/themes/admin/assets/js/challenges/hints.js":function(e,t,o){Object.defineProperty(t,"__esModule",{value:!0}),t.showHintModal=function(e){e.preventDefault(),(0,s.default)("#hint-edit-modal form").find("input, textarea").val(""),(0,s.default)("#new-hint-edit").on("shown.bs.tab",function(e){if("#hint-preview"==e.target.hash){var t=a.default.lib.markdown(),o=(0,s.default)("#hint-write textarea").val();(0,s.default)(e.target.hash).html(t.render(o))}}),(0,s.default)("#hint-edit-modal").modal()},t.showEditHintModal=function(e){e.preventDefault();var t=(0,s.default)(this).attr("hint-id");a.default.fetch("/api/v1/hints/"+t+"?preview=true",{method:"GET",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"}}).then(function(e){return e.json()}).then(function(e){e.success&&((0,s.default)("#hint-edit-form input[name=content],textarea[name=content]").val(e.data.content),(0,s.default)("#hint-edit-form input[name=cost]").val(e.data.cost),(0,s.default)("#hint-edit-form input[name=id]").val(e.data.id),(0,s.default)("#new-hint-edit").on("shown.bs.tab",function(e){if("#hint-preview"==e.target.hash){var t=a.default.lib.markdown(),o=(0,s.default)("#hint-write textarea").val();(0,s.default)(e.target.hash).html(t.render(o))}}),(0,s.default)("#hint-edit-modal").modal())})},t.deleteHint=function(e){e.preventDefault();var t=(0,s.default)(this).attr("hint-id"),o=(0,s.default)(this).parent().parent();(0,n.ezQuery)({title:"Delete Hint",body:"Are you sure you want to delete this hint?",success:function(){a.default.fetch("/api/v1/hints/"+t,{method:"DELETE"}).then(function(e){return e.json()}).then(function(e){e.success&&o.remove()})}})},t.editHint=function(e){e.preventDefault();var t=(0,s.default)(this).serializeJSON(!0);t.challenge=CHALLENGE_ID;var o="POST",n="/api/v1/hints";t.id&&(o="PATCH",n="/api/v1/hints/"+t.id);a.default.fetch(n,{method:o,credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(e){e.success&&window.location.reload()})};var s=i(o("./node_modules/jquery/dist/jquery.js")),a=i(o("./CTFd/themes/core/assets/js/CTFd.js")),n=o("./CTFd/themes/core/assets/js/ezq.js");function i(e){return e&&e.__esModule?e:{default:e}}},"./CTFd/themes/admin/assets/js/challenges/requirements.js":function(e,t,o){Object.defineProperty(t,"__esModule",{value:!0}),t.addRequirement=function(e){e.preventDefault();var t=(0,s.default)("#prerequisite-add-form").serializeJSON();if(!t.prerequisite)return;CHALLENGE_REQUIREMENTS.prerequisites.push(parseInt(t.prerequisite));var o={requirements:CHALLENGE_REQUIREMENTS};a.default.fetch("/api/v1/challenges/"+CHALLENGE_ID,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(o)}).then(function(e){return e.json()}).then(function(e){e.success&&window.location.reload()})},t.deleteRequirement=function(e){var t=(0,s.default)(this).attr("challenge-id"),o=(0,s.default)(this).parent().parent();CHALLENGE_REQUIREMENTS.prerequisites.pop(t);var n={requirements:CHALLENGE_REQUIREMENTS};a.default.fetch("/api/v1/challenges/"+CHALLENGE_ID,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(n)}).then(function(e){return e.json()}).then(function(e){e.success&&o.remove()})};var s=n(o("./node_modules/jquery/dist/jquery.js")),a=n(o("./CTFd/themes/core/assets/js/CTFd.js"));function n(e){return e&&e.__esModule?e:{default:e}}},"./CTFd/themes/admin/assets/js/challenges/tags.js":function(e,t,o){Object.defineProperty(t,"__esModule",{value:!0}),t.deleteTag=i,t.addTag=function(e){if(13!=e.keyCode)return;var t=(0,n.default)(this),o={value:t.val(),challenge:CHALLENGE_ID};s.default.api.post_tag_list({},o).then(function(e){if(e.success){var t=(0,n.default)("{0}×".format(e.data.value,e.data.id));(0,n.default)("#challenge-tags").append(t),t.click(i)}}),t.val("")};var n=a(o("./node_modules/jquery/dist/jquery.js")),s=a(o("./CTFd/themes/core/assets/js/CTFd.js"));function a(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=(0,n.default)(this),o=t.attr("tag-id");s.default.api.delete_tag({tagId:o}).then(function(e){e.success&&t.parent().remove()})}},"./CTFd/themes/admin/assets/js/pages/challenge.js":function(e,t,o){o("./CTFd/themes/admin/assets/js/pages/main.js");var n=o("./CTFd/themes/core/assets/js/utils.js"),l=f(o("./node_modules/jquery/dist/jquery.js"));o("./node_modules/bootstrap/js/dist/tab.js");var i=f(o("./CTFd/themes/core/assets/js/CTFd.js")),s=o("./CTFd/themes/core/assets/js/ezq.js"),a=f(o("./node_modules/nunjucks/browser/nunjucks.js")),d=f(o("./CTFd/themes/core/assets/js/helpers.js")),r=o("./CTFd/themes/admin/assets/js/challenges/files.js"),c=o("./CTFd/themes/admin/assets/js/challenges/tags.js"),u=o("./CTFd/themes/admin/assets/js/challenges/requirements.js"),m=o("./CTFd/themes/admin/assets/js/challenges/hints.js"),p=o("./CTFd/themes/admin/assets/js/challenges/flags.js");function f(e){return e&&e.__esModule?e:{default:e}}function h(t){i.default.api.get_hint({hintId:t,preview:!0}).then(function(e){e.data.content?function(e){(0,s.ezAlert)({title:"Hint",body:j.render(e.content),button:"Got it!"})}(e.data):displayUnlock(t)})}var j=i.default.lib.markdown();function _(e,t){var o=e.data,n=(0,l.default)("#result-message"),s=(0,l.default)("#result-notification"),a=(0,l.default)("#submission-input");s.removeClass(),n.text(o.message),"authentication_required"!==o.status?("incorrect"===o.status?(s.addClass("alert alert-danger alert-dismissable text-center"),s.slideDown(),a.removeClass("correct"),a.addClass("wrong"),setTimeout(function(){a.removeClass("wrong")},3e3)):"correct"===o.status?(s.addClass("alert alert-success alert-dismissable text-center"),s.slideDown(),(0,l.default)(".challenge-solves").text(parseInt((0,l.default)(".challenge-solves").text().split(" ")[0])+1+" Solves"),a.val(""),a.removeClass("wrong"),a.addClass("correct")):"already_solved"===o.status?(s.addClass("alert alert-info alert-dismissable text-center"),s.slideDown(),a.addClass("correct")):"paused"===o.status?(s.addClass("alert alert-warning alert-dismissable text-center"),s.slideDown()):"ratelimited"===o.status&&(s.addClass("alert alert-warning alert-dismissable text-center"),s.slideDown(),a.addClass("too-fast"),setTimeout(function(){a.removeClass("too-fast")},3e3)),setTimeout(function(){(0,l.default)(".alert").slideUp(),(0,l.default)("#submit-key").removeClass("disabled-button"),(0,l.default)("#submit-key").prop("disabled",!1)},3e3),t&&t(o)):window.location=i.default.config.urlRoot+"/login?next="+i.default.config.urlRoot+window.location.pathname+window.location.hash}function g(o){i.default._internal.challenge={},l.default.getScript(i.default.config.urlRoot+o.scripts.view,function(){l.default.get(i.default.config.urlRoot+o.templates.create,function(e){var t=a.default.compile(e);(0,l.default)("#create-chal-entry-div").html(t.render({nonce:i.default.config.csrfNonce,script_root:i.default.config.urlRoot})),l.default.getScript(i.default.config.urlRoot+o.scripts.create,function(){(0,l.default)("#create-chal-entry-div form").submit(function(e){e.preventDefault();var t=(0,l.default)("#create-chal-entry-div form").serializeJSON();i.default.fetch("/api/v1/challenges",{method:"POST",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t)}).then(function(e){return e.json()}).then(function(e){e.success&&((0,l.default)("#challenge-create-options #challenge_id").val(e.data.id),(0,l.default)("#challenge-create-options").modal())})})})})})}function v(s){s.preventDefault();var a=(0,l.default)(s.target).serializeJSON(!0),o={challenge_id:a.challenge_id,content:a.flag||"",type:a.flag_type,data:a.flag_data?a.flag_data:""};Promise.all([new Promise(function(t,e){0!=o.content.length?i.default.fetch("/api/v1/flags",{method:"POST",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(o)}).then(function(e){t(e.json())}):t()}),new Promise(function(e,t){var o=s.target,n={challenge:a.challenge_id,type:"challenge"};(0,l.default)(o.elements.file).val()&&d.default.files.upload(o,n),e()})]).then(function(e){i.default.fetch("/api/v1/challenges/"+a.challenge_id,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({state:a.state})}).then(function(e){return e.json()}).then(function(e){e.success&&setTimeout(function(){window.location=i.default.config.urlRoot+"/admin/challenges/"+a.challenge_id},700)})})}function y(e){var t=(0,l.default)(this).find("option:selected").data("meta");void 0!==t?g(t):(0,l.default)("#create-chal-entry-div").empty()}(0,l.default)(function(){if((0,l.default)(".preview-challenge").click(function(e){window.challenge=new Object,i.default._internal.challenge={},l.default.get(i.default.config.urlRoot+"/api/v1/challenges/"+CHALLENGE_ID,function(e){var o=i.default._internal.challenge,n=e.data;n.solves=null,l.default.getScript(i.default.config.urlRoot+n.type_data.scripts.view,function(){l.default.get(i.default.config.urlRoot+n.type_data.templates.view,function(e){(0,l.default)("#challenge-window").empty();var t=a.default.compile(e);o.data=n,o.preRender(),n.description=o.render(n.description),n.script_root=i.default.config.urlRoot,(0,l.default)("#challenge-window").append(t.render(n)),(0,l.default)(".challenge-solves").click(function(e){getsolves((0,l.default)("#challenge-id").val())}),(0,l.default)(".nav-tabs a").click(function(e){e.preventDefault(),(0,l.default)(this).tab("show")}),(0,l.default)("#challenge-window").on("hide.bs.modal",function(e){(0,l.default)("#submission-input").removeClass("wrong"),(0,l.default)("#submission-input").removeClass("correct"),(0,l.default)("#incorrect-key").slideUp(),(0,l.default)("#correct-key").slideUp(),(0,l.default)("#already-solved").slideUp(),(0,l.default)("#too-fast").slideUp()}),(0,l.default)(".load-hint").on("click",function(e){h((0,l.default)(this).data("hint-id"))}),(0,l.default)("#submit-key").click(function(e){e.preventDefault(),(0,l.default)("#submit-key").addClass("disabled-button"),(0,l.default)("#submit-key").prop("disabled",!0),i.default._internal.challenge.submit(!0).then(_)}),(0,l.default)("#submission-input").keyup(function(e){13==e.keyCode&&(0,l.default)("#submit-key").click()}),(0,l.default)(".input-field").bind({focus:function(){(0,l.default)(this).parent().addClass("input--filled"),$label=(0,l.default)(this).siblings(".input-label")},blur:function(){""===(0,l.default)(this).val()&&((0,l.default)(this).parent().removeClass("input--filled"),$label=(0,l.default)(this).siblings(".input-label"),$label.removeClass("input--hide"))}}),o.postRender(),window.location.replace(window.location.href.split("#")[0]+"#preview"),(0,l.default)("#challenge-window").modal()})})})}),(0,l.default)(".delete-challenge").click(function(e){(0,s.ezQuery)({title:"Delete Challenge",body:"Are you sure you want to delete {0}".format(""+(0,n.htmlEntities)(CHALLENGE_NAME)+""),success:function(){i.default.fetch("/api/v1/challenges/"+CHALLENGE_ID,{method:"DELETE"}).then(function(e){return e.json()}).then(function(e){e.success&&(window.location=i.default.config.urlRoot+"/admin/challenges")})}})}),(0,l.default)("#challenge-update-container > form").submit(function(e){e.preventDefault();var o=(0,l.default)(e.target).serializeJSON(!0);i.default.fetch("/api/v1/challenges/"+CHALLENGE_ID+"/flags",{method:"GET",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"}}).then(function(e){return e.json()}).then(function(e){function t(){i.default.fetch("/api/v1/challenges/"+CHALLENGE_ID,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(o)}).then(function(e){return e.json()}).then(function(e){if(e.success){switch((0,l.default)(".challenge-state").text(e.data.state),e.data.state){case"visible":(0,l.default)(".challenge-state").removeClass("badge-danger").addClass("badge-success");break;case"hidden":(0,l.default)(".challenge-state").removeClass("badge-success").addClass("badge-danger")}(0,s.ezToast)({title:"Success",body:"Your challenge has been updated!"})}})}0===e.data.length&&"visible"===o.state?(0,s.ezQuery)({title:"Missing Flags",body:"This challenge does not have any flags meaning it is unsolveable. Are you sure you'd like to update this challenge?",success:t}):t()})}),(0,l.default)("#challenge-create-options form").submit(v),(0,l.default)(".nav-tabs a").click(function(e){(0,l.default)(this).tab("show"),window.location.hash=this.hash}),window.location.hash){var e=window.location.hash.replace("<>[]'\"","");(0,l.default)('nav a[href="'+e+'"]').tab("show")}(0,l.default)("#tags-add-input").keyup(c.addTag),(0,l.default)(".delete-tag").click(c.deleteTag),(0,l.default)("#prerequisite-add-form").submit(u.addRequirement),(0,l.default)(".delete-requirement").click(u.deleteRequirement),(0,l.default)("#file-add-form").submit(r.addFile),(0,l.default)(".delete-file").click(r.deleteFile),(0,l.default)("#hint-add-button").click(m.showHintModal),(0,l.default)(".delete-hint").click(m.deleteHint),(0,l.default)(".edit-hint").click(m.showEditHintModal),(0,l.default)("#hint-edit-form").submit(m.editHint),(0,l.default)("#flag-add-button").click(p.addFlagModal),(0,l.default)(".delete-flag").click(p.deleteFlag),(0,l.default)("#flags-create-select").change(p.flagTypeSelect),(0,l.default)(".edit-flag").click(p.editFlagModal),l.default.get(i.default.config.urlRoot+"/api/v1/challenges/types",function(e){(0,l.default)("#create-chals-select").empty();var t=e.data,o=Object.keys(t).length;if(1 -- "),t){var s=t[n],a=(0,l.default)("