admin: add public interface management

This commit is contained in:
nemunaire 2017-01-20 19:18:43 +01:00
parent 37fa6a1955
commit e82b3ba80c
6 changed files with 294 additions and 0 deletions

80
admin/api/public.go Normal file
View File

@ -0,0 +1,80 @@
package api
import (
"encoding/json"
"os"
"path"
"github.com/julienschmidt/httprouter"
)
func init() {
router.GET("/api/public.json", apiHandler(getPublic))
router.DELETE("/api/public.json", apiHandler(deletePublic))
router.PUT("/api/public.json", apiHandler(savePublic))
}
type FICPublicScene struct {
Type string `json:"type"`
Params map[string]interface{} `json:"params"`
}
func readPublic(path string) ([]FICPublicScene, error) {
var s []FICPublicScene
if fd, err := os.Open(path); err != nil {
return s, err
} else {
defer fd.Close()
jdec := json.NewDecoder(fd)
if err := jdec.Decode(&s); err != nil {
return s, err
}
return s, nil
}
}
func savePublicTo(path string, s []FICPublicScene) error {
if fd, err := os.Create(path); err != nil {
return err
} else {
defer fd.Close()
jenc := json.NewEncoder(fd)
if err := jenc.Encode(s); err != nil {
return err
}
return nil
}
}
func getPublic(_ httprouter.Params, body []byte) (interface{}, error) {
if _, err := os.Stat(path.Join(TeamsDir, "_public", "public.json")); !os.IsNotExist(err) {
return readPublic(path.Join(TeamsDir, "_public", "public.json"))
} else {
return []FICPublicScene{}, nil
}
}
func deletePublic(_ httprouter.Params, body []byte) (interface{}, error) {
if err := savePublicTo(path.Join(TeamsDir, "_public", "public.json"), []FICPublicScene{}); err != nil {
return nil, err
} else {
return []FICPublicScene{}, err
}
}
func savePublic(_ httprouter.Params, body []byte) (interface{}, error) {
var scenes []FICPublicScene
if err := json.Unmarshal(body, &scenes); err != nil {
return nil, err
}
if err := savePublicTo(path.Join(TeamsDir, "_public", "public.json"), scenes); err != nil {
return nil, err
} else {
return scenes, err
}
}

View File

