diff --git a/backend/main.go b/backend/main.go index 76caea84..44e44ee2 100644 --- a/backend/main.go +++ b/backend/main.go @@ -47,6 +47,7 @@ func main() { flag.StringVar(&TeamsDir, "teams", "../TEAMS", "Base directory where save teams JSON files") flag.StringVar(&fic.FilesDir, "files", "/files", "Request path prefix to reach files") var skipFullGeneration = flag.Bool("skipFullGeneration", false, "Skip initial full generation (safe to skip after start)") + flag.BoolVar(&fic.PartialValidation, "partialValidation", false, "Validates flags which are corrects, don't be binary") flag.BoolVar(&fic.UnlockedChallenges, "unlockedChallenges", false, "Make all challenges accessible without having to validate previous level") flag.Parse() diff --git a/frontend/static/js/app.js b/frontend/static/js/app.js index 21f8aee3..bdee2f12 100644 --- a/frontend/static/js/app.js +++ b/frontend/static/js/app.js @@ -197,7 +197,7 @@ angular.module("FICApp") }) .controller("SubmissionController", function($scope, $http, $rootScope, $timeout) { - $scope.flags = [] + $scope.flags = []; $rootScope.sberr = ""; var waitMy = function() { @@ -205,12 +205,16 @@ angular.module("FICApp") $timeout.cancel($scope.cbs); $scope.cbs = $timeout(waitMy, 420); } else { + $scope.flags = []; angular.forEach($scope.my.exercices[$rootScope.current_exercice].keys, function(key,kid) { - this.push({ + var o = { id: kid, name: key, value: "" - }); + }; + if ($scope.my.exercices[$rootScope.current_exercice].solved_matrix != null) + o.found = $scope.my.exercices[$rootScope.current_exercice].solved_matrix[kid]; + this.push(o); }, $scope.flags); } } @@ -219,23 +223,10 @@ angular.module("FICApp") $scope.ssubmit = function() { var flgs = {} - var filled = true; angular.forEach($scope.flags, function(flag,kid) { flgs[flag.name] = flag.value; - filled = filled && flag.value.length > 0; }); - if (!filled) { - $rootScope.messageClass = {"text-danger": true}; - $rootScope.sberr = "Tous les champs sont obligatoires."; - $timeout(function() { - if ($rootScope.sberr == "Tous les champs sont obligatoires.") { - $rootScope.sberr = ""; - } - }, 2345); - return; - } - $http({ url: "/submit/" + $rootScope.current_exercice, method: "POST", diff --git a/frontend/static/views/theme.html b/frontend/static/views/theme.html index 8dc8074b..e2bbec27 100644 --- a/frontend/static/views/theme.html +++ b/frontend/static/views/theme.html @@ -52,9 +52,10 @@
-
+
- + +
diff --git a/libfic/db.go b/libfic/db.go index b3bb4e31..05134b03 100644 --- a/libfic/db.go +++ b/libfic/db.go @@ -107,6 +107,17 @@ CREATE TABLE IF NOT EXISTS exercice_keys( value BINARY(64) NOT NULL, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) ); +`); err != nil { + return err + } + if _, err := db.Exec(` +CREATE TABLE IF NOT EXISTS key_found( + id_key INTEGER NOT NULL, + id_team INTEGER NOT NULL, + time TIMESTAMP NOT NULL, + FOREIGN KEY(id_key) REFERENCES exercice_keys(id_key), + FOREIGN KEY(id_team) REFERENCES teams(id_team) +); `); err != nil { return err } diff --git a/libfic/exercice.go b/libfic/exercice.go index 6af662d4..4f3c1211 100644 --- a/libfic/exercice.go +++ b/libfic/exercice.go @@ -5,6 +5,8 @@ import ( "time" ) +var PartialValidation bool + type Exercice struct { Id int64 `json:"id"` Title string `json:"title"` @@ -201,13 +203,14 @@ func (e Exercice) CheckResponse(resps map[string]string, t Team) (bool, error) { valid := true for _, key := range keys { - if _, ok := resps[key.Type]; !ok { + if res, ok := resps[key.Type]; !ok { valid = false - break - } - if !key.Check(resps[key.Type]) { - valid = false - break + } else if !key.Check(res) { + if !PartialValidation || t.HasPartiallySolved(key) == nil { + valid = false + } + } else { + key.FoundBy(t) } } diff --git a/libfic/key.go b/libfic/key.go index a1a32d39..853f7166 100644 --- a/libfic/key.go +++ b/libfic/key.go @@ -2,6 +2,7 @@ package fic import ( "crypto/sha512" + "time" ) type Key struct { @@ -88,3 +89,7 @@ func (k Key) Check(val string) bool { return true } + +func (k Key) FoundBy(t Team) { + DBExec("INSERT INTO key_found (id_key, id_team, time) VALUES (?, ?, ?)", k.Id, t.Id, time.Now()) +} diff --git a/libfic/team.go b/libfic/team.go index 920ab6fd..27fbb40a 100644 --- a/libfic/team.go +++ b/libfic/team.go @@ -244,6 +244,12 @@ func IsSolved(e Exercice) (int, time.Time) { } } +func (t Team) HasPartiallySolved(k Key) (*time.Time) { + var tm *time.Time + DBQueryRow("SELECT MIN(time) FROM key_found WHERE id_team = ? AND id_key = ?", t.Id, k.Id).Scan(&tm) + return tm +} + type statLine struct { Tip string `json:"tip"` Total int `json:"total"` diff --git a/libfic/team_my.go b/libfic/team_my.go index 3626fcf1..06b218e7 100644 --- a/libfic/team_my.go +++ b/libfic/team_my.go @@ -28,6 +28,7 @@ type myTeamExercice struct { Files []myTeamFile `json:"files"` Keys []string `json:"keys"` Solved bool `json:"solved"` + SolvedMat []bool `json:"solved_matrix"` SolvedTime time.Time `json:"solved_time"` SolvedNumber int64 `json:"solved_number"` VideoURI string `json:"video_uri"` @@ -116,6 +117,9 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) { exercice.Keys = append(exercice.Keys, fmt.Sprintf("%x", k.Value)+k.Type) } else { exercice.Keys = append(exercice.Keys, k.Type) + if PartialValidation { + exercice.SolvedMat = append(exercice.SolvedMat, t.HasPartiallySolved(k) != nil) + } } } }