mirror of https://github.com/JohnHammond/CTFd.git
Add team mark missing
parent
76bd626c36
commit
a2e5aa4b9e
|
@ -2,7 +2,7 @@ import "./main";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import CTFd from "core/CTFd";
|
import CTFd from "core/CTFd";
|
||||||
import { htmlEntities } from "core/utils";
|
import { htmlEntities } from "core/utils";
|
||||||
import { ezQuery, ezBadge } from "core/ezq";
|
import { ezAlert, ezQuery, ezBadge } from "core/ezq";
|
||||||
import { createGraph, updateGraph } from "core/graphs";
|
import { createGraph, updateGraph } from "core/graphs";
|
||||||
|
|
||||||
function createTeam(event) {
|
function createTeam(event) {
|
||||||
|
@ -84,16 +84,16 @@ function deleteSelectedSubmissions(event, target) {
|
||||||
let submissions;
|
let submissions;
|
||||||
let type;
|
let type;
|
||||||
let title;
|
let title;
|
||||||
switch(target){
|
switch (target) {
|
||||||
case "solves":
|
case "solves":
|
||||||
submissions = $("input[data-submission-type=correct]:checked");
|
submissions = $("input[data-submission-type=correct]:checked");
|
||||||
type = "solve";
|
type = "solve";
|
||||||
title = "Solves"
|
title = "Solves";
|
||||||
break;
|
break;
|
||||||
case "fails":
|
case "fails":
|
||||||
submissions = $("input[data-submission-type=incorrect]:checked");
|
submissions = $("input[data-submission-type=incorrect]:checked");
|
||||||
type = "fail";
|
type = "fail";
|
||||||
title = "Fails"
|
title = "Fails";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -102,11 +102,13 @@ function deleteSelectedSubmissions(event, target) {
|
||||||
let submissionIDs = submissions.map(function() {
|
let submissionIDs = submissions.map(function() {
|
||||||
return $(this).data("submission-id");
|
return $(this).data("submission-id");
|
||||||
});
|
});
|
||||||
let target_string = submissionIDs.length === 1 ? type : (type + "s");
|
let target_string = submissionIDs.length === 1 ? type : type + "s";
|
||||||
|
|
||||||
ezQuery({
|
ezQuery({
|
||||||
title: `Delete ${title}`,
|
title: `Delete ${title}`,
|
||||||
body: `Are you sure you want to delete ${submissionIDs.length} ${target_string}?`,
|
body: `Are you sure you want to delete ${
|
||||||
|
submissionIDs.length
|
||||||
|
} ${target_string}?`,
|
||||||
success: function() {
|
success: function() {
|
||||||
const reqs = [];
|
const reqs = [];
|
||||||
for (var subId of submissionIDs) {
|
for (var subId of submissionIDs) {
|
||||||
|
@ -148,6 +150,62 @@ function deleteSelectedAwards(event) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function solveSelectedMissingChallenges(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let challengeIDs = $("input[data-missing-challenge-id]:checked").map(
|
||||||
|
function() {
|
||||||
|
return $(this).data("missing-challenge-id");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let target = challengeIDs.length === 1 ? "challenge" : "challenges";
|
||||||
|
|
||||||
|
ezQuery({
|
||||||
|
title: `Mark Correct`,
|
||||||
|
body: `Are you sure you want to mark ${
|
||||||
|
challengeIDs.length
|
||||||
|
} correct for ${htmlEntities(TEAM_NAME)}?`,
|
||||||
|
success: function() {
|
||||||
|
ezAlert({
|
||||||
|
title: `User Attribution`,
|
||||||
|
body: `
|
||||||
|
Which user on ${htmlEntities(TEAM_NAME)} solved these challenges?
|
||||||
|
<div class="pb-3" id="query-team-member-solve">
|
||||||
|
${$("#team-member-select").html()}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
button: "Mark Correct",
|
||||||
|
success: function() {
|
||||||
|
const USER_ID = $("#query-team-member-solve > select").val();
|
||||||
|
const reqs = [];
|
||||||
|
for (var challengeID of challengeIDs) {
|
||||||
|
let params = {
|
||||||
|
provided: "MARKED AS SOLVED BY ADMIN",
|
||||||
|
user_id: USER_ID,
|
||||||
|
team_id: TEAM_ID,
|
||||||
|
challenge_id: challengeID,
|
||||||
|
type: "correct"
|
||||||
|
};
|
||||||
|
|
||||||
|
let req = CTFd.fetch("/api/v1/submissions", {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(params)
|
||||||
|
});
|
||||||
|
reqs.push(req);
|
||||||
|
}
|
||||||
|
Promise.all(reqs).then(responses => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const api_funcs = {
|
const api_funcs = {
|
||||||
team: [
|
team: [
|
||||||
x => CTFd.api.get_team_solves({ teamId: x }),
|
x => CTFd.api.get_team_solves({ teamId: x }),
|
||||||
|
@ -403,18 +461,22 @@ $(() => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#solves-delete-button").click(function(e){
|
$("#solves-delete-button").click(function(e) {
|
||||||
deleteSelectedSubmissions(e, "solves")
|
deleteSelectedSubmissions(e, "solves");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#fails-delete-button").click(function(e){
|
$("#fails-delete-button").click(function(e) {
|
||||||
deleteSelectedSubmissions(e, "fails")
|
deleteSelectedSubmissions(e, "fails");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#awards-delete-button").click(function(e){
|
$("#awards-delete-button").click(function(e) {
|
||||||
deleteSelectedAwards(e);
|
deleteSelectedAwards(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#missing-solve-button").click(function(e) {
|
||||||
|
solveSelectedMissingChallenges(e);
|
||||||
|
});
|
||||||
|
|
||||||
$("#team-info-create-form").submit(createTeam);
|
$("#team-info-create-form").submit(createTeam);
|
||||||
|
|
||||||
$("#team-info-edit-form").submit(updateTeam);
|
$("#team-info-edit-form").submit(updateTeam);
|
||||||
|
|
|
@ -193,16 +193,16 @@ function deleteSelectedSubmissions(event, target) {
|
||||||
let submissions;
|
let submissions;
|
||||||
let type;
|
let type;
|
||||||
let title;
|
let title;
|
||||||
switch(target){
|
switch (target) {
|
||||||
case "solves":
|
case "solves":
|
||||||
submissions = $("input[data-submission-type=correct]:checked");
|
submissions = $("input[data-submission-type=correct]:checked");
|
||||||
type = "solve";
|
type = "solve";
|
||||||
title = "Solves"
|
title = "Solves";
|
||||||
break;
|
break;
|
||||||
case "fails":
|
case "fails":
|
||||||
submissions = $("input[data-submission-type=incorrect]:checked");
|
submissions = $("input[data-submission-type=incorrect]:checked");
|
||||||
type = "fail";
|
type = "fail";
|
||||||
title = "Fails"
|
title = "Fails";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -211,11 +211,13 @@ function deleteSelectedSubmissions(event, target) {
|
||||||
let submissionIDs = submissions.map(function() {
|
let submissionIDs = submissions.map(function() {
|
||||||
return $(this).data("submission-id");
|
return $(this).data("submission-id");
|
||||||
});
|
});
|
||||||
let target_string = submissionIDs.length === 1 ? type : (type + "s");
|
let target_string = submissionIDs.length === 1 ? type : type + "s";
|
||||||
|
|
||||||
ezQuery({
|
ezQuery({
|
||||||
title: `Delete ${title}`,
|
title: `Delete ${title}`,
|
||||||
body: `Are you sure you want to delete ${submissionIDs.length} ${target_string}?`,
|
body: `Are you sure you want to delete ${
|
||||||
|
submissionIDs.length
|
||||||
|
} ${target_string}?`,
|
||||||
success: function() {
|
success: function() {
|
||||||
const reqs = [];
|
const reqs = [];
|
||||||
for (var subId of submissionIDs) {
|
for (var subId of submissionIDs) {
|
||||||
|
@ -259,14 +261,18 @@ function deleteSelectedAwards(event) {
|
||||||
|
|
||||||
function solveSelectedMissingChallenges(event) {
|
function solveSelectedMissingChallenges(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let challengeIDs = $("input[data-missing-challenge-id]:checked").map(function() {
|
let challengeIDs = $("input[data-missing-challenge-id]:checked").map(
|
||||||
return $(this).data("missing-challenge-id");
|
function() {
|
||||||
});
|
return $(this).data("missing-challenge-id");
|
||||||
|
}
|
||||||
|
);
|
||||||
let target = challengeIDs.length === 1 ? "challenge" : "challenges";
|
let target = challengeIDs.length === 1 ? "challenge" : "challenges";
|
||||||
|
|
||||||
ezQuery({
|
ezQuery({
|
||||||
title: `Mark Correct`,
|
title: `Mark Correct`,
|
||||||
body: `Are you sure you want to mark ${challengeIDs.length} correct for ${htmlEntities(USER_NAME)}?`,
|
body: `Are you sure you want to mark ${
|
||||||
|
challengeIDs.length
|
||||||
|
} correct for ${htmlEntities(USER_NAME)}?`,
|
||||||
success: function() {
|
success: function() {
|
||||||
const reqs = [];
|
const reqs = [];
|
||||||
for (var challengeID of challengeIDs) {
|
for (var challengeID of challengeIDs) {
|
||||||
|
@ -286,7 +292,7 @@ function solveSelectedMissingChallenges(event) {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(params)
|
body: JSON.stringify(params)
|
||||||
})
|
});
|
||||||
reqs.push(req);
|
reqs.push(req);
|
||||||
}
|
}
|
||||||
Promise.all(reqs).then(responses => {
|
Promise.all(reqs).then(responses => {
|
||||||
|
@ -406,19 +412,19 @@ $(() => {
|
||||||
|
|
||||||
$("#user-mail-form").submit(emailUser);
|
$("#user-mail-form").submit(emailUser);
|
||||||
|
|
||||||
$("#solves-delete-button").click(function(e){
|
$("#solves-delete-button").click(function(e) {
|
||||||
deleteSelectedSubmissions(e, "solves")
|
deleteSelectedSubmissions(e, "solves");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#fails-delete-button").click(function(e){
|
$("#fails-delete-button").click(function(e) {
|
||||||
deleteSelectedSubmissions(e, "fails")
|
deleteSelectedSubmissions(e, "fails");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#awards-delete-button").click(function(e){
|
$("#awards-delete-button").click(function(e) {
|
||||||
deleteSelectedAwards(e);
|
deleteSelectedAwards(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#missing-solve-button").click(function(e){
|
$("#missing-solve-button").click(function(e) {
|
||||||
solveSelectedMissingChallenges(e);
|
solveSelectedMissingChallenges(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -61,6 +61,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<template id="team-member-select">
|
||||||
|
<select class="form-control custom-select">
|
||||||
|
<option value=""> -- </option>
|
||||||
|
{% for member in members %}
|
||||||
|
<option value="{{ member.id }}">{{ member.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div id="team-addresses-modal" class="modal fade">
|
<div id="team-addresses-modal" class="modal fade">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
@ -235,6 +244,9 @@
|
||||||
|
|
||||||
<a class="nav-item nav-link" id="nav-awards-tab" data-toggle="tab" href="#nav-awards" role="tab"
|
<a class="nav-item nav-link" id="nav-awards-tab" data-toggle="tab" href="#nav-awards" role="tab"
|
||||||
aria-controls="nav-awards" aria-selected="false">Awards</a>
|
aria-controls="nav-awards" aria-selected="false">Awards</a>
|
||||||
|
|
||||||
|
<a class="nav-item nav-link" id="nav-missing-tab" data-toggle="tab" href="#nav-missing" role="tab"
|
||||||
|
aria-controls="nav-missing" aria-selected="false">Missing</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="tab-content min-vh-50" id="nav-tabContent">
|
<div class="tab-content min-vh-50" id="nav-tabContent">
|
||||||
|
@ -424,6 +436,58 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="nav-missing" role="tabpanel" aria-labelledby="nav-missing-tab">
|
||||||
|
<h3 class="text-center pt-5 d-block">Missing</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="float-right pb-3">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<button type="button" class="btn btn-outline-success" id="missing-solve-button">
|
||||||
|
<i class="btn-fa fas fa-check"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<table class="table table-striped border">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="border-right" data-checkbox>
|
||||||
|
<div class="form-check text-center">
|
||||||
|
<input type="checkbox" class="form-check-input" data-checkbox-all>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th class="sort-col text-center"><b>Challenge</b></th>
|
||||||
|
<th class="sort-col text-center"><b>Category</b></th>
|
||||||
|
<th class="sort-col text-center"><b>Value</b></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for challenge in missing %}
|
||||||
|
<tr class="chal-solve" data-href="{{ url_for("admin.challenges_detail", challenge_id=challenge.id) }}">
|
||||||
|
<td class="border-right" data-checkbox>
|
||||||
|
<div class="form-check text-center">
|
||||||
|
<input type="checkbox" class="form-check-input" value="{{ challenge.id }}" data-missing-challenge-id="{{ challenge.id }}"
|
||||||
|
data-missing-challenge-name="{{ challenge.name }}">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-center chal" id="{{ challenge.id }}">
|
||||||
|
<a href="{{ url_for("admin.challenges_detail", challenge_id=challenge.id) }}">
|
||||||
|
{{ challenge.name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ challenge.category }}</td>
|
||||||
|
<td class="text-center">{{ challenge.value }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -359,14 +359,6 @@
|
||||||
<td class="text-center">{{ award.value }}</td>
|
<td class="text-center">{{ award.value }}</td>
|
||||||
<td class="text-center">{{ award.category }}</td>
|
<td class="text-center">{{ award.category }}</td>
|
||||||
<td class="text-center"> <i class="award-icon award-{{ award.icon }}"></i> {{ award.icon }}</td>
|
<td class="text-center"> <i class="award-icon award-{{ award.icon }}"></i> {{ award.icon }}</td>
|
||||||
|
|
||||||
<!-- <td class="text-center">
|
|
||||||
<span class="delete-award" data-toggle="tooltip"
|
|
||||||
data-placement="top" award-id="{{ award.id }}" award-name="{{ award.name }}"
|
|
||||||
title="Delete award #{{ award.id }}">
|
|
||||||
<i class="fas fa-times"></i>
|
|
||||||
</span>
|
|
||||||
</td> -->
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -419,13 +411,6 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">{{ challenge.category }}</td>
|
<td class="text-center">{{ challenge.category }}</td>
|
||||||
<td class="text-center">{{ challenge.value }}</td>
|
<td class="text-center">{{ challenge.value }}</td>
|
||||||
<!-- <td class="text-center">
|
|
||||||
<a class="correct-submission" data-toggle="tooltip" challenge-id="{{ challenge.id }}"
|
|
||||||
challenge-name="{{ challenge.name }}"
|
|
||||||
data-placement="top" title="Mark {{ challenge.name }} correct for {{ user.name }}">
|
|
||||||
<i class="fas fa-check"></i>
|
|
||||||
</a>
|
|
||||||
</td> -->
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue