Add bulk user page actions

bulk-table-profile-actions
Kevin Chung 2020-05-02 14:23:15 -04:00
parent 5a9d79f2bb
commit c101204879
3 changed files with 180 additions and 130 deletions

View File

@ -189,80 +189,70 @@ function emailUser(event) {
}); });
} }
function deleteUserSubmission(event) { function deleteSelectedSubmissions(event, target) {
event.preventDefault(); let submissions;
const submission_id = $(this).attr("submission-id"); let type;
const submission_type = $(this).attr("submission-type"); let title;
const submission_challenge = $(this).attr("submission-challenge"); switch(target){
case "solves":
submissions = $("input[data-submission-type=correct]:checked");
type = "solve";
title = "Solves"
break;
case "fails":
submissions = $("input[data-submission-type=incorrect]:checked");
type = "fail";
title = "Fails"
break;
default:
break;
}
const body = "<span>Are you sure you want to delete <strong>{0}</strong> submission from <strong>{1}</strong> for <strong>{2}</strong>?</span>".format( let submissionIDs = submissions.map(function() {
htmlEntities(submission_type), return $(this).data("submission-id");
htmlEntities(USER_NAME), });
htmlEntities(submission_challenge) let target_string = submissionIDs.length === 1 ? type : (type + "s");
);
const row = $(this)
.parent()
.parent();
ezQuery({ ezQuery({
title: "Delete Submission", title: `Delete ${title}`,
body: body, body: `Are you sure you want to delete ${submissionIDs.length} ${target_string}?`,
success: function() { success: function() {
CTFd.fetch("/api/v1/submissions/" + submission_id, { const reqs = [];
method: "DELETE", for (var subId of submissionIDs) {
credentials: "same-origin", reqs.push(CTFd.api.delete_submission({ submissionId: subId }));
headers: { }
Accept: "application/json", Promise.all(reqs).then(responses => {
"Content-Type": "application/json" window.location.reload();
} });
})
.then(function(response) {
return response.json();
})
.then(function(response) {
if (response.success) {
row.remove();
}
});
} }
}); });
} }
function deleteUserAward(event) { function deleteSelectedAwards(event) {
event.preventDefault(); let awardIDs = $("input[data-award-id]:checked").map(function() {
const award_id = $(this).attr("award-id"); return $(this).data("award-id");
const award_name = $(this).attr("award-name"); });
let target = awardIDs.length === 1 ? "award" : "awards";
const body = "<span>Are you sure you want to delete the <strong>{0}</strong> award from <strong>{1}</strong>?".format(
htmlEntities(award_name),
htmlEntities(USER_NAME)
);
const row = $(this)
.parent()
.parent();
ezQuery({ ezQuery({
title: "Delete Award", title: `Delete Awards`,
body: body, body: `Are you sure you want to delete ${awardIDs.length} ${target}?`,
success: function() { success: function() {
CTFd.fetch("/api/v1/awards/" + award_id, { const reqs = [];
method: "DELETE", for (var awardID of awardIDs) {
credentials: "same-origin", let req = CTFd.fetch("/api/v1/awards/" + awardID, {
headers: { method: "DELETE",
Accept: "application/json", credentials: "same-origin",
"Content-Type": "application/json" headers: {
} Accept: "application/json",
}) "Content-Type": "application/json"
.then(function(response) {
return response.json();
})
.then(function(response) {
if (response.success) {
row.remove();
} }
}); });
reqs.push(req);
}
Promise.all(reqs).then(responses => {
window.location.reload();
});
} }
}); });
} }
@ -425,8 +415,18 @@ $(() => {
$("#user-mail-form").submit(emailUser); $("#user-mail-form").submit(emailUser);
$(".delete-submission").click(deleteUserSubmission); $("#solves-delete-button").click(function(e){
$(".delete-award").click(deleteUserAward); deleteSelectedSubmissions(e, "solves")
});
$("#fails-delete-button").click(function(e){
deleteSelectedSubmissions(e, "fails")
});
$("#awards-delete-button").click(function(e){
deleteSelectedAwards(e);
});
$(".correct-submission").click(correctUserSubmission); $(".correct-submission").click(correctUserSubmission);
$("#user-info-create-form").submit(createUser); $("#user-info-create-form").submit(createUser);

File diff suppressed because one or more lines are too long

View File

@ -197,23 +197,45 @@
<div class="tab-content min-vh-25" id="nav-tabContent"> <div class="tab-content min-vh-25" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-solves" role="tabpanel" aria-labelledby="nav-solves-tab"> <div class="tab-pane fade show active" id="nav-solves" role="tabpanel" aria-labelledby="nav-solves-tab">
<h3 class="text-center pt-5 d-block">Solves</h3>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<table class="table table-striped"> <div class="float-right pb-3">
<h3 class="text-center py-3 d-block">Solves</h3> <div class="btn-group" role="group">
<button type="button" class="btn btn-outline-danger" id="solves-delete-button">
<i class="btn-fa fas fa-trash-alt"></i>
</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped border">
<thead> <thead>
<tr> <tr>
<td class="text-center"><b>Challenge</b></td> <th class="border-right" data-checkbox>
<td class="text-center"><b>Submitted</b></td> <div class="form-check text-center">
<td class="text-center"><b>Category</b></td> <input type="checkbox" class="form-check-input" data-checkbox-all>&nbsp;
<td class="text-center"><b>Value</b></td> </div>
<td class="text-center"><b>Time</b></td> </th>
<td class="text-center"><b>Delete</b></td> <th class="sort-col text-center"><b>Challenge</b></th>
</tr> <th class="sort-col text-center"><b>Submitted</b></th>
<th class="sort-col text-center"><b>Category</b></th>
<th class="sort-col text-center"><b>Value</b></th>
<th class="sort-col text-center"><b>Time</b></th>
</tr>
</thead> </thead>
<tbody> <tbody>
{% for solve in solves %} {% for solve in solves %}
<tr class="chal-solve" data-href="{{ url_for("admin.challenges_detail", challenge_id=solve.challenge_id) }}"> <tr class="chal-solve" data-href="{{ url_for("admin.challenges_detail", challenge_id=solve.challenge_id) }}">
<td class="border-right" data-checkbox>
<div class="form-check text-center">
<input type="checkbox" class="form-check-input" value="{{ solve.id }}" data-submission-id="{{ solve.id }}"
data-submission-type="{{ solve.type }}"
data-submission-challenge="{{ solve.challenge.name }}">&nbsp;
</div>
</td>
<td class="text-center chal" id="{{ solve.challenge_id }}"> <td class="text-center chal" id="{{ solve.challenge_id }}">
<a href="{{ url_for("admin.challenges_detail", challenge_id=solve.challenge_id) }}"> <a href="{{ url_for("admin.challenges_detail", challenge_id=solve.challenge_id) }}">
{{ solve.challenge.name }} {{ solve.challenge.name }}
@ -225,13 +247,6 @@
<td class="text-center solve-time"> <td class="text-center solve-time">
<span data-time="{{ solve.date | isoformat }}"></span> <span data-time="{{ solve.date | isoformat }}"></span>
</td> </td>
<td class="text-center">
<span class="delete-submission" submission-id="{{ solve.id }}"
submission-type="{{ solve.type }}" submission-challenge="{{ solve.challenge.name }}" data-toggle="tooltip"
data-placement="top" title="Delete solve #{{ solve.id }}">
<i class="btn-fa fas fa-times"></i>
</span>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -241,66 +256,101 @@
</div> </div>
<div class="tab-pane fade" id="nav-wrong" role="tabpanel" aria-labelledby="nav-wrong-tab"> <div class="tab-pane fade" id="nav-wrong" role="tabpanel" aria-labelledby="nav-wrong-tab">
<h3 class="text-center pt-5 d-block">Fails</h3>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<table class="table table-striped"> <div class="float-right pb-3">
<h3 class="text-center py-3 d-block">Fails</h3> <div class="btn-group" role="group">
<thead> <button type="button" class="btn btn-outline-danger" id="fails-delete-button">
<tr> <i class="btn-fa fas fa-trash-alt"></i>
<td class="text-center"><b>Challenge</b></td> </button>
<td class="text-center"><b>Submitted</b></td> </div>
<td class="text-center"><b>Time</b></td> </div>
<td class="text-center"><b>Delete</b></td> </div>
</tr> </div>
</thead> <div class="row">
<tbody> <div class="col-md-12">
{% for fail in fails %} <table class="table table-striped border">
<tr class="chal-wrong" data-href="{{ url_for("admin.challenges_detail", challenge_id=fail.challenge_id) }}"> <thead>
<td class="text-center chal" id="{{ fail.challenge_id }}"> <tr>
<a href="{{ url_for("admin.challenges_detail", challenge_id=fail.challenge_id) }}"> <th class="border-right" data-checkbox>
{{ fail.challenge.name }} <div class="form-check text-center">
</a> <input type="checkbox" class="form-check-input" data-checkbox-all>&nbsp;
</td> </div>
<td class="flag" id="{{ fail.id }}"> </th>
<pre>{{ fail.provided }}</pre> <th class="sort-col text-center"><b>Challenge</b></th>
</td> <th class="sort-col text-center"><b>Submitted</b></th>
<td class="text-center solve-time"> <th class="sort-col text-center"><b>Time</b></th>
<span data-time="{{ fail.date | isoformat }}"></span> </tr>
</td> </thead>
<td class="text-center"> <tbody>
<a class="delete-submission" submission-id="{{ fail.id }}" {% for fail in fails %}
submission-type="{{ fail.type }}" submission-challenge="{{ fail.challenge.name }}" data-toggle="tooltip" <tr class="chal-wrong" data-href="{{ url_for("admin.challenges_detail", challenge_id=fail.challenge_id) }}">
data-placement="top" title="Delete fail #{{ fail.id }}"> <td class="border-right" data-checkbox>
<i class="fas fa-times"></i> <div class="form-check text-center">
</a> <input type="checkbox" class="form-check-input" value="{{ fail.id }}" data-submission-id="{{ fail.id }}"
</td> data-submission-type="{{ fail.type }}"
</tr> data-submission-challenge="{{ fail.challenge.name }}">&nbsp;
{% endfor %} </div>
</tbody> </td>
</table> <td class="text-center chal" id="{{ fail.challenge_id }}">
<a href="{{ url_for("admin.challenges_detail", challenge_id=fail.challenge_id) }}">
{{ fail.challenge.name }}
</a>
</td>
<td class="flag" id="{{ fail.id }}">
<pre>{{ fail.provided }}</pre>
</td>
<td class="text-center solve-time">
<span data-time="{{ fail.date | isoformat }}"></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
<div class="tab-pane fade" id="nav-awards" role="tabpanel" aria-labelledby="nav-awards-tab"> <div class="tab-pane fade" id="nav-awards" role="tabpanel" aria-labelledby="nav-awards-tab">
<h3 class="text-center pt-5 d-block">Awards</h3>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<table class="table table-striped"> <div class="float-right pb-3">
<h3 class="text-center py-3 d-block">Awards</h3> <div class="btn-group" role="group">
<button type="button" class="btn btn-outline-danger" id="awards-delete-button">
<i class="btn-fa fas fa-trash-alt"></i>
</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped border">
<thead> <thead>
<tr> <tr>
<td class="text-center"><b>Name</b></td> <th class="border-right" data-checkbox>
<td class="text-center"><b>Description</b></td> <div class="form-check text-center">
<td class="text-center"><b>Date</b></td> <input type="checkbox" class="form-check-input" data-checkbox-all>&nbsp;
<td class="text-center"><b>Value</b></td> </div>
<td class="text-center"><b>Category</b></td> </th>
<td class="text-center"><b>Icon</b></td> <th class="sort-col text-center"><b>Name</b></th>
<td class="text-center"><b>Delete</b></td> <th class="sort-col text-center"><b>Description</b></th>
</tr> <th class="sort-col text-center"><b>Date</b></th>
<th class="sort-col text-center"><b>Value</b></th>
<th class="sort-col text-center"><b>Category</b></th>
<th class="sort-col text-center"><b>Icon</b></th>
</tr>
</thead> </thead>
<tbody id="awards-body"> <tbody id="awards-body">
{% for award in awards %} {% for award in awards %}
<tr class="award-row"> <tr class="award-row">
<td class="border-right" data-checkbox>
<div class="form-check text-center">
<input type="checkbox" class="form-check-input" value="{{ award.id }}" data-award-id="{{ award.id }}" data-award-name="{{ award.name }}">&nbsp;
</div>
</td>
<td class="text-center chal" id="{{ award.id }}">{{ award.name }}</td> <td class="text-center chal" id="{{ award.id }}">{{ award.name }}</td>
<td class=""><pre>{{ award.description }}</pre></td> <td class=""><pre>{{ award.description }}</pre></td>
<td class="text-center solve-time"> <td class="text-center solve-time">
@ -308,15 +358,15 @@
</td> </td>
<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">{{ award.icon }}</td> <td class="text-center"> <i class="award-icon award-{{ award.icon }}"></i> {{ award.icon }}</td>
<td class="text-center"> <!-- <td class="text-center">
<span class="delete-award" data-toggle="tooltip" <span class="delete-award" data-toggle="tooltip"
data-placement="top" award-id="{{ award.id }}" award-name="{{ award.name }}" data-placement="top" award-id="{{ award.id }}" award-name="{{ award.name }}"
title="Delete award #{{ award.id }}"> title="Delete award #{{ award.id }}">
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</span> </span>
</td> </td> -->
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>