server/admin/static/js/app.js

1156 lines
34 KiB
JavaScript
Raw Normal View History

2016-12-26 00:16:49 +00:00
angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
2016-01-13 00:22:54 +00:00
.config(function($routeProvider, $locationProvider) {
$routeProvider
2016-01-22 16:37:29 +00:00
.when("/themes", {
controller: "ThemesListController",
templateUrl: "views/theme-list.html"
})
.when("/themes/:themeId", {
controller: "ThemeController",
templateUrl: "views/theme.html"
})
2016-12-26 00:23:31 +00:00
.when("/themes/:themeId/exercices/:exerciceId", {
controller: "ExerciceController",
templateUrl: "views/exercice.html"
})
2017-01-15 01:37:59 +00:00
.when("/settings", {
controller: "SettingsController",
templateUrl: "views/settings.html"
})
2016-12-26 00:23:31 +00:00
.when("/exercices", {
controller: "AllExercicesListController",
templateUrl: "views/exercice-list.html"
})
.when("/exercices/:exerciceId", {
2016-01-22 16:37:29 +00:00
controller: "ExerciceController",
templateUrl: "views/exercice.html"
})
2016-01-13 00:22:54 +00:00
.when("/teams", {
controller: "TeamsListController",
templateUrl: "views/team-list.html"
})
.when("/teams/print", {
controller: "TeamsListController",
templateUrl: "views/team-print.html"
})
2016-10-13 17:52:54 +00:00
.when("/teams/:teamId", {
2017-01-28 18:36:28 +00:00
controller: "TeamController",
templateUrl: "views/team-edit.html"
})
.when("/teams/:teamId/stats", {
2016-10-13 17:52:54 +00:00
controller: "TeamController",
2017-04-02 09:38:40 +00:00
templateUrl: "views/team-stats.html"
2016-10-13 17:52:54 +00:00
})
2017-01-20 18:18:43 +00:00
.when("/public", {
controller: "PublicController",
templateUrl: "views/public.html"
})
2016-12-26 02:44:04 +00:00
.when("/events", {
controller: "EventsListController",
templateUrl: "views/event-list.html"
})
.when("/events/:eventId", {
controller: "EventController",
templateUrl: "views/event.html"
})
2016-10-13 17:52:54 +00:00
.when("/", {
templateUrl: "views/home.html"
2016-01-13 00:22:54 +00:00
});
$locationProvider.html5Mode(true);
});
angular.module("FICApp")
2016-10-13 17:52:54 +00:00
.factory("Version", function($resource) {
return $resource("/api/version")
})
2016-12-26 02:44:04 +00:00
.factory("Event", function($resource) {
return $resource("/api/events/:eventId", { eventId: '@id' }, {
'update': {method: 'PUT'},
})
})
.factory("ROSettings", function($resource) {
return $resource("/api/settings-ro.json")
})
2017-01-15 01:37:59 +00:00
.factory("Settings", function($resource) {
return $resource("/api/settings.json", null, {
'update': {method: 'PUT'},
})
})
2017-01-20 18:18:43 +00:00
.factory("Scene", function($resource) {
return $resource("/api/public.json", null, {
'update': {method: 'PUT', isArray: true},
2017-01-20 18:18:43 +00:00
})
})
2016-01-13 00:22:54 +00:00
.factory("Team", function($resource) {
2016-01-22 16:37:29 +00:00
return $resource("/api/teams/:teamId", { teamId: '@id' }, {
'update': {method: 'PUT'},
2016-01-22 16:37:29 +00:00
})
2016-10-13 17:52:54 +00:00
})
.factory("TeamMember", function($resource) {
2017-01-28 18:36:28 +00:00
return $resource("/api/teams/:teamId/members", { teamId: '@id' }, {
'save': {method: 'PUT'},
})
2016-10-13 17:52:54 +00:00
})
.factory("TeamMy", function($resource) {
return $resource("/api/teams/:teamId/my.json", { teamId: '@id' })
})
.factory("Teams", function($resource) {
return $resource("/api/teams.json")
2016-10-13 17:52:54 +00:00
})
2017-11-12 23:57:48 +00:00
.factory("TeamHistory", function($resource) {
return $resource("/api/teams/:teamId/history.json", { teamId: '@id' })
})
2016-10-13 17:52:54 +00:00
.factory("TeamStats", function($resource) {
return $resource("/api/teams/:teamId/stats.json", { teamId: '@id' })
})
.factory("TeamPresence", function($resource) {
return $resource("/api/teams/:teamId/tries", { teamId: '@id' })
})
2016-01-22 16:37:29 +00:00
.factory("Theme", function($resource) {
return $resource("/api/themes/:themeId", { themeId: '@id' }, {
update: {method: 'PUT'}
});
2016-10-13 17:52:54 +00:00
})
.factory("Themes", function($resource) {
return $resource("/api/themes.json", null, {
2016-10-13 17:52:54 +00:00
'get': {method: 'GET'},
2016-01-13 00:22:54 +00:00
})
2016-10-13 17:52:54 +00:00
})
2016-12-26 00:23:31 +00:00
.factory("ThemedExercice", function($resource) {
return $resource("/api/themes/:themeId/exercices/:exerciceId", { exerciceId: '@id' }, {
update: {method: 'PUT'}
})
})
2016-10-13 17:52:54 +00:00
.factory("Exercice", function($resource) {
return $resource("/api/exercices/:exerciceId", { exerciceId: '@id' }, {
update: {method: 'PUT'}
})
2016-12-26 00:23:31 +00:00
})
.factory("ExerciceFile", function($resource) {
return $resource("/api/exercices/:exerciceId/files/:fileId", { exerciceId: '@idExercice', fileId: '@id' }, {
update: {method: 'PUT'}
2016-12-26 00:23:31 +00:00
})
})
.factory("ExerciceHint", function($resource) {
return $resource("/api/exercices/:exerciceId/hints/:hintId", { exerciceId: '@idExercice', hintId: '@id' }, {
update: {method: 'PUT'}
2016-12-26 00:23:31 +00:00
})
})
.factory("ExerciceKey", function($resource) {
return $resource("/api/exercices/:exerciceId/keys/:keyId", { exerciceId: '@idExercice', keyId: '@id' }, {
update: {method: 'PUT'}
2016-12-26 00:23:31 +00:00
})
2016-01-13 00:22:54 +00:00
});
2016-10-13 17:52:54 +00:00
String.prototype.capitalize = function() {
return this
.toLowerCase()
.replace(
/(^|\s)([a-z])/g,
function(m,p1,p2) { return p1+p2.toUpperCase(); }
);
}
2016-01-13 00:22:54 +00:00
angular.module("FICApp")
2016-10-13 17:52:54 +00:00
.filter("capitalize", function() {
return function(input) {
if (input != undefined)
return input.capitalize();
}
})
2017-01-28 18:36:28 +00:00
.filter("toColor", function() {
return function(input) {
num >>>= 0;
var b = num & 0xFF,
g = (num & 0xFF00) >>> 8,
r = (num & 0xFF0000) >>> 16,
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
return "#" + r.toString(16) + g.toString(16) + b.toString(16);
}
})
2016-12-26 00:23:31 +00:00
.filter("size", function() {
var units = [
"o",
"kio",
"Mio",
"Gio",
"Tio",
"Pio",
"Eio",
"Zio",
"Yio",
]
return function(input) {
var res = input;
var unit = 0;
while (res > 1024) {
unit += 1;
res = res / 1024;
}
return (Math.round(res * 100) / 100) + " " + units[unit];
}
})
.filter("cksum", function() {
return function(input) {
if (input == undefined)
return input;
var raw = atob(input).toString(16);
var hex = '';
for (var i = 0; i < raw.length; i++ ) {
var _hex = raw.charCodeAt(i).toString(16)
hex += (_hex.length == 2 ? _hex : '0' + _hex);
}
return hex
}
})
2016-10-13 17:52:54 +00:00
.filter("time", function() {
return function(input) {
if (input == undefined) {
return "--";
} else if (input >= 10) {
return input;
} else {
return "0" + input;
}
}
})
2017-01-28 18:36:28 +00:00
.directive('color', function() {
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$formatters.unshift(function(num){
num >>>= 0;
var b = num & 0xFF,
g = (num & 0xFF00) >>> 8,
r = (num & 0xFF0000) >>> 16,
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
return "#" + r.toString(16) + g.toString(16) + b.toString(16);
});
ctrl.$parsers.unshift(function(viewValue){
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(viewValue);
return result ? (
parseInt(result[1], 16) * 256 * 256 +
parseInt(result[2], 16) * 256 +
parseInt(result[3], 16)
) : 0;
});
}
};
})
.directive('integer', function() {
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(function(viewValue){
return parseInt(viewValue, 10);
});
}
};
})
2017-01-15 01:37:59 +00:00
.directive('float', function() {
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(function(viewValue){
return parseFloat(viewValue, 10);
});
}
};
})
2016-10-13 17:52:54 +00:00
.controller("VersionController", function($scope, Version) {
$scope.v = Version.get();
})
.controller("DIWEBoxController", function($scope, $rootScope, $interval, $timeout) {
function updBox() {
while ($rootScope._newBoxes.length > 0) {
var b = $rootScope._newBoxes.shift();
$scope.boxes.unshift(b);
var id = $scope.boxes.length - 1;
b.cancel = function() {
$scope.boxes.pop($scope.boxes.indexOf(b));
}
2017-12-17 14:39:51 +00:00
if (b.timeout >= 0)
$timeout(function() { b.cancel(); }, b.timeout);
}
}
$rootScope._newBoxes = new Array();
$rootScope.newBox = function(kind, title, msg, tmout) {
if (kind === undefined) { kind = 'default'; }
if (msg === undefined) { msg = ''; }
if (tmout === undefined) { tmout = 5000; }
var mybox = {
'kind': kind,
'title': title,
'timeout': tmout,
};
2017-12-17 14:39:51 +00:00
if (Array.isArray(msg))
mybox['list'] = msg;
else
mybox['msg'] = msg;
$rootScope._newBoxes.push(mybox);
};
$rootScope.newYesNoBox = function(kind, title, msg, yesFunc, noFunc, tmout) {
if (kind === undefined) { kind = 'default'; }
if (msg === undefined) { msg = ''; }
if (tmout === undefined) { tmout = 5000; }
var mybox;
var yesFn = function() {
mybox.cancel();
if (yesFunc !== undefined) {
yesFunc();
}
}
var noFn = function() {
mybox.cancel();
if (noFunc !== undefined) {
noFunc();
}
}
mybox = {
'kind': kind,
'title': title,
'msg': msg,
'yes': yesFn,
'no': noFn,
'timeout': tmout,
};
$rootScope._newBoxes.push(mybox);
};
$scope.boxes = new Array();
updBox();
$interval(updBox, 750);
})
.controller("SettingsController", function($scope, $rootScope, Settings, ROSettings, $location, $http) {
2017-01-15 01:37:59 +00:00
$scope.config = Settings.get();
$scope.configro = ROSettings.get();
2017-01-15 01:37:59 +00:00
$scope.duration = 240;
$scope.saveSettings = function(msg) {
if (msg === undefined) { msg = 'New settings saved!'; }
2017-01-15 01:37:59 +00:00
this.config.$update(function() {
$rootScope.newBox('success', msg);
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when saving settings:', response.data);
2017-01-15 01:37:59 +00:00
});
}
2017-01-24 01:14:28 +00:00
$scope.regenerate = function() {
this.config.generation = (new Date()).toISOString();
$scope.saveSettings("Regeneration in progress...");
2017-01-24 01:14:28 +00:00
}
2017-01-15 01:37:59 +00:00
$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();
$rootScope.newYesNoBox('info', 'Challenge ready to start,', 'propagate the changes?',
function() {
$scope.saveSettings();
});
2017-01-15 01:37:59 +00:00
}
$scope.reset = function(type) {
if (confirm("Êtes-vous sûr ?")) {
2017-12-14 02:20:38 +00:00
$http.post("/api/reset", {"type": type}).then(function(time) {
$rootScope.newBox('success', type + 'reseted');
$location.url("/");
2017-12-14 02:20:38 +00:00
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when reseting ' + type + ':', response.data);
});
}
};
2017-01-15 01:37:59 +00:00
})
.controller("PublicController", function($scope, $rootScope, Scene, Theme, Teams, Exercice) {
2017-01-20 18:18:43 +00:00
$scope.scenes = Scene.query();
$scope.themes = Theme.query();
$scope.teams = Teams.get();
$scope.types = {
"welcome": "Messages de bienvenue",
2017-12-17 19:44:23 +00:00
"countdown": "Compte à rebours",
2017-01-20 18:18:43 +00:00
"message": "Message",
"panel": "Boîte",
"exercice": "Exercice",
"table": "Tableau",
"rank": "Classement",
};
$scope.welcome_types = {
2017-12-17 19:44:23 +00:00
"teams": "Accueil des équipes",
2017-01-20 18:18:43 +00:00
"public": "Accueil du public",
};
2017-12-17 19:44:23 +00:00
$scope.colors = {
"primary": "Primaire",
"secondary": "Secondaire",
"info": "Info",
"success": "Success",
"warning": "Warning",
"danger": "Danger",
"light": "Clair",
"dark": "Foncé",
2017-01-20 18:18:43 +00:00
};
$scope.rank_types = {
"general": "Classement général",
};
$scope.table_types = {
"levels": "Niveaux d'exercices",
"teams": "Équipes",
};
$scope.exercices = Exercice.query();
$scope.clearScene = function() {
$scope.someUpdt = true;
$scope.scenes = [];
2017-01-20 18:18:43 +00:00
};
2017-12-17 19:44:23 +00:00
$scope.presetScene = function(scene) {
$scope.someUpdt = true;
if (scene == "registration")
$scope.scenes = [
{
type: "welcome",
params: { kind: "teams" },
},
{
type: "welcome",
params: { kind: "public", notitle: true },
},
];
else if (scene == "welcome")
$scope.scenes = [
{
type: "welcome",
params: { kind: "public" },
},
];
else if (scene == "start")
$scope.scenes = [
{
type: "welcome",
params: { kind: "public" },
},
{
type: "countdown",
params: { color: "success", end: null, lead: "Go, go, go !", title: "Le challenge forensic va bientôt commencer !" },
},
];
else if (scene == "summary") {
$scope.scenes = [
{
type: "table",
params: { kind: "levels", themes: $scope.themes.map(function(z, i) { return z.id; }), total: true },
},
{
type: "rank",
params: { limit: 5, which: "general" },
},
];
}
};
2017-01-20 18:18:43 +00:00
$scope.saveScenes = function() {
$scope.someUpdt = false;
var prms = Scene.update($scope.scenes);
prms.$promise.then(function() {
$rootScope.newBox('success', 'Scene successfully published!');
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when saving scene:', response.data);
});
2017-01-20 18:18:43 +00:00
};
$scope.addScene = function() {
$scope.someUpdt = true;
2017-01-20 18:18:43 +00:00
$scope.scenes.push({params: {}});
};
$scope.delScene = function(s) {
$scope.someUpdt = true;
2017-01-20 18:18:43 +00:00
angular.forEach($scope.scenes, function(scene, k) {
if (scene == s)
$scope.scenes.splice(k, 1);
});
};
$scope.upScene = function(s) {
$scope.someUpdt = true;
2017-01-20 18:18:43 +00:00
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) {
$scope.someUpdt = true;
2017-01-20 18:18:43 +00:00
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;
}
});
};
})
2016-12-26 02:44:04 +00:00
.controller("EventsListController", function($scope, Event, $location) {
$scope.events = Event.query();
$scope.fields = ["id", "kind", "txt", "time"];
$scope.clearEvents = function(id) {
Event.delete(function() {
$scope.events = [];
});
};
$scope.show = function(id) {
$location.url("/events/" + id);
};
})
.controller("EventController", function($scope, Event, $routeParams, $location) {
$scope.event = Event.get({ eventId: $routeParams.eventId });
$scope.fields = ["kind", "txt", "time"];
$scope.kinds = {
2017-12-17 15:07:04 +00:00
"alert-secondary": "Par défaut",
"alert-primary": "Mise en valeur",
2016-12-26 02:44:04 +00:00
"alert-info": "Info",
"alert-warning": "Warning",
2017-03-31 17:37:47 +00:00
"alert-success": "Success",
"alert-danger": "Danger",
2017-12-17 15:07:04 +00:00
"alert-light": "Clair",
"alert-dark": "Foncé",
2016-12-26 02:44:04 +00:00
};
$scope.saveEvent = function() {
if (this.event.id) {
this.event.$update();
} else {
this.event.$save(function() {
$location.url("/events/" + $scope.event.id);
});
}
}
$scope.deleteEvent = function() {
this.event.$remove(function() { $location.url("/events/");});
}
})
2017-12-17 14:39:20 +00:00
.controller("ThemesListController", function($scope, Theme, $location, $rootScope, $http) {
2016-01-22 16:37:29 +00:00
$scope.themes = Theme.query();
$scope.fields = ["id", "name"];
$scope.show = function(id) {
$location.url("/themes/" + id);
};
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.sync = function() {
$scope.inSync = true;
$http({
url: "/api/sync/themes",
method: "GET"
}).then(function(response) {
$scope.inSync = false;
$scope.themes = Theme.query();
if (response.data)
$rootScope.newBox('danger', response.data);
else
$rootScope.newBox('success', 'Synchronisation de la liste des thèmes terminée avec succès.');
}, function(response) {
$scope.inSync = false;
$rootScope.newBox('danger', 'An error occurs when synchronizing theme list:', response.data);
});
};
2016-01-22 16:37:29 +00:00
})
2017-12-17 14:39:20 +00:00
.controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) {
2016-01-22 16:37:29 +00:00
$scope.theme = Theme.get({ themeId: $routeParams.themeId });
2016-12-26 00:20:06 +00:00
$scope.fields = ["name", "authors"];
2016-01-22 16:37:29 +00:00
$scope.saveTheme = function() {
if (this.theme.id) {
this.theme.$update();
} else {
this.theme.$save(function() {
$location.url("/themes/" + $scope.theme.id);
});
}
2016-12-26 00:20:06 +00:00
}
$scope.deleteTheme = function() {
this.theme.$remove(function() { $location.url("/themes/");});
2016-01-22 16:37:29 +00:00
}
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.syncExo = function() {
$scope.inSync = true;
$http({
url: "/api/sync/themes/" + $scope.theme.id + "/exercices",
method: "GET"
}).then(function(response) {
$scope.inSync = false;
$scope.theme = Theme.get({ themeId: $routeParams.themeId });
if (response.data)
$rootScope.newBox('warning', null, response.data, -1);
else
$rootScope.newBox('success', 'Synchronisation de la liste des exercices terminée avec succès.');
}, function(response) {
$scope.inSync = false;
$rootScope.newBox('danger', 'An error occurs when synchrinizing exercices:', response.data);
});
};
2016-01-22 16:37:29 +00:00
})
2017-12-17 14:39:20 +00:00
.controller("AllExercicesListController", function($scope, Exercice, $routeParams, $location, $rootScope, $http) {
2016-12-26 00:23:31 +00:00
$scope.exercices = Exercice.query();
$scope.fields = ["title", "statement", "overview", "videoURI"];
2016-01-22 16:37:29 +00:00
$scope.show = function(id) {
2016-12-26 00:23:31 +00:00
$location.url("/exercices/" + id);
2016-01-22 16:37:29 +00:00
};
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.syncFull = function() {
$scope.inSync = true;
$scope.done = -1;
$scope.total = 0;
var work = [];
var go = function() {
if (!work.length) {
$rootScope.newBox('info', "Synchronisation des exercices terminée.");
$scope.inSync = false;
return;
}
var u = work.pop();
$http({
url: u,
method: "GET"
}).then(function(response) {
$scope.done += 1;
go();
}, function(response) {
$scope.done += 1;
go();
});
};
angular.forEach($scope.exercices, function(ex) {
if ($scope.syncFiles)
work.push("/api/sync/exercices/" + ex.id + "/files");
if ($scope.syncHints)
work.push("/api/sync/exercices/" + ex.id + "/hints");
if ($scope.syncKeys)
work.push("/api/sync/exercices/" + ex.id + "/keys");
});
$scope.total = work.length;
go();
};
$scope.syncFiles = true;
$scope.syncHints = true;
$scope.syncKeys = true;
2016-01-22 16:37:29 +00:00
})
2016-12-26 00:23:31 +00:00
.controller("ExercicesListController", function($scope, ThemedExercice, $routeParams, $location) {
$scope.exercices = ThemedExercice.query({ themeId: $routeParams.themeId });
$scope.fields = ["title", "statement", "overview", "videoURI"];
2016-01-22 16:37:29 +00:00
2016-12-26 00:23:31 +00:00
$scope.show = function(id) {
$location.url("/themes/" + $routeParams.themeId + "/exercices/" + id);
};
})
.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 });
}
2016-12-26 00:23:31 +00:00
$scope.exercices = Exercice.query();
$scope.fields = ["title", "statement", "overview", "depend", "gain", "coefficient", "videoURI"];
2016-12-26 00:23:31 +00:00
$scope.saveExercice = function() {
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);
});
}
2016-12-26 00:23:31 +00:00
}
})
2017-12-17 14:39:20 +00:00
.controller("ExerciceFilesController", function($scope, ExerciceFile, $routeParams, $rootScope, $http) {
2016-12-26 00:23:31 +00:00
$scope.files = ExerciceFile.query({ exerciceId: $routeParams.exerciceId });
$scope.deleteFile = function() {
this.file.$delete(function() {
$scope.files.splice($scope.files.indexOf(this.file), 1);
});
return false;
2016-12-26 00:23:31 +00:00
}
$scope.saveFile = function() {
this.file.$update();
}
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.syncFiles = function() {
$scope.inSync = true;
$http({
url: "/api/sync/exercices/" + $routeParams.exerciceId + "/files",
method: "GET"
}).then(function(response) {
$scope.inSync = false;
$scope.files = ExerciceFile.query({ exerciceId: $routeParams.exerciceId });
if (response.data)
$rootScope.newBox('danger', response.data);
else
$rootScope.newBox('success', "Synchronisation de la liste de drapeaux terminée avec succès.");
}, function(response) {
$scope.inSync = false;
$rootScope.newBox('danger', 'An error occurs when synchronizing flags list:', response.data);
});
};
2016-12-26 00:23:31 +00:00
})
2017-12-17 14:39:20 +00:00
.controller("ExerciceHintsController", function($scope, ExerciceHint, $routeParams, $rootScope, $http) {
2016-12-26 00:23:31 +00:00
$scope.hints = ExerciceHint.query({ exerciceId: $routeParams.exerciceId });
$scope.addHint = function() {
$scope.hints.push(new ExerciceHint());
}
2016-12-26 00:23:31 +00:00
$scope.deleteHint = function() {
this.hint.$delete(function() {
$scope.hints.splice($scope.hints.indexOf(this.hint), 1);
});
2016-12-26 00:23:31 +00:00
}
$scope.saveHint = function() {
if (this.hint.id) {
this.hint.$update();
} else {
this.hint.$save({ exerciceId: $routeParams.exerciceId });
}
2016-12-26 00:23:31 +00:00
}
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.syncHints = function() {
$scope.inSync = true;
$http({
url: "/api/sync/exercices/" + $routeParams.exerciceId + "/hints",
method: "GET"
}).then(function(response) {
$scope.inSync = false;
$scope.hints = ExerciceHint.query({ exerciceId: $routeParams.exerciceId });
if (response.data)
$rootScope.newBox('danger', response.data);
else
$rootScope.newBox('success', "Synchronisation de la liste d'indices terminée avec succès.");
}, function(response) {
$scope.inSync = false;
$rootScope.newBox('danger', 'An error occurs when synchronizing hints list:', response.data);
});
};
2016-12-26 00:23:31 +00:00
})
2017-12-17 14:39:20 +00:00
.controller("ExerciceKeysController", function($scope, ExerciceKey, $routeParams, $rootScope, $http) {
2016-12-26 00:23:31 +00:00
$scope.keys = ExerciceKey.query({ exerciceId: $routeParams.exerciceId });
$scope.addKey = function() {
$scope.keys.push(new ExerciceKey());
}
2016-12-26 00:23:31 +00:00
$scope.deleteKey = function() {
this.key.$delete(function() {
$scope.keys.splice($scope.keys.indexOf(this.key), 1);
});
2016-12-26 00:23:31 +00:00
}
$scope.saveKey = function() {
if (this.key.id) {
this.key.$update();
} else {
this.key.$save({ exerciceId: $routeParams.exerciceId });
}
2016-01-22 16:37:29 +00:00
}
2017-12-17 14:39:20 +00:00
$scope.inSync = false;
$scope.syncKeys = function() {
$scope.inSync = true;
$http({
url: "/api/sync/exercices/" + $routeParams.exerciceId + "/keys",
method: "GET"
}).then(function(response) {
$scope.inSync = false;
$scope.keys = ExerciceKey.query({ exerciceId: $routeParams.exerciceId });
if (response.data)
$rootScope.newBox('danger', response.data);
else
$rootScope.newBox('success', "Synchronisation de la liste de drapeaux terminée avec succès.");
}, function(response) {
$scope.inSync = false;
$rootScope.newBox('danger', 'An error occurs when synchronizing flags list:', response.data);
});
};
2016-01-22 16:37:29 +00:00
})
2016-01-13 00:22:54 +00:00
.controller("TeamsListController", function($scope, Team, $location) {
$scope.teams = Team.query();
2016-10-13 17:52:54 +00:00
$scope.fields = ["id", "name", "initialName"];
2016-01-13 00:22:54 +00:00
$scope.show = function(id) {
$location.url("/teams/" + id);
};
2016-01-22 16:37:29 +00:00
})
.controller("TeamMembersController", function($scope, TeamMember) {
2017-01-28 18:36:28 +00:00
$scope.fields = ["firstname", "lastname", "nickname", "company"];
if ($scope.team != null) {
$scope.members = TeamMember.query({ teamId: $scope.team.id });
2017-01-28 18:36:28 +00:00
$scope.newMember = function() {
$scope.members.push(new TeamMember());
}
$scope.saveTeamMembers = function() {
if (this.team.id) {
TeamMember.save({ teamId: this.team.id }, $scope.members);
}
}
$scope.removeMember = function(member) {
angular.forEach($scope.members, function(m, k) {
if (member == m)
$scope.members.splice(k, 1);
});
}
}
2017-01-28 18:36:28 +00:00
})
.controller("TeamController", function($scope, $rootScope, $location, Team, TeamMember, $routeParams, $http) {
2016-10-13 17:52:54 +00:00
$scope.team = Team.get({ teamId: $routeParams.teamId });
2017-01-28 18:36:28 +00:00
$scope.fields = ["name", "color"];
$scope.hasCertificate = false;
$http({
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate.p12",
method: "HEAD",
transformResponse: null
}).then(function(response) {
$scope.hasCertificate = true;
}, function(response) {
$scope.hasCertificate = false;
});
$scope.generateCertificate = function() {
$http({
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate/generate",
method: "GET",
transformResponse: null
}).then(function(response) {
$scope.hasCertificate = true;
$rootScope.newBox('success', 'Team certificate successfully generated!');
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when generating certiticate:', response.data);
});
}
$scope.revokeCertificate = function() {
if (!confirm("Are you sure you want to revoke this certificate?"))
return false;
$http({
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate.p12",
method: "DELETE",
transformResponse: null
}).then(function(response) {
$scope.hasCertificate = false;
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when revoking the certiticate:', response.data);
});
}
2017-01-28 18:36:28 +00:00
$scope.saveTeam = function() {
if (this.team.id) {
this.team.$update();
} else {
this.team.$save(function() {
$location.url("/teams/" + $scope.team.id);
});
}
}
$scope.deleteTeam = function() {
backName = this.team.name;
this.team.$remove(function() { $rootScope.newBox('success', 'Team ' + backName + ' successfully removed.'); $location.url("/teams/"); },
function(response) { console.log($rootScope.newBox); $rootScope.newBox('danger', 'An error occurs during suppression of the team:', response.data); });
2017-01-28 18:36:28 +00:00
}
$scope.showStats = function() {
$location.url("/teams/" + $scope.team.id + "/stats");
}
2016-10-13 17:52:54 +00:00
})
2017-11-12 23:57:48 +00:00
.controller("TeamHistoryController", function($scope, TeamHistory, $routeParams) {
$scope.history = TeamHistory.query({ teamId: $routeParams.teamId });
})
2016-10-13 17:52:54 +00:00
.controller("TeamStatsController", function($scope, TeamStats, $routeParams) {
$scope.teamstats = TeamStats.get({ teamId: $routeParams.teamId });
$scope.teamstats.$promise.then(function(res) {
solvedByLevelPie("#pieLevels", res.levels);
var themes = [];
angular.forEach(res.themes, function(theme, tid) {
themes.push(theme);
})
solvedByThemesPie("#pieThemes", themes);
2016-10-13 17:52:54 +00:00
});
})
.controller("TeamExercicesController", function($scope, Teams, Themes, TeamMy, Exercice, $routeParams) {
$scope.teams = Teams.get();
$scope.themes = Themes.get();
$scope.exercices = Exercice.query();
$scope.my = TeamMy.get({ teamId: $routeParams.teamId });
$scope.teams.$promise.then(function(res){
$scope.nb_teams = 0;
$scope.nb_reg_teams = Object.keys(res).length;
angular.forEach(res, function(team, tid) {
if (team.rank)
$scope.nb_teams += 1;
}, 0);
});
$scope.my.$promise.then(function(res){
$scope.solved_exercices = 0;
angular.forEach(res.exercices, function(exercice, eid) {
2017-01-16 12:09:31 +00:00
if (exercice.solved_rank) {
2016-10-13 17:52:54 +00:00
$scope.solved_exercices += 1;
}
}, 0);
});
})
.controller("PresenceController", function($scope, TeamPresence, $routeParams) {
$scope.presence = TeamPresence.query({ teamId: $routeParams.teamId });
$scope.presence.$promise.then(function(res) {
2017-04-02 09:38:40 +00:00
presenceCal($scope, "#presenceCal", res);
2016-10-13 17:52:54 +00:00
});
})
2017-04-02 09:38:40 +00:00
.controller("CountdownController", function($scope, $rootScope, $http, $timeout) {
2016-10-13 17:52:54 +00:00
$scope.time = {};
function updTime() {
$timeout.cancel($scope.cbm);
$scope.cbm = $timeout(updTime, 1000);
if (sessionStorage.userService) {
var time = angular.fromJson(sessionStorage.userService);
var srv_cur = (Date.now() + (time.cu * 1000 - time.he)) / 1000;
var remain = time.du;
if (time.st == Math.floor(srv_cur)) {
$scope.refresh(true);
}
if (time.st > 0 && time.st <= srv_cur) {
2017-01-16 12:14:55 +00:00
$scope.startIn = 0;
2016-10-13 17:52:54 +00:00
remain = time.st + time.du - srv_cur;
2017-01-16 12:14:55 +00:00
} else if (time.st > 0) {
$scope.startIn = Math.floor(time.st - srv_cur);
2016-10-13 17:52:54 +00:00
}
if (remain < 0) {
remain = 0;
$scope.time.end = true;
$scope.time.expired = true;
} else if (remain < 60) {
$scope.time.end = false;
$scope.time.expired = true;
} else {
$scope.time.end = false;
$scope.time.expired = false;
}
$scope.time.start = time.st * 1000;
$scope.time.duration = time.du * 1000;
$scope.time.remaining = remain;
$scope.time.hours = Math.floor(remain / 3600);
$scope.time.minutes = Math.floor((remain % 3600) / 60);
$scope.time.seconds = Math.floor(remain % 60);
2017-04-02 09:38:40 +00:00
$rootScope.time = $scope.time;
2016-10-13 17:52:54 +00:00
}
}
2017-12-14 02:20:38 +00:00
$http.get("/time.json").then(function(time) {
2016-10-13 17:52:54 +00:00
time.he = (new Date()).getTime();
sessionStorage.userService = angular.toJson(time);
updTime();
});
});
function solvedByLevelPie(location, data) {
var width = d3.select(location).node().getBoundingClientRect().width - 10,
height = d3.select(location).node().getBoundingClientRect().width - 10,
radius = Math.min(width, height) / 2,
innerRadius = 0.1 * radius;
var color = d3.scale.ordinal()
.range(["#9E0041", "#C32F4B", "#E1514B", "#F47245", "#FB9F59", "#FEC574", "#FAE38C", "#EAD195", "#C7E89E", "#9CD6A4", "#6CC4A4", "#4D9DB4", "#4776B4", "#5E4EA1"]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.width; });
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(function (d) {
return (radius - innerRadius) * (d.data.score / 100.0) + innerRadius;
});
var outlineArc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(radius);
var svg = d3.select(location).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data.forEach(function(d) {
d.score = d.solved * 100 / d.total;
d.width = d.tries + 1;
2016-01-13 00:22:54 +00:00
});
2016-10-13 17:52:54 +00:00
var path = svg.selectAll(".solidArc")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d) { return color(d.data.tip); })
.attr("class", "solidArc")
.attr("stroke", "gray")
.attr("d", arc);
var outerPath = svg.selectAll(".outlineArc")
.data(pie(data))
.enter().append("path")
.attr("fill", "none")
.attr("stroke", "gray")
.attr("class", "outlineArc")
.attr("d", outlineArc);
var labelArc = d3.svg.arc()
.outerRadius(0.8 * radius)
.innerRadius(0.8 * radius);
svg.selectAll(".labelArc")
.data(pie(data))
.enter().append("text")
.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.data.tip + ": " + d.data.solved + "/" + d.data.total; });
svg.selectAll(".label2Arc")
.data(pie(data))
.enter().append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.data.tries; });
}
function solvedByThemesPie(location, data) {
var width = d3.select(location).node().getBoundingClientRect().width,
height = d3.select(location).node().getBoundingClientRect().width,
radius = Math.min(width, height) / 2,
innerRadius = 0.1 * radius;
var color = d3.scale.ordinal()
.range(["#9E0041", "#C32F4B", "#E1514B", "#F47245", "#FB9F59", "#FEC574", "#FAE38C", "#EAD195", "#C7E89E", "#9CD6A4", "#6CC4A4", "#4D9DB4", "#4776B4", "#5E4EA1"]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.width; });
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(function (d) {
return (radius - innerRadius) * (d.data.score / 100.0) + innerRadius;
});
var outlineArc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(radius);
var svg = d3.select(location).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data.forEach(function(d) {
d.score = d.solved * 100 / d.total;
d.width = d.tries + 0.5;
});
var path = svg.selectAll(".solidArc")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d) { return color(d.data.tip); })
.attr("class", "solidArc")
.attr("stroke", "gray")
.attr("d", arc);
var outerPath = svg.selectAll(".outlineArc")
.data(pie(data))
.enter().append("path")
.attr("fill", "none")
.attr("stroke", "gray")
.attr("class", "outlineArc")
.attr("d", outlineArc);
svg.selectAll(".label2Arc")
.data(pie(data))
.enter().append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.data.solved; });
var labelArc = d3.svg.arc()
.outerRadius(0.8 * radius)
.innerRadius(0.8 * radius);
svg.selectAll(".labelArc")
.data(pie(data))
.enter().append("text")
.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.data.tip + ": " + d.data.tries; });
}
2017-04-02 09:38:40 +00:00
function presenceCal(scope, location, data) {
2016-10-13 17:52:54 +00:00
var width = d3.select(location).node().getBoundingClientRect().width,
height = 80,
cellSize = 17; // cell size
var percent = d3.format(".1%"),
format = d3.time.format("%H:%M");
var color = d3.scale.quantize()
.domain([0, 16])
.range(d3.range(8).map(function(d) { return "q" + d + "-8"; }));
var svg = d3.select(location).selectAll("svg")
2017-04-02 09:38:40 +00:00
.data(d3.range(scope.time.start, scope.time.start + (scope.time.start % 86400000 + scope.time.duration), 86400000).map(function(t) { return new Date(t); }))
2016-10-13 17:52:54 +00:00
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "RdYlGn")
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 24) / 2) + "," + (height - cellSize * 4 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-6," + cellSize * 2.6 + ")rotate(-90)")
.style("text-anchor", "middle")
2017-04-02 09:38:40 +00:00
.text(function(d) { return d.getDate() + "-" + (d.getMonth() + 1); });
2016-10-13 17:52:54 +00:00
var rect = svg.selectAll(".quarter")
2017-04-02 09:38:40 +00:00
.data(function(d) { return d3.time.minutes(new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0), new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23), 15); })
2016-10-13 17:52:54 +00:00
.enter().append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
2017-04-02 09:38:40 +00:00
.attr("transform", function(d) { return "translate(" + (d.getHours() * cellSize) + "," + (d.getMinutes() / 15 * cellSize) + ")"; })
.attr("class", function(d) { if (d >= scope.time.start && d < scope.time.start + scope.time.duration) return color(data.reduce(function(prev, cur){
2016-10-13 17:52:54 +00:00
cur = new Date(cur).getTime();
dv = d.getTime();
return prev + ((dv <= cur && cur < dv+15*60000)?1:0);
}, 0)); });
}