server/frontend/fic/src/lib/components/ExerciceFlags.svelte

229 lines
7.2 KiB
Svelte

<script>
import {
Button,
Card,
CardBody,
CardHeader,
CardText,
Icon,
ListGroup,
ListGroupItem,
Progress,
Spinner,
Tooltip,
} from '@sveltestrap/sveltestrap';
import { blake2b } from 'hash-wasm';
import { my } from '$lib/stores/my.js';
import { settings } from '$lib/stores/settings.js';
import { timeouted, waitDiff, waitInProgress } from '$lib/wait.js';
import DateFormat from './DateFormat.svelte';
import FlagKey from './FlagKey.svelte';
import FlagMCQ from './FlagMCQ.svelte';
export let exercice = { };
export let flags = [];
export let readonly = false;
export let forcesolved = false;
let responses = { };
async function submitFlags() {
waitInProgress.set(true);
sberr = "";
message = "";
if ($my && $my.team_id === 0) {
let allGoodResponse = true;
for (const f in flags) {
const flag = flags[f];
let soluce = "";
if (flag.type == "mcq") {
for (const c in flag.choices) {
soluce += responses.mcqs[c] ? "t" : "f";
}
} else {
soluce = responses.flags[flag.id];
}
if (flag.ignore_case) {
soluce = soluce.toLowerCase();
}
if (flag.capture_regexp) {
let re = new RegExp(flag.capture_regexp, flag.ignore_case?'i':'');
soluce = soluce.match(re).slice(1).join("+");
}
if (await blake2b(soluce) == flag.soluce) {
flags[f].found = new Date();
} else if (!flag.found) {
allGoodResponse = false;
}
flags = flags;
}
if (allGoodResponse) {
forcesolved = true;
}
if (exercice.tries) {
exercice.tries += 1;
} else {
exercice.tries = 1;
}
exercice.solved_time = new Date();
exercice = exercice;
waitInProgress.set(false);
} else {
const response = await fetch(
"submit/" + exercice.id,
{
method: "POST",
headers: {'Accept': 'application/json'},
body: JSON.stringify(responses),
}
)
if (response.status < 300) {
const data = await response.json();
messageClass = 'text-success';
message = data.errmsg;
waitDiff(13, exercice);
} else {
waitInProgress.set(false);
messageClass = 'text-danger';
let data = "";
try {
data = await response.json();
} catch(e) {
data = null;
}
if (data && data.errmsg)
message = data.errmsg;
if (response.statys != 402)
sberr = "Oups !";
}
}
}
function resetResponses() {
responses = {
flags: { },
mcqs: { },
justifications: { },
};
}
let last_exercice = null;
$: {
if (!last_exercice || last_exercice != exercice.id) {
last_exercice = exercice.id;
resetResponses()
}
}
let sberr = "";
let message = "";
let messageClass = "text-danger";
</script>
<Card class="border-danger mb-2">
<CardHeader class="bg-danger text-light">
<Icon name="flag-fill" />
Faire son rapport
</CardHeader>
{#if exercice.flags.length != exercice.nb_flags}
<Progress
value={exercice.flags.filter((f) => f.type !== undefined).length}
max={exercice.nb_flags}
class="rounded-0"
barClassName="text-light"
>
{exercice.flags.filter((f) => f.type !== undefined).length}/{exercice.nb_flags}
</Progress>
{/if}
{#if exercice.tries || exercice.solved_time || exercice.submitted || sberr || $timeouted}
<ListGroup class="border-dark">
{#if exercice.solved_time || exercice.tries}
<ListGroupItem class="text-warning rounded-0">
{#if exercice.tries > 0}{exercice.tries} {exercice.tries==1?"tentative effectuée":"tentatives effectuées"}.{/if}
Dernière solution envoyée à <DateFormat date={exercice.solved_time} />.
</ListGroupItem>
{/if}
{#if exercice.solve_dist}
<ListGroupItem class="rounded-0">
{exercice.solve_dist} {exercice.solve_dist == 1?"réponse erronée":"réponses erronées"}.
</ListGroupItem>
{/if}
{#if exercice.submitted || sberr}
<ListGroupItem class="{messageClass} rounded-0">
{#if !sberr}
<strong>Votre solution a bien été envoyée !</strong>
{:else}
<strong>{sberr}</strong> {message}
{/if}
</ListGroupItem>
{/if}
{#if $timeouted}
<ListGroupItem class="text-danger rounded-0">
<strong>Oops</strong>
La requête a dépassé le délai d'attente. Vous devriez réessayer dans quelques instant&hellip;
</ListGroupItem>
{/if}
</ListGroup>
{/if}
{#if !exercice.submitted || sberr}
<CardBody>
<form on:submit|preventDefault={submitFlags}>
{#each flags as flag, index ((flag.type?flag.type:"i") + (flag.id?flag.id:index))}
{#if !flag.type && !flag.id}
<div class="form-group mb-3">
<span class="{flag.variant?('text-'+flag.variant):''}">{@html flag.label}</span>
</div>
{:else if flag.type == "mcq"}
<FlagMCQ
exercice_id={exercice.id}
{flag}
bind:values={responses.mcqs}
bind:justifications={responses.justifications}
/>
{:else}
<FlagKey
class="mb-3"
exercice_id={exercice.id}
{flag}
bind:value={responses.flags[flag.id]}
/>
{/if}
{/each}
<div class="form-group mt-2">
<Button
type="submit"
color="danger"
id="submission-{exercice.id}"
disabled={$waitInProgress || $settings.disablesubmitbutton || readonly}
>
{#if $waitInProgress}
<Spinner size="sm" class="me-2" />
{/if}
Soumettre
</Button>
{#if $settings.disablesubmitbutton}
<span class="text-muted">{$settings.disablesubmitbutton}</span>
{:else if readonly}
<span class="text-muted">Ce défi est désactivé</span>
{/if}
</div>
</form>
</CardBody>
{/if}
</Card>