admin: control settings

This commit is contained in:
nemunaire 2017-01-15 02:37:59 +01:00
parent b42016c74a
commit ef4a738672
7 changed files with 180 additions and 0 deletions

34
admin/api/settings.go Normal file
View File

@ -0,0 +1,34 @@
package api
import (
"encoding/json"
"path"
"srs.epita.fr/fic-server/settings"
"github.com/julienschmidt/httprouter"
)
var TeamsDir string
func init() {
router.GET("/api/settings.json", apiHandler(getSettings))
router.PUT("/api/settings.json", apiHandler(saveSettings))
}
func getSettings(_ httprouter.Params, body []byte) (interface{}, error) {
return settings.ReadSettings(path.Join(TeamsDir, settings.SettingsFile))
}
func saveSettings(_ httprouter.Params, body []byte) (interface{}, error) {
var config settings.FICSettings
if err := json.Unmarshal(body, &config); err != nil {
return nil, err
}
if err := settings.SaveSettings(path.Join(TeamsDir, settings.SettingsFile), config); err != nil {
return nil, err
} else {
return config, err
}
}

View File

@ -24,6 +24,7 @@ const indextpl = `<!DOCTYPE html>
<li><a href="{{.urlbase}}themes">Thèmes</a></li> <li><a href="{{.urlbase}}themes">Thèmes</a></li>
<li><a href="{{.urlbase}}exercices">Exercices</a></li> <li><a href="{{.urlbase}}exercices">Exercices</a></li>
<li><a href="{{.urlbase}}events">&Eacute;vénements</a></li> <li><a href="{{.urlbase}}events">&Eacute;vénements</a></li>
<li><a href="{{.urlbase}}settings">Paramètres</a></li>
</ul> </ul>
<p id="clock" class="navbar-text navbar-right" ng-controller="CountdownController"> <p id="clock" class="navbar-text navbar-right" ng-controller="CountdownController">

View File

@ -25,6 +25,7 @@ func main() {
flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions") flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions")
flag.StringVar(&PKIDir, "pki", "./pki/", "Base directory where found PKI scripts") flag.StringVar(&PKIDir, "pki", "./pki/", "Base directory where found PKI scripts")
flag.StringVar(&StaticDir, "static", "./htdocs-admin/", "Directory containing static files") flag.StringVar(&StaticDir, "static", "./htdocs-admin/", "Directory containing static files")
flag.StringVar(&api.TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
flag.StringVar(&fic.FilesDir, "files", "./FILES/", "Base directory where found challenges files, local part") flag.StringVar(&fic.FilesDir, "files", "./FILES/", "Base directory where found challenges files, local part")
flag.StringVar(&api.CloudDAVBase, "clouddav", "https://srs.epita.fr/owncloud/remote.php/webdav/FIC 2016", flag.StringVar(&api.CloudDAVBase, "clouddav", "https://srs.epita.fr/owncloud/remote.php/webdav/FIC 2016",
"Base directory where found challenges files, cloud part") "Base directory where found challenges files, cloud part")

View File

@ -19,6 +19,9 @@ func init() {
api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html")) http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
}) })
api.Router().GET("/settings/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/teams/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { api.Router().GET("/teams/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html")) http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
}) })

View File

@ -22,6 +22,7 @@
<li><a href="/themes">Thèmes</a></li> <li><a href="/themes">Thèmes</a></li>
<li><a href="/exercices">Exercices</a></li> <li><a href="/exercices">Exercices</a></li>
<li><a href="/events">&Eacute;vénements</a></li> <li><a href="/events">&Eacute;vénements</a></li>
<li><a href="/settings">Paramètres</a></li>
</ul> </ul>
<p id="clock" class="navbar-text navbar-right" ng-controller="CountdownController"> <p id="clock" class="navbar-text navbar-right" ng-controller="CountdownController">

View File

@ -13,6 +13,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
controller: "ExerciceController", controller: "ExerciceController",
templateUrl: "views/exercice.html" templateUrl: "views/exercice.html"
}) })
.when("/settings", {
controller: "SettingsController",
templateUrl: "views/settings.html"
})
.when("/exercices", { .when("/exercices", {
controller: "AllExercicesListController", controller: "AllExercicesListController",
templateUrl: "views/exercice-list.html" templateUrl: "views/exercice-list.html"
@ -56,6 +60,11 @@ angular.module("FICApp")
'update': {method: 'PUT'}, 'update': {method: 'PUT'},
}) })
}) })
.factory("Settings", function($resource) {
return $resource("/api/settings.json", null, {
'update': {method: 'PUT'},
})
})
.factory("Team", function($resource) { .factory("Team", function($resource) {
return $resource("/api/teams/:teamId", { teamId: '@id' }, { return $resource("/api/teams/:teamId", { teamId: '@id' }, {
'update': {method: 'PUT'}, 'update': {method: 'PUT'},
@ -186,10 +195,39 @@ angular.module("FICApp")
}; };
}) })
.directive('float', function() {
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(function(viewValue){
return parseFloat(viewValue, 10);
});
}
};
})
.controller("VersionController", function($scope, Version) { .controller("VersionController", function($scope, Version) {
$scope.v = Version.get(); $scope.v = Version.get();
}) })
.controller("SettingsController", function($scope, Settings, $location, $http) {
$scope.config = Settings.get();
$scope.duration = 240;
$scope.saveSettings = function() {
this.config.$update(function() {
$location.url("/");
});
}
$scope.launchChallenge = function() {
var ts = Date.now() - Date.now() % 60000;
var d = new Date(ts + 120000);
this.config.start = d.toISOString();
var f = new Date(ts + 120000 + this.duration * 60000);
this.config.end = f.toISOString();
}
})
.controller("EventsListController", function($scope, Event, $location) { .controller("EventsListController", function($scope, Event, $location) {
$scope.events = Event.query(); $scope.events = Event.query();
$scope.fields = ["id", "kind", "txt", "time"]; $scope.fields = ["id", "kind", "txt", "time"];

View File

@ -0,0 +1,102 @@
<h2>Paramètres</h2>
<form ng-submit="saveSettings()" class="form-horizontal well">
<div class="form-group">
<label for="startTime" class="col-sm-2 control-label">Début du challenge</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="startTime" ng-model="config.start">
</div>
<div class="col-sm-2 text-right">
<a ng-click="launchChallenge()" class="btn btn-warning" role="button"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Lancer le challenge</a>
</div>
</div>
<div class="form-group">
<label for="endTime" class="col-sm-2 control-label">Fin du challenge</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="endTime" ng-model="config.end">
</div>
<div class="col-sm-1 text-right">
<label for="duration" class="control-label">Durée</label>
</div>
<div class="col-sm-2">
<div class="input-group">
<input type="text" class="form-control" id="duration" ng-model="duration" integer>
<div class="input-group-addon">min</div>
</div>
</div>
</div>
<hr>
<div class="form-group">
<label for="firstBlood" class="col-sm-2 control-label">Bonus premier sang</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="firstBlood" ng-model="config.firstBlood" float>
</div>
</div>
<div class="form-group">
<label for="submissionCostBase" class="col-sm-2 control-label">Coût de base d'une soumission</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="submissionCostBase" ng-model="config.submissionCostBase" float>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="config.allowRegistration"> Activer les inscriptions
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="config.denyNameChange"> Interdire les changements de nom d'équipe
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="config.enableResolutionRoute"> Activer la route montrant les solutions
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="config.partialValidation"> Activer la validation partielle des challenges
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="config.enableExerciceDepend"> Activer les dépendances des exercices
</label>
</div>
</div>
</div>
<div class="text-right">
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-save" aria-hidden="true"></span> Propager ces paramètres</button>
</div>
</form>