diff --git a/admin/api/exercice.go b/admin/api/exercice.go index 6d0ab34c..e00772e7 100644 --- a/admin/api/exercice.go +++ b/admin/api/exercice.go @@ -18,12 +18,20 @@ func init() { router.GET("/api/exercices/:eid/files", apiHandler(exerciceHandler(listExerciceFiles))) router.POST("/api/exercices/:eid/files", apiHandler(exerciceHandler(createExerciceFile))) + router.GET("/api/exercices/:eid/files/:fid", apiHandler(fileHandler(showExerciceFile))) + router.DELETE("/api/exercices/:eid/files/:fid", apiHandler(fileHandler(deleteExerciceFile))) router.GET("/api/exercices/:eid/hints", apiHandler(exerciceHandler(listExerciceHints))) router.POST("/api/exercices/:eid/hints", apiHandler(exerciceHandler(createExerciceHint))) + router.GET("/api/exercices/:eid/hints/:hid", apiHandler(hintHandler(showExerciceHint))) + router.PUT("/api/exercices/:eid/hints/:hid", apiHandler(hintHandler(updateExerciceHint))) + router.DELETE("/api/exercices/:eid/hints/:hid", apiHandler(hintHandler(deleteExerciceHint))) router.GET("/api/exercices/:eid/keys", apiHandler(exerciceHandler(listExerciceKeys))) router.POST("/api/exercices/:eid/keys", apiHandler(exerciceHandler(createExerciceKey))) + router.GET("/api/exercices/:eid/keys/:kid", apiHandler(keyHandler(showExerciceKey))) + router.PUT("/api/exercices/:eid/keys/:kid", apiHandler(keyHandler(updateExerciceKey))) + router.DELETE("/api/exercices/:eid/keys/:kid", apiHandler(keyHandler(deleteExerciceKey))) } func listExercices(_ httprouter.Params, body []byte) (interface{}, error) { @@ -94,7 +102,7 @@ func createExercice(theme fic.Theme, body []byte) (interface{}, error) { } type uploadedKey struct { - Name string + Type string Key string } @@ -108,7 +116,7 @@ func createExerciceKey(exercice fic.Exercice, body []byte) (interface{}, error) return nil, errors.New("Key not filled") } - return exercice.AddRawKey(uk.Name, uk.Key) + return exercice.AddRawKey(uk.Type, uk.Key) } func createExerciceHint(exercice fic.Exercice, body []byte) (interface{}, error) { @@ -123,3 +131,68 @@ func createExerciceHint(exercice fic.Exercice, body []byte) (interface{}, error) return exercice.AddHint(uh.Title, uh.Content, uh.Cost) } + +func showExerciceHint(hint fic.EHint, body []byte) (interface{}, error) { + return hint, nil +} + +func updateExerciceHint(hint fic.EHint, body []byte) (interface{}, error) { + var uh fic.EHint + if err := json.Unmarshal(body, &uh); err != nil { + return nil, err + } + + uh.Id = hint.Id + + if len(uh.Title) == 0 { + return nil, errors.New("Hint's title not filled") + } + + if _, err := uh.Update(); err != nil { + return nil, err + } + + return uh, nil +} + +func deleteExerciceHint(hint fic.EHint, _ []byte) (interface{}, error) { + return hint.Delete() +} + + +func showExerciceKey(key fic.Key, _ fic.Exercice, body []byte) (interface{}, error) { + return key, nil +} + +func updateExerciceKey(key fic.Key, exercice fic.Exercice, body []byte) (interface{}, error) { + var uk fic.Key + if err := json.Unmarshal(body, &uk); err != nil { + return nil, err + } + + uk.Id = key.Id + uk.IdExercice = exercice.Id + + if len(uk.Type) == 0 { + uk.Type = "Flag" + } + + if _, err := uk.Update(); err != nil { + return nil, err + } + + return uk, nil +} + +func deleteExerciceKey(key fic.Key, _ fic.Exercice, _ []byte) (interface{}, error) { + return key.Delete() +} + + +func showExerciceFile(file fic.EFile, body []byte) (interface{}, error) { + return file, nil +} + +func deleteExerciceFile(file fic.EFile, _ []byte) (interface{}, error) { + return file.Delete() +} diff --git a/admin/api/handlers.go b/admin/api/handlers.go index 70dfe1ee..c0e02bd8 100644 --- a/admin/api/handlers.go +++ b/admin/api/handlers.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "errors" "fmt" "io" "log" @@ -151,6 +152,76 @@ func themedExerciceHandler(f func(fic.Theme,fic.Exercice,[]byte) (interface{}, e } } +func hintHandler(f func(fic.EHint,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { + return func (ps httprouter.Params, body []byte) (interface{}, error) { + if hid, err := strconv.Atoi(string(ps.ByName("hid"))); err != nil { + return nil, err + } else if hint, err := fic.GetHint(int64(hid)); err != nil { + return nil, err + } else { + return f(hint, body) + } + } +} + +func keyHandler(f func(fic.Key,fic.Exercice,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { + return func (ps httprouter.Params, body []byte) (interface{}, error) { + var exercice fic.Exercice + exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) { + exercice = ex + return nil,nil + })(ps, body) + + if kid, err := strconv.Atoi(string(ps.ByName("kid"))); err != nil { + return nil, err + } else if keys, err := exercice.GetKeys(); err != nil { + return nil, err + } else { + for _, key := range keys { + if (key.Id == int64(kid)) { + return f(key, exercice, body) + } + } + return nil, errors.New("Unable to find the requested key") + } + } +} + +func fileHandler(f func(fic.EFile,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { + return func (ps httprouter.Params, body []byte) (interface{}, error) { + var exercice fic.Exercice + exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) { + exercice = ex + return nil,nil + })(ps, body) + + if fid, err := strconv.Atoi(string(ps.ByName("fid"))); err != nil { + return nil, err + } else if files, err := exercice.GetFiles(); err != nil { + return nil, err + } else { + for _, file := range files { + if (file.Id == int64(fid)) { + return f(file, body) + } + } + return nil, errors.New("Unable to find the requested file") + } + } +} + +func eventHandler(f func(fic.Event,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { + return func (ps httprouter.Params, body []byte) (interface{}, error) { + if evid, err := strconv.Atoi(string(ps.ByName("evid"))); err != nil { + return nil, err + } else if event, err := fic.GetEvent(evid); err != nil { + return nil, err + } else { + return f(event, body) + } + } +} + func notFound(ps httprouter.Params, _ []byte) (interface{}, error) { return nil, nil } diff --git a/admin/fill_exercices.sh b/admin/fill_exercices.sh index 054e47b1..e428c269 100755 --- a/admin/fill_exercices.sh +++ b/admin/fill_exercices.sh @@ -60,10 +60,10 @@ new_hint() { new_key() { THEME="$1" EXERCICE="$2" - NAME="$3" + TYPE="$3" KEY=`echo $4 | sed 's/"/\\\\"/g' | sed 's#\\\\#\\\\\\\\#g'` - curl -f -s -d "{\"name\": \"$NAME\", \"key\": \"$KEY\"}" "${BASEURL}/api/themes/$THEME/exercices/$EXERCICE/keys" | + curl -f -s -d "{\"type\": \"$TYPE\", \"key\": \"$KEY\"}" "${BASEURL}/api/themes/$THEME/exercices/$EXERCICE/keys" | grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+" } diff --git a/admin/static/js/app.js b/admin/static/js/app.js index ffbcfdaa..004334c7 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -97,18 +97,18 @@ angular.module("FICApp") }) }) .factory("ExerciceFile", function($resource) { - return $resource("/api/exercices/:exerciceId/files", { exerciceId: '@idExercice' }, { - update: {method: 'PATCH'} + return $resource("/api/exercices/:exerciceId/files/:fileId", { exerciceId: '@idExercice', fileId: '@id' }, { + update: {method: 'PUT'} }) }) .factory("ExerciceHint", function($resource) { - return $resource("/api/exercices/:exerciceId/hints", { exerciceId: '@idExercice' }, { - update: {method: 'PATCH'} + return $resource("/api/exercices/:exerciceId/hints/:hintId", { exerciceId: '@idExercice', hintId: '@id' }, { + update: {method: 'PUT'} }) }) .factory("ExerciceKey", function($resource) { - return $resource("/api/exercices/:exerciceId/keys", { exerciceId: '@idExercice' }, { - update: {method: 'PATCH'} + return $resource("/api/exercices/:exerciceId/keys/:keyId", { exerciceId: '@idExercice', keyId: '@id' }, { + update: {method: 'PUT'} }) }); @@ -175,6 +175,17 @@ angular.module("FICApp") } }) + .directive('integer', function() { + return { + require: 'ngModel', + link: function(scope, ele, attr, ctrl){ + ctrl.$parsers.unshift(function(viewValue){ + return parseInt(viewValue, 10); + }); + } + }; + }) + .controller("VersionController", function($scope, Version) { $scope.v = Version.get(); }) @@ -228,7 +239,13 @@ angular.module("FICApp") $scope.fields = ["name", "authors"]; $scope.saveTheme = function() { - this.theme.$update(); + if (this.theme.id) { + this.theme.$update(); + } else { + this.theme.$save(function() { + $location.url("/themes/" + $scope.theme.id); + }); + } } $scope.deleteTheme = function() { this.theme.$remove(function() { $location.url("/themes/");}); @@ -237,7 +254,7 @@ angular.module("FICApp") .controller("AllExercicesListController", function($scope, Exercice, $routeParams, $location) { $scope.exercices = Exercice.query(); - $scope.fields = ["id", "title", "statement", "videoURI"]; + $scope.fields = ["title", "statement", "videoURI"]; $scope.show = function(id) { $location.url("/exercices/" + id); @@ -245,27 +262,40 @@ angular.module("FICApp") }) .controller("ExercicesListController", function($scope, ThemedExercice, $routeParams, $location) { $scope.exercices = ThemedExercice.query({ themeId: $routeParams.themeId }); - $scope.fields = ["id", "title", "statement", "videoURI"]; + $scope.fields = ["title", "statement", "videoURI"]; $scope.show = function(id) { $location.url("/themes/" + $routeParams.themeId + "/exercices/" + id); }; }) - .controller("ExerciceController", function($scope, Exercice, $routeParams) { - $scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId }); + .controller("ExerciceController", function($scope, Exercice, ThemedExercice, $routeParams, $location) { + if ($routeParams.themeId && $routeParams.exerciceId == "new") { + $scope.exercice = new ThemedExercice(); + } else { + $scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId }); + } $scope.exercices = Exercice.query(); $scope.fields = ["title", "statement", "depend", "gain", "videoURI"]; $scope.saveExercice = function() { - this.exercice.$update(); + if (this.exercice.id) { + this.exercice.$update(); + } else if ($routeParams.themeId) { + this.exercice.$save({ themeId: $routeParams.themeId }, function() { + $location.url("/themes/" + $scope.exercice.idTheme + "/exercices/" + $scope.exercice.id); + }); + } } }) - .controller("ExerciceFilesController", function($scope, ExerciceFile, $routeParams) { + .controller("ExerciceFilesController", function($scope, ExerciceFile, $routeParams, $location) { $scope.files = ExerciceFile.query({ exerciceId: $routeParams.exerciceId }); $scope.deleteFile = function() { - this.file.$delete(); + this.file.$delete(function() { + $scope.files.splice($scope.files.indexOf(this.file), 1); + }); + return false; } $scope.saveFile = function() { this.file.$update(); @@ -275,22 +305,40 @@ angular.module("FICApp") .controller("ExerciceHintsController", function($scope, ExerciceHint, $routeParams) { $scope.hints = ExerciceHint.query({ exerciceId: $routeParams.exerciceId }); + $scope.addHint = function() { + $scope.hints.push(new ExerciceHint()); + } $scope.deleteHint = function() { - this.hint.$delete(); + this.hint.$delete(function() { + $scope.hints.splice($scope.hints.indexOf(this.hint), 1); + }); } $scope.saveHint = function() { - this.hint.$update(); + if (this.hint.id) { + this.hint.$update(); + } else { + this.hint.$save({ exerciceId: $routeParams.exerciceId }); + } } }) .controller("ExerciceKeysController", function($scope, ExerciceKey, $routeParams) { $scope.keys = ExerciceKey.query({ exerciceId: $routeParams.exerciceId }); + $scope.addKey = function() { + $scope.keys.push(new ExerciceKey()); + } $scope.deleteKey = function() { - this.key.$delete(); + this.key.$delete(function() { + $scope.keys.splice($scope.keys.indexOf(this.key), 1); + }); } $scope.saveKey = function() { - this.key.$update(); + if (this.key.id) { + this.key.$update(); + } else { + this.key.$save({ exerciceId: $routeParams.exerciceId }); + } } }) diff --git a/admin/static/views/exercice.html b/admin/static/views/exercice.html index 8a94cf5f..a95ea5d3 100644 --- a/admin/static/views/exercice.html +++ b/admin/static/views/exercice.html @@ -1,25 +1,29 @@

{{exercice.title}}

-
+
- - - + + +
-
+
- + Delete +
+
+

-
+
@@ -37,17 +41,17 @@
- +
- +
- +
@@ -80,15 +84,30 @@
-
+
+
+ +
-
+
-
+
+
+ +
+
+
+ +
+ +
+
+ +
diff --git a/admin/static/views/theme-list.html b/admin/static/views/theme-list.html index c676fd7f..7cef07a6 100644 --- a/admin/static/views/theme-list.html +++ b/admin/static/views/theme-list.html @@ -1,4 +1,4 @@ -

Thèmes

+

Thèmes Ajouter un thème

diff --git a/admin/static/views/theme.html b/admin/static/views/theme.html index 623e2c64..3469a04a 100644 --- a/admin/static/views/theme.html +++ b/admin/static/views/theme.html @@ -1,19 +1,24 @@

{{theme.name}} {{theme.authors}}

- +
- - + +
+ +
-
+
- + Delete +
+
+
-

Exercices

+
+

Exercices Ajouter un exercice

-