From 7e215ec523a6d047bb2dedb7665602dced3a56a9 Mon Sep 17 00:00:00 2001 From: LpCote <73721863+LpCote4@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:14:46 -0500 Subject: [PATCH] feat: sport challenge value modification in admin --- CTFd/api/v1/submissions.py | 43 +++++++++++++------ .../admin/assets/js/pages/submissions.js | 32 ++++++++++++++ .../assets/pages/submissions.0ab48ae1.js | 1 + .../assets/pages/submissions.a169d18d.js | 1 - CTFd/themes/admin/static/manifest.json | 28 +++++++----- CTFd/themes/admin/templates/submissions.html | 8 ++++ 6 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 CTFd/themes/admin/static/assets/pages/submissions.0ab48ae1.js delete mode 100644 CTFd/themes/admin/static/assets/pages/submissions.a169d18d.js diff --git a/CTFd/api/v1/submissions.py b/CTFd/api/v1/submissions.py index 6412ebb1..3ef00066 100644 --- a/CTFd/api/v1/submissions.py +++ b/CTFd/api/v1/submissions.py @@ -180,21 +180,38 @@ class Submission(Resource): return {"success": True, "data": response.data} - @admins_only - @submissions_namespace.doc( - description="Endpoint to edit a submission object", - responses={ - 200: ("Success", "SubmissionDetailedSuccessResponse"), - 400: ( - "Une erreur s'est produite en traitant des données fournies ou stockées", - "APISimpleErrorResponse", - ), - }, - ) + # @admins_only + # @submissions_namespace.doc( + # description="Endpoint to edit a submission object", + # responses={ + # 200: ("Success", "SubmissionDetailedSuccessResponse"), + # 400: ( + # "Une erreur s'est produite en traitant des données fournies ou stockées", + # "APISimpleErrorResponse", + # ), + # }, + # ) def patch(self, submission_id): - submission = Submissions.query.filter_by(id=submission_id).first_or_404() - req = request.get_json() + new_value = req.get("value") + submission = Submissions.query.filter_by(id=submission_id).first_or_404() + + #Patching value of submission + if new_value is not None: + try: + new_value = int(new_value) # Ensure the value is numeric + submission.value = new_value + db.session.commit() + + return { + "success": True, + "data": {"id": submission.id, "value": submission.value}, + } + except ValueError: + return {"success": False, "error": "Value must be a number"}, 400 + + + #Changing submission to Solve submission_type = req.get("type") print("\n\nsubmissions/patch...") diff --git a/CTFd/themes/admin/assets/js/pages/submissions.js b/CTFd/themes/admin/assets/js/pages/submissions.js index 2655b6ae..fb6764b1 100644 --- a/CTFd/themes/admin/assets/js/pages/submissions.js +++ b/CTFd/themes/admin/assets/js/pages/submissions.js @@ -157,6 +157,37 @@ function copyFlag(event) { }, 1500); } +function updateValue(event) { + const target = $(event.target).closest("[data-submission-id]"); // Look for the closest parent with data attribute + const submissionId = target.data("submission-id"); + + if (!submissionId) { + alert("Submission ID is not defined."); + return; + } + const currentValue = $(event.target).text(); // Get the current text value + const newValue = prompt("Enter the new value for the submission:", currentValue); // Prompt for a new value + + if (newValue !== null && newValue.trim() !== "") { + // Send a PATCH request to update the submission value + CTFd.fetch(`/api/v1/submissions/${submissionId}`, { + method: "PATCH", + credentials: "same-origin", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify({ value: newValue.trim() }), + }).then(function (response) { + if (response.success) { + window.location.reload(); + } + }); + } else { + alert("Invalid input. Update canceled."); + } +} + $(() => { $("#show-full-flags-button").click(showFlagsToggle); $("#show-short-flags-button").click(showFlagsToggle); @@ -165,6 +196,7 @@ $(() => { $("#correct-flags-button").click(correctSubmissions); $(".delete-correct-submission").click(deleteCorrectSubmission); $("#submission-delete-button").click(deleteSelectedSubmissions); + $(".submission-value").click(updateValue); }); let elements = document.getElementsByClassName("imageContainer"); for (let i = 0; i < elements.length; i++) { diff --git a/CTFd/themes/admin/static/assets/pages/submissions.0ab48ae1.js b/CTFd/themes/admin/static/assets/pages/submissions.0ab48ae1.js new file mode 100644 index 00000000..aeff45ba --- /dev/null +++ b/CTFd/themes/admin/static/assets/pages/submissions.0ab48ae1.js @@ -0,0 +1 @@ +import{$ as e,u as c,z as u,C as l,B as f}from"./main.a9ca099a.js";import{s as p}from"../visual.09506247.js";window.carouselPosition=0;window.carouselMax=0;function h(i){const t=e(this).data("submission-id"),n=e(this).parent().parent(),s=n.find(".chal").text().trim(),a=n.find(".team").text().trim(),o=e(this).parent().parent();c({title:"Supprimer soumission",body:"\xCAtes-vous certain de vouloir supprimer la soumission de l'\xE9quipe {0} pour le d\xE9fi {1}".format("<strong>"+u(a)+"</strong>","<strong>"+u(s)+"</strong>"),success:function(){alert({submissionId:t}),l.api.delete_submission({submissionId:t}).then(function(r){r.success&&o.remove()})}})}function g(i){let t=e("input[data-submission-id]:checked").map(function(){return e(this).data("submission-id")}),n=t.length===1?"submission":"submissions";c({title:"Supprimer une soumission",body:`\xCAtes-vous certain de vouloir supprimer ${t.length} ${n}?`,success:function(){const s=[];for(var a of t)s.push(l.api.delete_submission({submissionId:a}));Promise.all(s).then(o=>{window.location.reload()})}})}function b(i){let t=e("input[data-submission-id]:checked").map(function(){return e(this).data("submission-id")}).get(),n=t.length===1?"submission":"submissions",s=[];c({title:"Valider une soumission",body:`\xCAtes-vous s\xFBr de vouloir marquer ${t.length} ${n} correct?`,success:function(){const a=t.map(o=>l.fetch(`/api/v1/submissions/${o}`,{method:"GET",credentials:"same-origin",headers:{Accept:"application/json"}}).then(r=>r.json()).then(r=>{r.data.provided!=="M\xE9dia en traitement"?s.push(o):f({title:"Erreur",body:`Soumission ID ${o} ne peut \xEAtre marqu\xE9e comme correcte car le media est encore en traitement.`,button:"OK"})}));Promise.all(a).then(()=>{if(s.length>0){const o=s.map(r=>l.fetch(`/api/v1/submissions/${r}`,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({type:"correct"})}));Promise.all(o).then(()=>{window.location.reload()})}})}})}function m(i){const t=new URLSearchParams(window.location.search);t.has("full")?t.delete("full"):t.set("full","true"),window.location.href=`${window.location.pathname}?${t.toString()}`}function w(i){let t=e(i.currentTarget),n=t.find("i"),s=t.parent().find("pre");s.hasClass("full-flag")?(s.text(s.attr("title").substring(0,42)+"..."),s.removeClass("full-flag"),n.addClass("fa-eye"),n.removeClass("fa-eye-slash")):(s.text(s.attr("title")),s.addClass("full-flag"),n.addClass("fa-eye-slash"),n.removeClass("fa-eye"))}function v(i){let s=e(i.currentTarget).parent().find("pre").attr("title");navigator.clipboard.writeText(s),e(i.currentTarget).tooltip({title:"Copi\xE9!",trigger:"manual"}),e(i.currentTarget).tooltip("show"),setTimeout(function(){e(i.currentTarget).tooltip("hide")},1500)}function y(i){const n=e(i.target).closest("[data-submission-id]").data("submission-id");if(!n){alert("Submission ID is not defined.");return}const s=e(i.target).text(),a=prompt("Enter the new value for the submission:",s);a!==null&&a.trim()!==""?l.fetch(`/api/v1/submissions/${n}`,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({value:a.trim()})}).then(function(o){o.success&&window.location.reload()}):alert("Invalid input. Update canceled.")}e(()=>{e("#show-full-flags-button").click(m),e("#show-short-flags-button").click(m),e(".show-flag").click(w),e(".copy-flag").click(v),e("#correct-flags-button").click(b),e(".delete-correct-submission").click(h),e("#submission-delete-button").click(g),e(".submission-value").click(y)});let d=document.getElementsByClassName("imageContainer");for(let i=0;i<d.length;i++)p(d[i]); diff --git a/CTFd/themes/admin/static/assets/pages/submissions.a169d18d.js b/CTFd/themes/admin/static/assets/pages/submissions.a169d18d.js deleted file mode 100644 index c89b3d3c..00000000 --- a/CTFd/themes/admin/static/assets/pages/submissions.a169d18d.js +++ /dev/null @@ -1 +0,0 @@ -import{$ as e,u as c,z as u,C as l,B as f}from"./main.a9ca099a.js";import{s as p}from"../visual.09506247.js";window.carouselPosition=0;window.carouselMax=0;function h(i){const t=e(this).data("submission-id"),o=e(this).parent().parent(),s=o.find(".chal").text().trim(),r=o.find(".team").text().trim(),n=e(this).parent().parent();c({title:"Supprimer soumission",body:"\xCAtes-vous certain de vouloir supprimer la soumission de l'\xE9quipe {0} pour le d\xE9fi {1}".format("<strong>"+u(r)+"</strong>","<strong>"+u(s)+"</strong>"),success:function(){alert({submissionId:t}),l.api.delete_submission({submissionId:t}).then(function(a){a.success&&n.remove()})}})}function g(i){let t=e("input[data-submission-id]:checked").map(function(){return e(this).data("submission-id")}),o=t.length===1?"submission":"submissions";c({title:"Supprimer une soumission",body:`\xCAtes-vous certain de vouloir supprimer ${t.length} ${o}?`,success:function(){const s=[];for(var r of t)s.push(l.api.delete_submission({submissionId:r}));Promise.all(s).then(n=>{window.location.reload()})}})}function b(i){let t=e("input[data-submission-id]:checked").map(function(){return e(this).data("submission-id")}).get(),o=t.length===1?"submission":"submissions",s=[];c({title:"Valider une soumission",body:`\xCAtes-vous s\xFBr de vouloir marquer ${t.length} ${o} correct?`,success:function(){const r=t.map(n=>l.fetch(`/api/v1/submissions/${n}`,{method:"GET",credentials:"same-origin",headers:{Accept:"application/json"}}).then(a=>a.json()).then(a=>{a.data.provided!=="M\xE9dia en traitement"?s.push(n):f({title:"Erreur",body:`Soumission ID ${n} ne peut \xEAtre marqu\xE9e comme correcte car le media est encore en traitement.`,button:"OK"})}));Promise.all(r).then(()=>{if(s.length>0){const n=s.map(a=>l.fetch(`/api/v1/submissions/${a}`,{method:"PATCH",credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({type:"correct"})}));Promise.all(n).then(()=>{window.location.reload()})}})}})}function m(i){const t=new URLSearchParams(window.location.search);t.has("full")?t.delete("full"):t.set("full","true"),window.location.href=`${window.location.pathname}?${t.toString()}`}function w(i){let t=e(i.currentTarget),o=t.find("i"),s=t.parent().find("pre");s.hasClass("full-flag")?(s.text(s.attr("title").substring(0,42)+"..."),s.removeClass("full-flag"),o.addClass("fa-eye"),o.removeClass("fa-eye-slash")):(s.text(s.attr("title")),s.addClass("full-flag"),o.addClass("fa-eye-slash"),o.removeClass("fa-eye"))}function v(i){let s=e(i.currentTarget).parent().find("pre").attr("title");navigator.clipboard.writeText(s),e(i.currentTarget).tooltip({title:"Copi\xE9!",trigger:"manual"}),e(i.currentTarget).tooltip("show"),setTimeout(function(){e(i.currentTarget).tooltip("hide")},1500)}e(()=>{e("#show-full-flags-button").click(m),e("#show-short-flags-button").click(m),e(".show-flag").click(w),e(".copy-flag").click(v),e("#correct-flags-button").click(b),e(".delete-correct-submission").click(h),e("#submission-delete-button").click(g)});let d=document.getElementsByClassName("imageContainer");for(let i=0;i<d.length;i++)p(d[i]); diff --git a/CTFd/themes/admin/static/manifest.json b/CTFd/themes/admin/static/manifest.json index c79f9b3a..c4c48089 100644 --- a/CTFd/themes/admin/static/manifest.json +++ b/CTFd/themes/admin/static/manifest.json @@ -87,7 +87,7 @@ ] }, "assets/js/pages/submissions.js": { - "file": "assets/pages/submissions.a169d18d.js", + "file": "assets/pages/submissions.0ab48ae1.js", "src": "assets/js/pages/submissions.js", "isEntry": true, "imports": [ @@ -153,8 +153,8 @@ "assets/CommentBox.23213b39.css" ] }, - "_htmlmixed.3b26375a.js": { - "file": "assets/htmlmixed.3b26375a.js", + "_htmlmixed.5f06a96a.js": { + "file": "assets/htmlmixed.5f06a96a.js", "imports": [ "assets/js/pages/main.js" ] @@ -178,24 +178,24 @@ "_echarts.common.27787dd0.js" ] }, - "assets/css/challenge-board.scss": { - "file": "assets/challenge-board.44e07e05.css", - "src": "assets/css/challenge-board.scss", - "isEntry": true + "assets/js/pages/challenge.css": { + "file": "assets/challenge.66ec3ebe.css", + "src": "assets/js/pages/challenge.css" }, "CommentBox.css": { "file": "assets/CommentBox.23213b39.css", "src": "CommentBox.css" }, + "assets/css/challenge-board.scss": { + "file": "assets/challenge-board.44e07e05.css", + "src": "assets/css/challenge-board.scss", + "isEntry": true + }, "assets/css/admin.scss": { "file": "assets/admin.3594ea3f.css", "src": "assets/css/admin.scss", "isEntry": true }, - "assets/js/pages/challenge.css": { - "file": "assets/challenge.66ec3ebe.css", - "src": "assets/js/pages/challenge.css" - }, "assets/css/codemirror.scss": { "file": "assets/codemirror.d74a88bc.css", "src": "assets/css/codemirror.scss", @@ -210,5 +210,11 @@ "file": "assets/main.088f55c6.css", "src": "assets/css/main.scss", "isEntry": true + }, + "_htmlmixed.3b26375a.js": { + "file": "assets/htmlmixed.3b26375a.js", + "imports": [ + "assets/js/pages/main.js" + ] } } \ No newline at end of file diff --git a/CTFd/themes/admin/templates/submissions.html b/CTFd/themes/admin/templates/submissions.html index 972c96fe..30405fd4 100644 --- a/CTFd/themes/admin/templates/submissions.html +++ b/CTFd/themes/admin/templates/submissions.html @@ -88,6 +88,7 @@ <th class="sort-col"><b>Défi</b></th> <th class="sort-col"><b>Type</b></th> <th class="sort-col"><b>Fourni</b></th> + <th class="sort-col"><b>Valeur</b></th> <th class="text-center sort-col"><b>Date</b></th> </tr> </thead> @@ -130,6 +131,13 @@ <pre class="mb-0 pl-2 float-left imageContainer" id="{{sub.provided}}" title=""></pre> {% endif %} </td> + <td {% if sub.value %} style="color:blue;" class="submission-value" data-submission-id="{{ sub.id }}"{% endif %}> + {% if sub.value %} + {{ sub.value }} + {% else %} + {{ sub.challenge.value }} + {% endif %} + </td> <td class="text-center solve-time"> <span data-time="{{ sub.date | isoformat }}"></span> </td> -- GitLab