Compare commits
9 Commits
f15cd29f78
...
a5fd04672b
Author | SHA1 | Date | |
---|---|---|---|
a5fd04672b | |||
57c3cd8fd6 | |||
24686a6a24 | |||
407b67f4c2 | |||
c28d974105 | |||
ffb69663b6 | |||
4ec4f47951 | |||
96707e3a29 | |||
a4001759f6 |
@ -62,6 +62,7 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
|
||||
apiFlagsRoutes.POST("/try", tryExerciceFlag)
|
||||
apiFlagsRoutes.DELETE("/", deleteExerciceFlag)
|
||||
apiFlagsRoutes.GET("/dependancies", showExerciceFlagDeps)
|
||||
apiFlagsRoutes.GET("/statistics", showExerciceFlagStats)
|
||||
apiFlagsRoutes.GET("/choices/", listFlagChoices)
|
||||
apiFlagsChoicesRoutes := apiExercicesRoutes.Group("/choices/:cid")
|
||||
apiFlagsChoicesRoutes.Use(FlagChoiceHandler)
|
||||
@ -852,6 +853,34 @@ func showExerciceFlagDeps(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, deps)
|
||||
}
|
||||
|
||||
func showExerciceFlagStats(c *gin.Context) {
|
||||
exercice := c.MustGet("exercice").(*fic.Exercice)
|
||||
flag := c.MustGet("flag-key").(*fic.FlagKey)
|
||||
|
||||
history, err := exercice.GetHistory()
|
||||
if err != nil {
|
||||
log.Println("Unable to getExerciceHistory:", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving exercice history"})
|
||||
return
|
||||
}
|
||||
|
||||
var completed, tries, nteams int64
|
||||
|
||||
for _, hline := range history {
|
||||
if hline["kind"].(string) == "flag_found" {
|
||||
if *hline["secondary"].(*int) == flag.Id {
|
||||
completed += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"completed": completed,
|
||||
"tries": tries,
|
||||
"nteams": nteams,
|
||||
})
|
||||
}
|
||||
|
||||
func tryExerciceFlag(c *gin.Context) {
|
||||
flag := c.MustGet("flag-key").(*fic.FlagKey)
|
||||
|
||||
@ -1048,7 +1077,11 @@ func updateExerciceQuiz(c *gin.Context) {
|
||||
if cur.Id == next.Id {
|
||||
seen = true
|
||||
|
||||
log.Println("ici", cur.Label, cur.Response, next.Response)
|
||||
|
||||
if cur.Label != next.Label || cur.Response != next.Response {
|
||||
log.Println("1", cur.Label, cur.Response, next.Response)
|
||||
|
||||
cur.Label = next.Label
|
||||
cur.Response = next.Response
|
||||
if _, err := cur.Update(); err != nil {
|
||||
|
@ -348,6 +348,9 @@ angular.module("FICApp")
|
||||
.factory("ExerciceFlagDeps", function ($resource) {
|
||||
return $resource("api/exercices/:exerciceId/flags/:flagId/dependancies", { exerciceId: '@idExercice', flagId: '@id' })
|
||||
})
|
||||
.factory("ExerciceFlagStats", function ($resource) {
|
||||
return $resource("api/exercices/:exerciceId/flags/:flagId/statistics", { exerciceId: '@idExercice', flagId: '@id' })
|
||||
})
|
||||
.factory("ExerciceMCQFlag", function ($resource) {
|
||||
return $resource("api/exercices/:exerciceId/quiz/:mcqId", { exerciceId: '@idExercice', mcqId: '@id' }, {
|
||||
update: { method: 'PUT' }
|
||||
@ -2345,6 +2348,12 @@ angular.module("FICApp")
|
||||
}
|
||||
})
|
||||
|
||||
.controller("ExerciceFlagStatsController", function ($scope, $routeParams, ExerciceFlagStats) {
|
||||
$scope.init = function (flag) {
|
||||
$scope.stats = ExerciceFlagStats.get({ exerciceId: $routeParams.exerciceId, flagId: flag.id });
|
||||
}
|
||||
})
|
||||
|
||||
.controller("ExerciceMCQFlagsController", function ($scope, ExerciceMCQFlag, $routeParams, $rootScope) {
|
||||
$scope.quiz = ExerciceMCQFlag.query({ exerciceId: $routeParams.exerciceId });
|
||||
|
||||
|
@ -73,12 +73,21 @@
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div ng-controller="ExerciceFlagDepsController" ng-init="init(flag)">
|
||||
Dépendances :
|
||||
<strong>Dépendances :</strong>
|
||||
<ul ng-if="deps.length > 0">
|
||||
<dependancy ng-repeat="dep in deps" dep="dep"></dependancy>
|
||||
</ul>
|
||||
<span ng-if="deps.length == 0"> sans</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div ng-controller="ExerciceFlagStatsController" ng-init="init(flag)">
|
||||
<strong>Statistiques</strong>
|
||||
<ul>
|
||||
<li>Validés : {{ stats["completed"] }}</li>
|
||||
<li>Tentés : {{ stats["tries"] }}</li>
|
||||
<li>Équipes : {{ stats["nteams"] }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4" ng-controller="ExerciceFlagChoicesController">
|
||||
<div class="btn-toolbar justify-content-end mb-2" role="toolbar">
|
||||
|
@ -30,13 +30,13 @@
|
||||
<div class="spinner-border spinner-border-sm" role="status" ng-if="file.gunzipWIP"></div>
|
||||
</button>
|
||||
</td>
|
||||
<td ng-repeat="field in fields">
|
||||
<td ng-repeat="field in fields" class="text-truncate" style="max-width: 30vw" title="{{ file[field] }}">
|
||||
{{ file[field] }}
|
||||
<span ng-if="field == 'id' && file.err !== undefined && file.err !== true" title="{{ file.err }}" class="glyphicon glyphicon-exclamation-sign"></span>
|
||||
</td>
|
||||
<td>
|
||||
{{ file.checksum | bto16 }}
|
||||
<div ng-if="file.checksum_shown">{{ file.checksum_shown | bto16 }}</div>
|
||||
<td style="max-width: 100px">
|
||||
<div class="text-truncate" title="{{ file.checksum | bto16 }}">{{ file.checksum | bto16 }}</div>
|
||||
<div class="text-truncate" ng-if="file.checksum_shown" title="{{ file.checksum_shown | bto16 }}">{{ file.checksum_shown | bto16 }}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -279,6 +279,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
|
||||
}
|
||||
|
||||
type importFlag struct {
|
||||
origin ExerciceFlag
|
||||
Line int
|
||||
Flag fic.Flag
|
||||
JustifyOf *fic.MCQ_entry
|
||||
@ -392,8 +393,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
|
||||
errs = multierr.Append(errs, berrs)
|
||||
if addedFlag != nil {
|
||||
ret = append(ret, importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: addedFlag,
|
||||
origin: flag,
|
||||
Line: nline + 1,
|
||||
Flag: addedFlag,
|
||||
})
|
||||
}
|
||||
} else if flag.Type == "key" || strings.HasPrefix(flag.Type, "number") || flag.Type == "text" || flag.Type == "ucq" || flag.Type == "radio" || flag.Type == "vector" {
|
||||
@ -401,6 +403,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
|
||||
errs = multierr.Append(errs, berrs)
|
||||
if addedFlag != nil {
|
||||
ret = append(ret, importFlag{
|
||||
origin: flag,
|
||||
Line: nline + 1,
|
||||
Flag: *addedFlag,
|
||||
Choices: choices,
|
||||
@ -462,6 +465,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
|
||||
errs = multierr.Append(errs, berrs)
|
||||
if addedFlag != nil {
|
||||
ret = append(ret, importFlag{
|
||||
origin: flag,
|
||||
Line: nline + 1,
|
||||
Flag: *addedFlag,
|
||||
JustifyOf: entry,
|
||||
@ -479,8 +483,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
|
||||
}
|
||||
|
||||
ret = append([]importFlag{importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: &addedFlag,
|
||||
origin: flag,
|
||||
Line: nline + 1,
|
||||
Flag: &addedFlag,
|
||||
}}, ret...)
|
||||
}
|
||||
return
|
||||
@ -570,6 +575,10 @@ func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string, exce
|
||||
if int64(fk.ChoicesCost) >= exercice.Gain {
|
||||
errs = multierr.Append(errs, NewFlagError(exercice, nil, flag.Line, fmt.Errorf("flag's choice_cost is higher than exercice gain")))
|
||||
}
|
||||
|
||||
if raw, ok := flag.origin.Raw.(string); ok && raw == fk.Placeholder {
|
||||
errs = multierr.Append(errs, NewFlagError(exercice, nil, flag.Line, fmt.Errorf("flag's placeholder and raw are identical")))
|
||||
}
|
||||
}
|
||||
|
||||
// Check dependency loop
|
||||
|
@ -20,6 +20,8 @@ escape_newline () {
|
||||
sed 's/$/\\n/g' | tr -d '\n'
|
||||
}
|
||||
|
||||
which mkisofs > /dev/null 2> /dev/null || { echo "Please install genisoimage (Debian/Ubuntu) or cdrkit (Alpine)" >&2; exit 1; }
|
||||
|
||||
if [ $# -gt 0 ]
|
||||
then
|
||||
which jq > /dev/null 2> /dev/null || { echo "Please install jq" >&2; exit 1; }
|
||||
|
@ -21,6 +21,8 @@ OLD_KEY=$(cat /run/config/dm-crypt/key)
|
||||
[ "${NEW_KEY}" != "${OLD_KEY}" ] && {
|
||||
read -p "DM-CRYPT key changed in metadata, are you sure you want to erase it? (y/N) " V
|
||||
[ "$V" != "y" ] && [ "$V" != "Y" ] && while true; do
|
||||
mv /boot/imgs/fickit-metadata.iso /boot/imgs/fickit-metadata.iso.skipped
|
||||
cp /boot/imgs/fickit-metadata.iso.bak /boot/imgs/fickit-metadata.iso
|
||||
echo
|
||||
echo "Metadata drive not erased"
|
||||
echo
|
||||
|
@ -153,6 +153,15 @@ onboot:
|
||||
mkdir:
|
||||
- /var/lib/fic/secrets
|
||||
|
||||
- name: create-ssh-keys
|
||||
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
|
||||
command: ["/bin/sh", "-c", "touch /etc/ssh/sshd_config && ssh-keygen -A"]
|
||||
binds:
|
||||
- /var/lib/fic/ssh:/etc/ssh
|
||||
runtime:
|
||||
mkdir:
|
||||
- /var/lib/fic/ssh
|
||||
|
||||
services:
|
||||
# - name: getty
|
||||
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b
|
||||
@ -361,7 +370,6 @@ services:
|
||||
- /var/lib/fic/files
|
||||
- /var/lib/fic/pki/shared
|
||||
- /var/lib/fic/settingsdist
|
||||
- /var/lib/fic/ssh
|
||||
- /var/lib/fic/submissions
|
||||
- /var/lib/fic/teams
|
||||
- /var/log/frontend
|
||||
|
@ -136,6 +136,15 @@ onboot:
|
||||
- /etc/iptables/rules.v6:/etc/iptables/rules.v6:ro
|
||||
net: /run/netns/sshd
|
||||
|
||||
- name: create-ssh-keys
|
||||
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
|
||||
command: ["/bin/sh", "-c", "touch /etc/ssh/sshd_config && ssh-keygen -A"]
|
||||
binds:
|
||||
- /var/lib/fic/ssh:/etc/ssh
|
||||
runtime:
|
||||
mkdir:
|
||||
- /var/lib/fic/ssh
|
||||
|
||||
services:
|
||||
# - name: getty
|
||||
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b
|
||||
@ -257,7 +266,6 @@ services:
|
||||
- /var/lib/fic/files
|
||||
- /var/lib/fic/pki
|
||||
- /var/lib/fic/settingsdist
|
||||
- /var/lib/fic/ssh
|
||||
- /var/lib/fic/submissions
|
||||
- /var/lib/fic/teams
|
||||
|
||||
|
@ -7,9 +7,9 @@ kernel:
|
||||
init:
|
||||
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
|
||||
- nemunaire/syslinux:086f221f281d577d300949aa1094fb20c5cd90dc
|
||||
- linuxkit/format:3c858f0cf42a2b14441bfb5c266b78f14d2b75a4
|
||||
- linuxkit/dm-crypt:19fa6affe9da03afc91694e36d72a4924c65a0e0
|
||||
- linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44
|
||||
- linuxkit/format:8f487d728959192289e0783784fc2b185eadbc82
|
||||
- linuxkit/dm-crypt:ad2a05dcffa28ef809a61aa27ba230c82f02f603
|
||||
- linuxkit/metadata:83cda7b43112b201613084ea8b7fab585b6e5549
|
||||
- alpine:latest
|
||||
|
||||
files:
|
||||
|
@ -33,9 +33,9 @@
|
||||
</h1>
|
||||
<div style="min-width: 0">
|
||||
<h4 class="fw-bold"><samp>{file.name}</samp></h4>
|
||||
{#if file.disclamer}
|
||||
<div class="file-disclamer text-warning">
|
||||
{file.disclamer}
|
||||
{#if file.disclaimer}
|
||||
<div class="file-disclaimer text-warning">
|
||||
{file.disclaimer}
|
||||
</div>
|
||||
{/if}
|
||||
<nobr>
|
||||
@ -61,10 +61,10 @@
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.file-disclamer {
|
||||
.file-disclaimer {
|
||||
display: none;
|
||||
}
|
||||
:global(.list-group-item:hover .file-disclamer) {
|
||||
:global(.list-group-item:hover .file-disclaimer) {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
@ -392,7 +392,12 @@ func (f *EFile) GetDepends() ([]Flag, error) {
|
||||
|
||||
// CheckFileOnDisk recalculates the hash of the file on disk.
|
||||
func (f *EFile) CheckFileOnDisk() error {
|
||||
if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), f.Checksum); err != nil {
|
||||
firstChecksum := f.Checksum
|
||||
if len(f.ChecksumShown) > 0 {
|
||||
firstChecksum = f.ChecksumShown
|
||||
}
|
||||
|
||||
if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), firstChecksum); size > 0 && err != nil {
|
||||
return err
|
||||
} else if size == 0 {
|
||||
if _, _, err := checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil {
|
||||
@ -400,9 +405,17 @@ func (f *EFile) CheckFileOnDisk() error {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path.Join(FilesDir, f.Path+".gz")); !os.IsNotExist(err) {
|
||||
if _, _, err = checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GunzipFileOnDisk gunzip a compressed file.
|
||||
|
@ -207,7 +207,7 @@ func (m *MCQ) AddEntry(e *MCQ_entry) (*MCQ_entry, error) {
|
||||
|
||||
// Update applies modifications back to the database.
|
||||
func (n *MCQ_entry) Update() (int64, error) {
|
||||
if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq = ?", n.Label, n.Response, n.Id); err != nil {
|
||||
if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq_entry = ?", n.Label, n.Response, n.Id); err != nil {
|
||||
return 0, err
|
||||
} else if nb, err := res.RowsAffected(); err != nil {
|
||||
return 0, err
|
||||
|
Loading…
x
Reference in New Issue
Block a user