@ -23,6 +23,7 @@ const indextpl = `<!DOCTYPE html>
<li><a href="{{.urlbase}}teams">&Eacute;quipes</a></li>
<li><a href="{{.urlbase}}themes">Thèmes</a></li>
<li><a href="{{.urlbase}}exercices">Exercices</a></li>
<li><a href="{{.urlbase}}public">Public</a></li>
<li><a href="{{.urlbase}}events">&Eacute;vénements</a></li>
<li><a href="{{.urlbase}}settings">Paramètres</a></li>
</ul>

View File

@ -19,6 +19,9 @@ func init() {
api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/public", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
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"))
})

View File

@ -21,6 +21,7 @@
<li><a href="/teams">&Eacute;quipes</a></li>
<li><a href="/themes">Thèmes</a></li>
<li><a href="/exercices">Exercices</a></li>
<li><a href="/public">Public</a></li>
<li><a href="/events">&Eacute;vénements</a></li>
<li><a href="/settings">Paramètres</a></li>
</ul>

View File

@ -37,6 +37,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
controller: "TeamNewController",
templateUrl: "views/team-new.html"
})
.when("/public", {
controller: "PublicController",
templateUrl: "views/public.html"
})
.when("/events", {
controller: "EventsListController",
templateUrl: "views/event-list.html"
@ -65,6 +69,11 @@ angular.module("FICApp")
'update': {method: 'PUT'},
})
})
.factory("Scene", function($resource) {
return $resource("/api/public.json", null, {
'update': {method: 'PUT'},
})
})
.factory("Team", function($resource) {
return $resource("/api/teams/:teamId", { teamId: '@id' }, {
'update': {method: 'PUT'},
@ -228,6 +237,77 @@ angular.module("FICApp")
}
})
.controller("PublicController", function($scope, Scene, Theme, Teams, Exercice) {
$scope.scenes = Scene.query();
$scope.themes = Theme.query();
$scope.teams = Teams.get();
$scope.types = {
"welcome": "Messages de bienvenue",
"message": "Message",
"panel": "Boîte",
"exercice": "Exercice",
"table": "Tableau",
"rank": "Classement",
};
$scope.welcome_types = {
"init": "Accueil des équipes",
"public": "Accueil du public",
"countdown": "Compte à rebours lancement",
};
$scope.panel_types = {
"panel-default": "Default",
"panel-info": "Info",
"panel-success": "Success",
"panel-warning": "Warning",
"panel-danger": "Danger",
};
$scope.rank_types = {
"general": "Classement général",
};
$scope.table_types = {
"levels": "Niveaux d'exercices",
"teams": "Équipes",
};
$scope.exercices = Exercice.query();
$scope.clearScene = function() {
Scene.delete(function() {
$scope.scenes = [];
});
};
$scope.saveScenes = function() {
Scene.update($scope.scenes);
};
$scope.addScene = function() {
$scope.scenes.push({params: {}});
};
$scope.delScene = function(s) {
angular.forEach($scope.scenes, function(scene, k) {
if (scene == s)
$scope.scenes.splice(k, 1);
});
};
$scope.upScene = function(s) {
angular.forEach($scope.scenes, function(scene, k) {
if (scene == s && k > 0) {
$scope.scenes.splice(k, 1);
$scope.scenes.splice(k - 1, 0, scene);
}
});
};
$scope.downScene = function(s) {
var move = true;
angular.forEach($scope.scenes, function(scene, k) {
if (move && scene == s) {
$scope.scenes.splice(k, 1);
$scope.scenes.splice(k + 1, 0, scene);
move = false;
}
});
};
})
.controller("EventsListController", function($scope, Event, $location) {
$scope.events = Event.query();
$scope.fields = ["id", "kind", "txt", "time"];

View File

@ -0,0 +1,129 @@
<form ng-submit="saveScenes()" class="form-horizontal">
<h2>Interface publique<a ng-click="clearScene()" class="pull-right btn btn-danger"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Vider la scène</a><a ng-click="addScene()" class="pull-right btn btn-primary" style="margin-right: 10px"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Ajouter un élément</a><button type="submit" style="margin-right: 10px" class="pull-right btn btn-success"><span class="glyphicon glyphicon-save" aria-hidden="true"></span> Publier cette scène</button>
</h2>
<div class="well" ng-repeat="scene in scenes">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="scene.params.hide"> Masquer temporairement
</label>
</div>
</div>
<div class="col-sm-2">
<a ng-click="upScene(scene)" class="pull-right btn btn-default"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span> Up</a>
<a ng-click="downScene(scene)" class="pull-right btn btn-default"><span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span> Down</a>
</div>
<div class="col-sm-2">
<a ng-click="delScene(scene)" class="pull-right btn btn-warning"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span> Supprimer</a>
</div>
</div>
<div class="form-group">
<label for="type" class="col-sm-2 control-label">Type de scène</label>
<div class="col-sm-10">
<select class="form-control" id="type" ng-model="scene.type" ng-options="k as v for (k, v) in types"></select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'welcome'">
<label for="wtype" class="col-sm-2 control-label">Sorte</label>
<div class="col-sm-10">
<select class="form-control" id="wtype" ng-model="scene.params.kind" ng-options="k as v for (k, v) in welcome_types"></select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'panel'">
<label for="ptype" class="col-sm-2 control-label">Type de cadre</label>
<div class="col-sm-10">
<select class="form-control" id="ptype" ng-model="scene.params.kind" ng-options="k as v for (k, v) in panel_types"></select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'message' || scene.type == 'panel'">
<label for="mtitle" class="col-sm-2 control-label">Titre</label>
<div class="col-sm-10">
<input type="text" id="mtitle" ng-model="scene.params.title" class="form-control">
</div>
</div>
<div class="form-group" ng-if="scene.type == 'message'">
<label for="mlead" class="col-sm-2 control-label">Lead</label>
<div class="col-sm-10">
<input type="text" id="mlead" ng-model="scene.params.lead" class="form-control">
</div>
</div>
<div class="form-group" ng-if="scene.type == 'message' || scene.type == 'panel'">
<label for="mcnt" class="col-sm-2 control-label">Contenu HTML</label>
<div class="col-sm-10">
<textarea class="form-control" id="mcnt" ng-model="scene.params.html"></textarea>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'exercice'">
<label for="eex" class="col-sm-2 control-label">Exercice</label>
<div class="col-sm-10">
<select class="form-control" id="eex" ng-model="scene.params.exercice" ng-options="ex.id as ex.title for ex in exercices">
</select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'rank'">
<label for="rtype" class="col-sm-2 control-label">Sorte</label>
<div class="col-sm-10">
<select class="form-control" id="rtype" ng-model="scene.params.which" ng-options="k as v for (k, v) in rank_types"></select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'rank'">
<label for="rlimit" class="col-sm-2 control-label">Nombre d'éléments</label>
<div class="col-sm-10">
<input type="text" id="rlimit" ng-model="scene.params.limit" class="form-control" integer>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'rank'">
<label for="begin" class="col-sm-2 control-label">Début du classement (à partir de 0)</label>
<div class="col-sm-10">
<input type="text" id="rbegin" ng-model="scene.params.begin" class="form-control" integer>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'table'">
<label for="ttable" class="col-sm-2 control-label">Quelle table ?</label>
<div class="col-sm-10">
<select class="form-control" id="ttable" ng-model="scene.params.kind" ng-options="k as v for (k, v) in table_types">
</select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'table'">
<label for="ttheme" class="col-sm-2 control-label">Thèmes à afficher</label>
<div class="col-sm-10">
<select class="form-control" id="ttheme" multiple="1" ng-model="scene.params.themes" ng-options="th.id as th.name for th in themes">
</select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'table' && scene.params.kind == 'teams'">
<label for="tteams" class="col-sm-2 control-label">Équipes à afficher</label>
<div class="col-sm-10">
<select class="form-control" id="tteams" multiple="1" ng-model="scene.params.teams" ng-options="t.id as (t.rank + 'e - ' + t.name) for t in teams">
</select>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'table'">
<div class="col-sm-offset-2 col-sm-6">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="scene.params.total"> Ligne de total
</label>
</div>
</div>
</div>
</div>
</form>