admin: control settings
This commit is contained in:
parent
b42016c74a
commit
ef4a738672
34
admin/api/settings.go
Normal file
34
admin/api/settings.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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">Événements</a></li>
|
<li><a href="{{.urlbase}}events">É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">
|
||||||
|
@ -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")
|
||||||
|
@ -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"))
|
||||||
})
|
})
|
||||||
|
@ -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">Événements</a></li>
|
<li><a href="/events">É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">
|
||||||
|
@ -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"];
|
||||||
|
102
admin/static/views/settings.html
Normal file
102
admin/static/views/settings.html
Normal 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>
|
Loading…
Reference in New Issue
Block a user