diff --git a/admin/api/file.go b/admin/api/file.go
index d609b6a0..60ed0ce8 100644
--- a/admin/api/file.go
+++ b/admin/api/file.go
@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net/http"
+ "path/filepath"
"strconv"
"srs.epita.fr/fic-server/admin/sync"
@@ -166,8 +167,14 @@ func createExerciceFile(c *gin.Context) {
return
}
+ paramsFiles, err := sync.GetExerciceFilesParams(sync.GlobalImporter, exercice.(*fic.Exercice))
+ if err != nil {
+ c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
+ return
+ }
+
var uf uploadedFile
- err := c.ShouldBindJSON(&uf)
+ err = c.ShouldBindJSON(&uf)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
@@ -178,7 +185,12 @@ func createExerciceFile(c *gin.Context) {
if digest, err := hex.DecodeString(uf.Digest); err != nil {
return nil, err
} else {
- return exercice.(*fic.Exercice).ImportFile(filePath, origin, digest, nil)
+ published := true
+ if f, exists := paramsFiles[filepath.Base(filePath)]; exists {
+ published = !f.Hidden
+ }
+
+ return exercice.(*fic.Exercice).ImportFile(filePath, origin, digest, nil, published)
}
})
if err != nil {
diff --git a/admin/static/views/exercice.html b/admin/static/views/exercice.html
index a0977e02..5c60cf42 100644
--- a/admin/static/views/exercice.html
+++ b/admin/static/views/exercice.html
@@ -103,6 +103,10 @@
Taille : {{ file.size | size }} ‐
BLAKE2b : {{ file.checksum | cksum }}
+
+
+
+
Dépend de la validation de :
aucun flag
diff --git a/admin/sync/exercice_defines.go b/admin/sync/exercice_defines.go
index d8fdaa0d..60ff08c9 100644
--- a/admin/sync/exercice_defines.go
+++ b/admin/sync/exercice_defines.go
@@ -28,6 +28,12 @@ type ExerciceUnlockFile struct {
Filename string `toml:",omitempty"`
}
+// ExerciceFile defines attributes on files.
+type ExerciceFile struct {
+ Filename string `toml:",omitempty"`
+ Hidden bool `toml:",omitempty"`
+}
+
// ExerciceFlag holds informations about one flag.
type ExerciceFlag struct {
Id int64
@@ -66,6 +72,7 @@ type ExerciceFlagChoice struct {
type ExerciceParams struct {
Gain int64
Tags []string
+ Files []ExerciceFile `toml:"file"`
Hints []ExerciceHintParams `toml:"hint"`
Dependencies []ExerciceDependency `toml:"depend"`
Flags []ExerciceFlag `toml:"flag"`
@@ -127,3 +134,17 @@ func getExerciceParams(i Importer, exercice *fic.Exercice) (params ExerciceParam
}
return
}
+
+func GetExerciceFilesParams(i Importer, exercice *fic.Exercice) (map[string]ExerciceFile, error) {
+ params, _, err := parseExerciceParams(i, exercice.Path)
+ if err != nil {
+ return nil, err
+ }
+
+ paramsFiles := map[string]ExerciceFile{}
+ for _, f := range params.Files {
+ paramsFiles[f.Filename] = f
+ }
+
+ return paramsFiles, nil
+}
diff --git a/admin/sync/exercice_files.go b/admin/sync/exercice_files.go
index dc3bdf21..1e04d0aa 100644
--- a/admin/sync/exercice_files.go
+++ b/admin/sync/exercice_files.go
@@ -134,6 +134,12 @@ func SyncExerciceFiles(i Importer, exercice *fic.Exercice, exceptions *CheckExce
errs = append(errs, err)
}
+ paramsFiles, err := GetExerciceFilesParams(i, exercice)
+ if err != nil {
+ errs = append(errs, NewChallengeTxtError(exercice, 0, err))
+ return
+ }
+
files, digests, berrs := BuildFilesListInto(i, exercice, "files")
errs = append(errs, berrs...)
@@ -147,7 +153,13 @@ func SyncExerciceFiles(i Importer, exercice *fic.Exercice, exceptions *CheckExce
digest_shown = d
}
}
- return exercice.ImportFile(filePath, origin, digests[fname], digest_shown)
+
+ published := true
+ if f, exists := paramsFiles[fname]; exists {
+ published = !f.Hidden
+ }
+
+ return exercice.ImportFile(filePath, origin, digests[fname], digest_shown, published)
}); err != nil {
errs = append(errs, NewFileError(exercice, fname, err))
continue
diff --git a/libfic/db.go b/libfic/db.go
index c31a5517..c1a52994 100644
--- a/libfic/db.go
+++ b/libfic/db.go
@@ -170,6 +170,7 @@ CREATE TABLE IF NOT EXISTS exercice_files(
cksum BINARY(64) NOT NULL,
cksum_shown BINARY(64),
size BIGINT UNSIGNED NOT NULL,
+ published BOOLEAN NOT NULL DEFAULT 1,
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`); err != nil {
diff --git a/libfic/file.go b/libfic/file.go
index 615477cd..56cbdea4 100644
--- a/libfic/file.go
+++ b/libfic/file.go
@@ -44,6 +44,8 @@ type EFile struct {
ChecksumShown []byte `json:"checksum_shown"`
// Size contains the cached size of the file
Size int64 `json:"size"`
+ // Published indicates if the file should be shown or not
+ Published bool `json:"published"`
}
// NewDummyFile creates an EFile, without any link to an actual Exercice File.
@@ -58,12 +60,13 @@ func (e *Exercice) NewDummyFile(origin string, dest string, checksum []byte, siz
Checksum: checksum,
ChecksumShown: nil,
Size: size,
+ Published: true,
}
}
// GetFiles returns a list of all files living in the database.
func GetFiles() ([]*EFile, error) {
- if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, cksum, cksum_shown, size FROM exercice_files"); err != nil {
+ if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, cksum, cksum_shown, size, published FROM exercice_files"); err != nil {
return nil, err
} else {
defer rows.Close()
@@ -71,7 +74,7 @@ func GetFiles() ([]*EFile, error) {
files := []*EFile{}
for rows.Next() {
f := &EFile{}
- if err := rows.Scan(&f.Id, &f.IdExercice, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size); err != nil {
+ if err := rows.Scan(&f.Id, &f.IdExercice, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published); err != nil {
return nil, err
}
files = append(files, f)
@@ -87,13 +90,13 @@ func GetFiles() ([]*EFile, error) {
// GetFile retrieves the file with the given id.
func GetFile(id int64) (f *EFile, err error) {
f = &EFile{}
- err = DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size FROM exercice_files WHERE id_file = ?", id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size)
+ err = DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size, published FROM exercice_files WHERE id_file = ?", id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published)
return
}
func (e *Exercice) GetFile(id int64) (f *EFile, err error) {
f = &EFile{}
- err = DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size FROM exercice_files WHERE id_file = ? AND id_exercice = ?", id, e.Id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size)
+ err = DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size, published FROM exercice_files WHERE id_file = ? AND id_exercice = ?", id, e.Id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published)
return
}
@@ -102,7 +105,7 @@ func GetFileByPath(path string) (*EFile, error) {
path = strings.TrimPrefix(path, FilesDir)
f := &EFile{}
- if err := DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, cksum_shown, size FROM exercice_files WHERE path = ?", path).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size); err != nil {
+ if err := DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, cksum_shown, size, published FROM exercice_files WHERE path = ?", path).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published); err != nil {
return f, err
}
@@ -114,14 +117,14 @@ func (e *Exercice) GetFileByFilename(filename string) (f *EFile, err error) {
filename = path.Base(filename)
f = &EFile{}
- err = DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, cksum_shown, size FROM exercice_files WHERE id_exercice = ? AND origin LIKE ?", e.Id, "%/"+filename).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size)
+ err = DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, cksum_shown, size, published FROM exercice_files WHERE id_exercice = ? AND origin LIKE ?", e.Id, "%/"+filename).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published)
return
}
// GetFiles returns a list of files coming with the challenge.
func (e *Exercice) GetFiles() ([]*EFile, error) {
- if rows, err := DBQuery("SELECT id_file, origin, path, name, cksum, cksum_shown, size FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil {
+ if rows, err := DBQuery("SELECT id_file, origin, path, name, cksum, cksum_shown, size, published FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil {
return nil, err
} else {
defer rows.Close()
@@ -130,7 +133,7 @@ func (e *Exercice) GetFiles() ([]*EFile, error) {
for rows.Next() {
f := &EFile{}
f.IdExercice = e.Id
- if err := rows.Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size); err != nil {
+ if err := rows.Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published); err != nil {
return nil, err
}
files = append(files, f)
@@ -148,7 +151,7 @@ func (e *Exercice) GetFileByPath(path string) (*EFile, error) {
path = strings.TrimPrefix(path, FilesDir)
f := &EFile{}
- if err := DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size FROM exercice_files WHERE id_exercice = ? AND path = ?", e.Id, path).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size); err != nil {
+ if err := DBQueryRow("SELECT id_file, origin, path, name, cksum, cksum_shown, size, published FROM exercice_files WHERE id_exercice = ? AND path = ?", e.Id, path).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.ChecksumShown, &f.Size, &f.Published); err != nil {
return nil, err
}
@@ -229,13 +232,13 @@ func checkFileHash(filePath string, digest []byte) (dgst []byte, size int64, err
}
// ImportFile registers (ou updates if it already exists in database) the file in database.
-func (e *Exercice) ImportFile(filePath string, origin string, digest []byte, digestshown []byte) (interface{}, error) {
+func (e *Exercice) ImportFile(filePath string, origin string, digest []byte, digestshown []byte, published bool) (interface{}, error) {
if result512, size, err := checkFileHash(filePath, digest); !OptionalDigest && err != nil {
return EFile{}, err
} else {
dPath := strings.TrimPrefix(filePath, FilesDir)
if f, err := e.GetFileByPath(dPath); err != nil {
- return e.AddFile(dPath, origin, path.Base(filePath), result512, digestshown, size)
+ return e.AddFile(dPath, origin, path.Base(filePath), result512, digestshown, size, published)
} else {
// Don't need to update Path and Name, because they are related to dPath
@@ -244,6 +247,7 @@ func (e *Exercice) ImportFile(filePath string, origin string, digest []byte, dig
f.Checksum = result512
f.ChecksumShown = digestshown
f.Size = size
+ f.Published = published
if _, err := f.Update(); err != nil {
return nil, err
@@ -255,19 +259,19 @@ func (e *Exercice) ImportFile(filePath string, origin string, digest []byte, dig
}
// AddFile creates and fills a new struct File and registers it into the database.
-func (e *Exercice) AddFile(path string, origin string, name string, checksum []byte, checksumshown []byte, size int64) (*EFile, error) {
- if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, cksum, cksum_shown, size) VALUES (?, ?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, checksumshown, size); err != nil {
+func (e *Exercice) AddFile(path string, origin string, name string, checksum []byte, checksumshown []byte, size int64, published bool) (*EFile, error) {
+ if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, cksum, cksum_shown, size, published) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, checksumshown, size, published); err != nil {
return nil, err
} else if fid, err := res.LastInsertId(); err != nil {
return nil, err
} else {
- return &EFile{fid, origin, path, e.Id, name, checksum, checksumshown, size}, nil
+ return &EFile{fid, origin, path, e.Id, name, checksum, checksumshown, size, published}, nil
}
}
// Update applies modifications back to the database.
func (f *EFile) Update() (int64, error) {
- if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, cksum = ?, cksum_shown = ?, size = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.ChecksumShown, f.Size, f.Id); err != nil {
+ if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, cksum = ?, cksum_shown = ?, size = ?, published = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.ChecksumShown, f.Size, f.Published, f.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
diff --git a/libfic/team.go b/libfic/team.go
index 7b1b4ea7..25c3cffe 100644
--- a/libfic/team.go
+++ b/libfic/team.go
@@ -152,7 +152,9 @@ func (t *Team) HasAccess(e *Exercice) bool {
// CanDownload checks if the Team has access to the given file.
func (t *Team) CanDownload(f *EFile) bool {
- if deps, err := f.GetDepends(); err != nil {
+ if !f.Published {
+ return false
+ } else if deps, err := f.GetDepends(); err != nil {
log.Printf("Unable to retrieve file dependencies: %s\n", err)
return false
} else {