diff --git a/CTFd/schemas/challenges.py b/CTFd/schemas/challenges.py
index c9ad6f4a..3cd9615a 100644
--- a/CTFd/schemas/challenges.py
+++ b/CTFd/schemas/challenges.py
@@ -1,9 +1,29 @@
from marshmallow import validate
+from marshmallow.exceptions import ValidationError
from marshmallow_sqlalchemy import field_for
from CTFd.models import Challenges, ma
+class ChallengeRequirementsValidator(validate.Validator):
+ default_message = "Error parsing challenge requirements"
+
+ def __init__(self, error=None):
+ self.error = error or self.default_message
+
+ def __call__(self, value):
+ if isinstance(value, dict) is False:
+ raise ValidationError(self.default_message)
+
+ prereqs = value.get("prerequisites", [])
+ if all(prereqs) is False:
+ raise ValidationError(
+ "Challenge requirements cannot have a null prerequisite"
+ )
+
+ return value
+
+
class ChallengeSchema(ma.ModelSchema):
class Meta:
model = Challenges
@@ -46,3 +66,7 @@ class ChallengeSchema(ma.ModelSchema):
)
],
)
+
+ requirements = field_for(
+ Challenges, "requirements", validate=[ChallengeRequirementsValidator()],
+ )
diff --git a/CTFd/themes/admin/assets/js/components/requirements/Requirements.vue b/CTFd/themes/admin/assets/js/components/requirements/Requirements.vue
index 19286365..0fc2f865 100644
--- a/CTFd/themes/admin/assets/js/components/requirements/Requirements.vue
+++ b/CTFd/themes/admin/assets/js/components/requirements/Requirements.vue
@@ -43,7 +43,12 @@
-
+
@@ -123,6 +128,10 @@ export default {
? this.requirements.prerequisites
: [];
+ if (!this.selectedRequirement) {
+ return;
+ }
+
newRequirements.push(this.selectedRequirement);
this.requirements["prerequisites"] = newRequirements;
@@ -144,6 +153,7 @@ export default {
})
.then(data => {
if (data.success) {
+ this.selectedRequirement = null;
this.loadRequirements();
}
});
diff --git a/CTFd/themes/admin/static/js/components.dev.js b/CTFd/themes/admin/static/js/components.dev.js
index 80f60007..53b60842 100644
--- a/CTFd/themes/admin/static/js/components.dev.js
+++ b/CTFd/themes/admin/static/js/components.dev.js
@@ -668,7 +668,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[\"default\"] = void 0;\n\nvar _CTFd = _interopRequireDefault(__webpack_require__(/*! core/CTFd */ \"./CTFd/themes/core/assets/js/CTFd.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar _default = {\n props: {\n challenge_id: Number\n },\n data: function data() {\n return {\n challenges: [],\n requirements: {},\n selectedRequirement: null\n };\n },\n computed: {\n // Get all challenges besides the current one and current prereqs\n otherChallenges: function otherChallenges() {\n var _this = this;\n\n var prerequisites = this.requirements.prerequisites || [];\n return this.challenges.filter(function (challenge) {\n return challenge.id !== _this.$props.challenge_id && !prerequisites.includes(challenge.id);\n });\n }\n },\n methods: {\n loadChallenges: function loadChallenges() {\n var _this2 = this;\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges?view=admin\", {\n method: \"GET\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n }\n }).then(function (response) {\n return response.json();\n }).then(function (response) {\n if (response.success) {\n _this2.challenges = response.data;\n }\n });\n },\n getChallengeById: function getChallengeById(challenge_id) {\n return this.challenges.find(function (challenge) {\n return challenge.id === challenge_id;\n });\n },\n loadRequirements: function loadRequirements() {\n var _this3 = this;\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id, \"/requirements\"), {\n method: \"GET\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n }\n }).then(function (response) {\n return response.json();\n }).then(function (response) {\n if (response.success) {\n _this3.requirements = response.data || {};\n }\n });\n },\n addRequirement: function addRequirement() {\n var _this4 = this;\n\n var newRequirements = this.requirements.prerequisites ? this.requirements.prerequisites : [];\n newRequirements.push(this.selectedRequirement);\n this.requirements[\"prerequisites\"] = newRequirements;\n var params = {\n requirements: this.requirements\n };\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id), {\n method: \"PATCH\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(params)\n }).then(function (response) {\n return response.json();\n }).then(function (data) {\n if (data.success) {\n _this4.loadRequirements();\n }\n });\n },\n removeRequirement: function removeRequirement(challenge_id) {\n var _this5 = this;\n\n this.requirements.prerequisites = this.requirements.prerequisites.filter(function (val) {\n return val !== challenge_id;\n });\n var params = {\n requirements: this.requirements\n };\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id), {\n method: \"PATCH\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(params)\n }).then(function (response) {\n return response.json();\n }).then(function (data) {\n if (data.success) {\n _this5.loadRequirements();\n }\n });\n }\n },\n created: function created() {\n this.loadChallenges();\n this.loadRequirements();\n }\n};\nexports[\"default\"] = _default;\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/components/requirements/Requirements.vue?./node_modules/babel-loader/lib??ref--0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports[\"default\"] = void 0;\n\nvar _CTFd = _interopRequireDefault(__webpack_require__(/*! core/CTFd */ \"./CTFd/themes/core/assets/js/CTFd.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar _default = {\n props: {\n challenge_id: Number\n },\n data: function data() {\n return {\n challenges: [],\n requirements: {},\n selectedRequirement: null\n };\n },\n computed: {\n // Get all challenges besides the current one and current prereqs\n otherChallenges: function otherChallenges() {\n var _this = this;\n\n var prerequisites = this.requirements.prerequisites || [];\n return this.challenges.filter(function (challenge) {\n return challenge.id !== _this.$props.challenge_id && !prerequisites.includes(challenge.id);\n });\n }\n },\n methods: {\n loadChallenges: function loadChallenges() {\n var _this2 = this;\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges?view=admin\", {\n method: \"GET\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n }\n }).then(function (response) {\n return response.json();\n }).then(function (response) {\n if (response.success) {\n _this2.challenges = response.data;\n }\n });\n },\n getChallengeById: function getChallengeById(challenge_id) {\n return this.challenges.find(function (challenge) {\n return challenge.id === challenge_id;\n });\n },\n loadRequirements: function loadRequirements() {\n var _this3 = this;\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id, \"/requirements\"), {\n method: \"GET\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n }\n }).then(function (response) {\n return response.json();\n }).then(function (response) {\n if (response.success) {\n _this3.requirements = response.data || {};\n }\n });\n },\n addRequirement: function addRequirement() {\n var _this4 = this;\n\n var newRequirements = this.requirements.prerequisites ? this.requirements.prerequisites : [];\n\n if (!this.selectedRequirement) {\n return;\n }\n\n newRequirements.push(this.selectedRequirement);\n this.requirements[\"prerequisites\"] = newRequirements;\n var params = {\n requirements: this.requirements\n };\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id), {\n method: \"PATCH\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(params)\n }).then(function (response) {\n return response.json();\n }).then(function (data) {\n if (data.success) {\n _this4.selectedRequirement = null;\n\n _this4.loadRequirements();\n }\n });\n },\n removeRequirement: function removeRequirement(challenge_id) {\n var _this5 = this;\n\n this.requirements.prerequisites = this.requirements.prerequisites.filter(function (val) {\n return val !== challenge_id;\n });\n var params = {\n requirements: this.requirements\n };\n\n _CTFd[\"default\"].fetch(\"/api/v1/challenges/\".concat(this.$props.challenge_id), {\n method: \"PATCH\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(params)\n }).then(function (response) {\n return response.json();\n }).then(function (data) {\n if (data.success) {\n _this5.loadRequirements();\n }\n });\n }\n },\n created: function created() {\n this.loadChallenges();\n this.loadRequirements();\n }\n};\nexports[\"default\"] = _default;\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/components/requirements/Requirements.vue?./node_modules/babel-loader/lib??ref--0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
@@ -847,7 +847,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/***/ (function(module, __webpack_exports__, __webpack_require__) {
;
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", [\n _c(\"table\", { staticClass: \"table table-striped text-center\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"tbody\",\n { attrs: { id: \"challenge-solves-body\" } },\n _vm._l(_vm.requirements.prerequisites, function(requirement) {\n return _c(\"tr\", { key: requirement }, [\n _c(\"td\", [_vm._v(_vm._s(_vm.getChallengeById(requirement).name))]),\n _vm._v(\" \"),\n _c(\"td\", [\n _c(\"i\", {\n staticClass: \"btn-fa fas fa-times delete-requirement\",\n attrs: { role: \"button\", \"challenge-id\": requirement },\n on: {\n click: function($event) {\n return _vm.removeRequirement(requirement)\n }\n }\n })\n ])\n ])\n }),\n 0\n )\n ]),\n _vm._v(\" \"),\n _c(\n \"form\",\n {\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.addRequirement($event)\n }\n }\n },\n [\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.selectedRequirement,\n expression: \"selectedRequirement\"\n }\n ],\n staticClass: \"form-control custom-select\",\n attrs: { name: \"prerequisite\" },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call($event.target.options, function(o) {\n return o.selected\n })\n .map(function(o) {\n var val = \"_value\" in o ? o._value : o.value\n return val\n })\n _vm.selectedRequirement = $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n }\n }\n },\n [\n _c(\"option\", { attrs: { value: \"\" } }, [_vm._v(\" -- \")]),\n _vm._v(\" \"),\n _vm._l(_vm.otherChallenges, function(challenge) {\n return _c(\n \"option\",\n { key: challenge.id, domProps: { value: challenge.id } },\n [\n _vm._v(\n \"\\n \" + _vm._s(challenge.name) + \"\\n \"\n )\n ]\n )\n })\n ],\n 2\n )\n ]),\n _vm._v(\" \"),\n _vm._m(1)\n ]\n )\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"thead\", [\n _c(\"tr\", [\n _c(\"td\", [_c(\"b\", [_vm._v(\"Requirement\")])]),\n _vm._v(\" \"),\n _c(\"td\", [_c(\"b\", [_vm._v(\"Settings\")])])\n ])\n ])\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"button\", { staticClass: \"btn btn-success float-right\" }, [\n _vm._v(\"Add Prerequisite\")\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/components/requirements/Requirements.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", [\n _c(\"table\", { staticClass: \"table table-striped text-center\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"tbody\",\n { attrs: { id: \"challenge-solves-body\" } },\n _vm._l(_vm.requirements.prerequisites, function(requirement) {\n return _c(\"tr\", { key: requirement }, [\n _c(\"td\", [_vm._v(_vm._s(_vm.getChallengeById(requirement).name))]),\n _vm._v(\" \"),\n _c(\"td\", [\n _c(\"i\", {\n staticClass: \"btn-fa fas fa-times delete-requirement\",\n attrs: { role: \"button\", \"challenge-id\": requirement },\n on: {\n click: function($event) {\n return _vm.removeRequirement(requirement)\n }\n }\n })\n ])\n ])\n }),\n 0\n )\n ]),\n _vm._v(\" \"),\n _c(\n \"form\",\n {\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.addRequirement($event)\n }\n }\n },\n [\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.selectedRequirement,\n expression: \"selectedRequirement\"\n }\n ],\n staticClass: \"form-control custom-select\",\n attrs: { name: \"prerequisite\" },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call($event.target.options, function(o) {\n return o.selected\n })\n .map(function(o) {\n var val = \"_value\" in o ? o._value : o.value\n return val\n })\n _vm.selectedRequirement = $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n }\n }\n },\n [\n _c(\"option\", { attrs: { value: \"\" } }, [_vm._v(\" -- \")]),\n _vm._v(\" \"),\n _vm._l(_vm.otherChallenges, function(challenge) {\n return _c(\n \"option\",\n { key: challenge.id, domProps: { value: challenge.id } },\n [\n _vm._v(\n \"\\n \" + _vm._s(challenge.name) + \"\\n \"\n )\n ]\n )\n })\n ],\n 2\n )\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\n \"button\",\n {\n staticClass: \"btn btn-success float-right\",\n attrs: { disabled: !_vm.selectedRequirement }\n },\n [_vm._v(\"\\n Add Prerequisite\\n \")]\n )\n ])\n ]\n )\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"thead\", [\n _c(\"tr\", [\n _c(\"td\", [_c(\"b\", [_vm._v(\"Requirement\")])]),\n _vm._v(\" \"),\n _c(\"td\", [_c(\"b\", [_vm._v(\"Settings\")])])\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./CTFd/themes/admin/assets/js/components/requirements/Requirements.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
diff --git a/CTFd/themes/admin/static/js/components.min.js b/CTFd/themes/admin/static/js/components.min.js
index ea0d3791..e4af15ee 100644
--- a/CTFd/themes/admin/static/js/components.min.js
+++ b/CTFd/themes/admin/static/js/components.min.js
@@ -1 +1 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{"./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue":function(e,t,s){s.r(t);var n,i=s("./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=template&id=1fd2c08a&scoped=true&"),a=s("./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=script&lang=js&");for(n in a)"default"!==n&&function(e){s.d(t,e,function(){return a[e]})}(n);s("./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=style&index=0&id=1fd2c08a&scoped=true&lang=css&");var o=s("./node_modules/vue-loader/lib/runtime/componentNormalizer.js"),l=Object(o.a)(a.default,i.a,i.b,!1,null,"1fd2c08a",null);l.options.__file="CTFd/themes/admin/assets/js/components/comments/CommentBox.vue",t.default=l.exports},"./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=script&lang=js&":function(e,t,s){s.r(t);var n,i=s("./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=script&lang=js&"),a=s.n(i);for(n in i)"default"!==n&&function(e){s.d(t,e,function(){return i[e]})}(n);t.default=a.a},"./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=style&index=0&id=1fd2c08a&scoped=true&lang=css&":function(e,t,s){var n=s("./node_modules/vue-style-loader/index.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/vue-loader/lib/index.js?!./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=style&index=0&id=1fd2c08a&scoped=true&lang=css&");s.n(n).a},"./CTFd/themes/admin/assets/js/components/comments/CommentBox.vue?vue&type=template&id=1fd2c08a&scoped=true&":function(e,t,s){function n(){var s=this,e=s.$createElement,n=s._self._c||e;return n("div",[n("div",{staticClass:"row mb-3"},[n("div",{staticClass:"col-md-12"},[n("div",{staticClass:"comment"},[n("textarea",{directives:[{name:"model",rawName:"v-model.lazy",value:s.comment,expression:"comment",modifiers:{lazy:!0}}],staticClass:"form-control mb-2",attrs:{rows:"2",id:"comment-input",placeholder:"Add comment"},domProps:{value:s.comment},on:{change:function(e){s.comment=e.target.value}}}),s._v(" "),n("button",{staticClass:"btn btn-sm btn-success btn-outlined float-right",attrs:{type:"submit"},on:{click:function(e){return s.submitComment()}}},[s._v("\n Comment\n ")])])])]),s._v(" "),1>>\n ")])])]),s._v(" "),n("div",{staticClass:"col-md-12"},[n("div",{staticClass:"text-center"},[n("small",{staticClass:"text-muted"},[s._v("Page "+s._s(s.page)+" of "+s._s(s.total)+" comments")])])])]):s._e(),s._v(" "),n("div",{staticClass:"comments"},[n("transition-group",{attrs:{name:"comment-card"}},s._l(s.comments,function(t){return n("div",{key:t.id,staticClass:"comment-card card mb-2"},[n("div",{staticClass:"card-body pl-0 pb-0 pt-2 pr-2"},[n("button",{staticClass:"close float-right",attrs:{type:"button","aria-label":"Close"},on:{click:function(e){return s.deleteComment(t.id)}}},[n("span",{attrs:{"aria-hidden":"true"}},[s._v("×")])])]),s._v(" "),n("div",{staticClass:"card-body"},[n("div",{staticClass:"card-text",domProps:{innerHTML:s._s(t.html)}}),s._v(" "),n("small",{staticClass:"text-muted float-left"},[n("span",[n("a",{attrs:{href:s.urlRoot+"/admin/users/"+t.author_id}},[s._v(s._s(t.author.name))])])]),s._v(" "),n("small",{staticClass:"text-muted float-right"},[n("span",{staticClass:"float-right"},[s._v(s._s(s.toLocalTime(t.date)))])])])])}),0)],1),s._v(" "),1>>\n ")])])]),s._v(" "),n("div",{staticClass:"col-md-12"},[n("div",{staticClass:"text-center"},[n("small",{staticClass:"text-muted"},[s._v("Page "+s._s(s.page)+" of "+s._s(s.total)+" comments")])])])]):s._e()])}var i=[];n._withStripped=!0,s.d(t,"a",function(){return n}),s.d(t,"b",function(){return i})},"./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue":function(e,t,s){s.r(t);var n,i=s("./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue?vue&type=template&id=30e0f744&scoped=true&"),a=s("./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue?vue&type=script&lang=js&");for(n in a)"default"!==n&&function(e){s.d(t,e,function(){return a[e]})}(n);var o=s("./node_modules/vue-loader/lib/runtime/componentNormalizer.js"),l=Object(o.a)(a.default,i.a,i.b,!1,null,"30e0f744",null);l.options.__file="CTFd/themes/admin/assets/js/components/configs/fields/Field.vue",t.default=l.exports},"./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue?vue&type=script&lang=js&":function(e,t,s){s.r(t);var n,i=s("./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue?vue&type=script&lang=js&"),a=s.n(i);for(n in i)"default"!==n&&function(e){s.d(t,e,function(){return i[e]})}(n);t.default=a.a},"./CTFd/themes/admin/assets/js/components/configs/fields/Field.vue?vue&type=template&id=30e0f744&scoped=true&":function(e,t,s){function n(){var o=this,e=o.$createElement,t=o._self._c||e;return t("div",{staticClass:"border-bottom"},[t("div",[t("button",{staticClass:"close float-right",attrs:{type:"button","aria-label":"Close"},on:{click:function(e){return o.deleteField()}}},[t("span",{attrs:{"aria-hidden":"true"}},[o._v("×")])])]),o._v(" "),t("div",{staticClass:"row"},[t("div",{staticClass:"col-md-3"},[t("div",{staticClass:"form-group"},[t("label",[o._v("Field Type")]),o._v(" "),t("select",{directives:[{name:"model",rawName:"v-model.lazy",value:o.field.field_type,expression:"field.field_type",modifiers:{lazy:!0}}],staticClass:"form-control custom-select",on:{change:function(e){var t=Array.prototype.filter.call(e.target.options,function(e){return e.selected}).map(function(e){return"_value"in e?e._value:e.value});o.$set(o.field,"field_type",e.target.multiple?t:t[0])}}},[t("option",{attrs:{value:"text"}},[o._v("Text Field")]),o._v(" "),t("option",{attrs:{value:"boolean"}},[o._v("Checkbox")])]),o._v(" "),t("small",{staticClass:"form-text text-muted"},[o._v("Type of field shown to the user")])])]),o._v(" "),t("div",{staticClass:"col-md-9"},[t("div",{staticClass:"form-group"},[t("label",[o._v("Field Name")]),o._v(" "),t("input",{directives:[{name:"model",rawName:"v-model.lazy",value:o.field.name,expression:"field.name",modifiers:{lazy:!0}}],staticClass:"form-control",attrs:{type:"text"},domProps:{value:o.field.name},on:{change:function(e){return o.$set(o.field,"name",e.target.value)}}}),o._v(" "),t("small",{staticClass:"form-text text-muted"},[o._v("Field name")])])]),o._v(" "),t("div",{staticClass:"col-md-12"},[t("div",{staticClass:"form-group"},[t("label",[o._v("Field Description")]),o._v(" "),t("input",{directives:[{name:"model",rawName:"v-model.lazy",value:o.field.description,expression:"field.description",modifiers:{lazy:!0}}],staticClass:"form-control",attrs:{type:"text"},domProps:{value:o.field.description},on:{change:function(e){return o.$set(o.field,"description",e.target.value)}}}),o._v(" "),t("small",{staticClass:"form-text text-muted",attrs:{id:"emailHelp"}},[o._v("Field Description")])])]),o._v(" "),t("div",{staticClass:"col-md-12"},[t("div",{staticClass:"form-check"},[t("label",{staticClass:"form-check-label"},[t("input",{directives:[{name:"model",rawName:"v-model.lazy",value:o.field.editable,expression:"field.editable",modifiers:{lazy:!0}}],staticClass:"form-check-input",attrs:{type:"checkbox"},domProps:{checked:Array.isArray(o.field.editable)?-1"+_this.createForm+"").find("script").each(function(){eval((0,_jquery.default)(this).html())})},100)})},loadTypes:function(){var t=this;_CTFd.default.fetch("/api/v1/flags/types",{method:"GET"}).then(function(e){return e.json()}).then(function(e){t.types=e.data})},submitFlag:function(e){var t=this,s=(0,_jquery.default)(e.target).serializeJSON(!0);s.challenge=this.$props.challenge_id,_CTFd.default.fetch("/api/v1/flags",{method:"POST",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(s)}).then(function(e){return e.json()}).then(function(e){t.$emit("refreshFlags",t.$options.name)})}},created:function(){this.loadTypes()}};exports.default=_default},"./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./CTFd/themes/admin/assets/js/components/flags/FlagEditForm.vue?vue&type=script&lang=js&":function(module,exports,__webpack_require__){Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _jquery=_interopRequireDefault(__webpack_require__("./node_modules/jquery/dist/jquery.js")),_CTFd=_interopRequireDefault(__webpack_require__("./CTFd/themes/core/assets/js/CTFd.js")),_nunjucks=_interopRequireDefault(__webpack_require__("./node_modules/nunjucks/browser/nunjucks.js"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}var _default={name:"FlagEditForm",props:{flag_id:Number},data:function(){return{flag:{},editForm:""}},watch:{flag_id:{immediate:!0,handler:function(e){null!==e&&this.loadFlag()}}},methods:{loadFlag:function loadFlag(){var _this=this;_CTFd.default.fetch("/api/v1/flags/".concat(this.$props.flag_id),{method:"GET"}).then(function(e){return e.json()}).then(function(response){_this.flag=response.data;var editFormURL=_this.flag.templates.update;_jquery.default.get(_CTFd.default.config.urlRoot+editFormURL,function(template_data){var template=_nunjucks.default.compile(template_data);_this.editForm=template.render(_this.flag),_this.editForm.includes("