299 Commits

Author SHA1 Message Date
ab5cf04822 Update glusterfs 2021-06-22 08:46:15 +02:00
aedfa21b00 correction coquille 2020-10-19 11:06:43 +02:00
c65d71b269 mise à jour procedure ldap 2020-10-19 10:53:24 +02:00
5b747460ef Adding missing slides 2020-10-19 10:38:51 +02:00
f019329420 Cleanup glusterfs 2020-10-19 09:34:58 +02:00
bc6803e5ac commande utiles glusterfs 2020-10-16 16:47:33 +02:00
6c2f9b1e85 Updating details 2020-10-16 16:37:10 +02:00
a8d4149017 redaction procédure et archi-détaillée pour les dns 2020-10-09 17:02:16 +02:00
ec3cb2a05f redaction archi détaillées et procdure 2020-10-09 14:32:19 +02:00
414b6b44b2 Merge branch 'formation-mse-2020' of ssh://forge.cadoles.com:4242/cadoles/formations into formation-mse-2020 2020-10-09 11:18:45 +02:00
b36cf1a5f4 réalisation plan et commentaire slide a écrire 2020-10-09 11:18:13 +02:00
aeb6855270 Cleanup 2020-10-09 10:42:00 +02:00
356be79686 formation personnalisée MSE deuxième partie 2020-10-09 10:28:24 +02:00
3b94172f3c modif 2020-10-09 09:44:44 +02:00
4743f4ce6d correction orthographique 2020-01-30 17:25:53 +01:00
9c09d702ce formation tc1 et base architecture MSE 2020-01-30 16:50:42 +01:00
b2b0764be2 désactivation de l'état LB qui fait rebooter la machine non stop 2019-11-05 15:25:43 +01:00
f0de8947a0 mise à jour des formations 2019-10-10 12:28:04 +02:00
912314e24f Mise à jour notes formation NoSQL 2019-10-03 10:50:06 +02:00
8a06e036a1 Merge branch 'master' of ssh://forge.cadoles.com:4242/Cadoles/formations 2019-10-03 10:49:27 +02:00
ad6aced650 Ajout documents pour cours NoSQL 2019-09-22 22:14:24 +02:00
0091d980b3 Cours hébergement web 2019-05-20 11:25:26 +02:00
4dca21830a Programme de formation pour l’ain 2019-05-10 10:49:45 +02:00
2a39b88df1 Merge branch 'master' of https://forge.cadoles.com/Cadoles/formations 2019-03-25 13:23:10 +01:00
42e475449d Mise à jour des listes de modules disponibles 2019-03-19 16:01:32 +01:00
a699b7551d ajout cours agile cesi 2019-03-15 09:35:55 +01:00
2a06cee004 CESI: Ajout fiche module Hébergement Web + feuille de notation 2019-02-06 14:13:21 +01:00
a3bce17093 Ajout ressources formation CESI: Hébergement Web 2019-02-06 14:10:04 +01:00
b48ccf2bb2 Mise à jour du programme amon/sphynx 2019-02-06 11:36:52 +01:00
18647029a7 ajouter l'option shell-escape à xelatex pour les exercices TC2 2018-12-20 15:24:13 +01:00
a970852f3b CESI - Exo Microbloggr Solution - Création de statuts fonctionnelle 2018-11-28 16:56:54 +01:00
eaa659f3c6 CESI - Exo Microbloggr Solution - Authentification fonctionnelle 2018-11-28 14:47:09 +01:00
68ccdca3a4 Intro Big Data: mise à jour slides + données d'exemple graphe 2018-09-27 07:23:06 +02:00
89ba44063d Architecture N Tiers: ajout QCM 2018-09-27 07:20:36 +02:00
4c92c99472 some cleaning 2018-09-13 10:09:32 +02:00
a58dc496c4 CESI: Intro Big Data - ajout exercice bdd clé/valeur et graphe 2018-09-05 21:54:11 +02:00
8f84189ed5 CESI: Intro Big Data - ajout tuile + exercice BDD orientée graphe 2018-09-05 07:30:09 +02:00
a29c349d75 CESI: Intro Big Data, biblio + environnement démo Hadoop 2018-08-24 17:17:35 +02:00
37fccd7d8c algo et data science 2018-08-24 14:09:25 +02:00
ff92e072df CESI: Intro Big Data, base bibliographie 2018-08-22 11:26:45 +02:00
2db270359c python2 -> python subfolder 2018-08-21 10:26:27 +02:00
ee81eaad1b en and fr python3 courses 2018-08-21 10:25:44 +02:00
8c6997b27d ancien cours python -> python2 2018-08-20 21:02:38 +02:00
8ab75d1eac algorithmique : api et paramètres 2018-08-20 21:01:58 +02:00
9220531442 CESI: DevOps, mise à jour des slides 2018-06-28 06:50:04 +02:00
1ead473830 CESI: Métiers DevOps, base slides 2018-06-27 16:09:39 +02:00
bee347f833 DIIAGE: session 23/03/2018 2018-03-23 11:51:43 +01:00
2aea564151 Logomotion: React+Redux, corrections typo 2018-03-22 18:08:34 +01:00
1baa61d2e8 Logomotion: Qualification 2018-03-20 14:03:21 +01:00
74a2e26f18 Logomotion: React + Redux 2018-03-12 21:20:13 +01:00
7c0f21ae7f CESI: Architectures N Tiers, ajout mini projet 'Alfred' 2018-03-05 19:07:27 +01:00
5f537a3a77 DIIAGE: ajout derniers cours 2018-03-02 12:03:52 +01:00
5255503103 Logomotion: Base des slides pour la formation sur la qualification 2018-02-20 09:03:38 +01:00
e4cad32252 CESI: Sécurité entreprise, maquette + support OK 2018-02-04 18:27:46 +01:00
56066ac24f CESI: Sécurité des entreprises, infrastructure Vagrant avec supervision Prometheus 2018-02-04 15:55:09 +01:00
85d1a97452 CESI: présentation + maquette Vagrant Sécurité entreprise 2018-02-01 17:35:41 +01:00
482bc0e960 Logomotion: maj formation Sécurité Web 2018-01-25 22:10:30 +01:00
0fe8dd7112 Logomotion: Sécurité Web, sécurisation du serveur GNU/Linux 2018-01-23 22:46:57 +01:00
171b1e512c Logomotion: sécurité web, ajout exercice métrologie 2018-01-22 22:33:49 +01:00
16df9d12da CESI: Architecture N Tiers, exemple microservices 2018-01-22 22:14:30 +01:00
7cefd73d13 Logomotion: Sécurité Web 2018-01-22 22:13:04 +01:00
03b9ed5f1e DIIAGE: session 19/01/2018 2018-01-19 11:50:12 +01:00
0eb9d2e1e1 DIIAGE: Prépa session 19/01/2018 2018-01-17 22:58:53 +01:00
608c203acd CESI: architectures n tiers 2018-01-14 21:13:12 +01:00
703ca7d4fb CESI: Architecture N tiers 2018-01-13 18:02:29 +01:00
c8caed6efc CESI: Architecture N tiers, exercice 2018-01-13 16:53:31 +01:00
e041aa9b9f CESI: Architecture N Tiers 2018-01-13 15:28:05 +01:00
ea0439f8ab CESI: mise à jour fiche de préparation Architecture N tiers 2018-01-10 22:42:48 +01:00
f1d44dc9ed Logomotion: mise à jour introduction framework javascript 2018-01-09 22:52:41 +01:00
3a14479bc1 Logomotion: tour d'horizon Javascript, base EmberJS 2018-01-08 23:03:36 +01:00
6eaec99f06 Logomotion: Introduction Javascript 2018-01-08 17:35:19 +01:00
8d4a57ed9b Logomotion: slides Symfony3 seconde journée 2017-12-27 16:12:22 +01:00
63cb07d03e Logomotion: suites des slides Symfony3 2017-12-26 17:38:01 +01:00
cdc80c6a5f CESI: réorganisation de l'arborescence 2017-12-26 10:46:56 +01:00
fc85a3a7f1 DIIAGE: réorganisation des questions 2017-12-26 10:46:06 +01:00
25d1f582a8 DIIAGE: TP sécurité des applicaiton web & métrologie appliquée à la sécurité 2017-12-22 10:16:12 +01:00
4d76474d99 Logomotion: Volet sécurité des applications Web, métrologie / prometheus 2017-12-21 16:55:59 +01:00
03faa7a663 Diiage: préparation QCM évaluation 22/12/2017 2017-12-20 12:00:44 +01:00
a130fab2f8 Remise à niveau Symfony3: slides 2017-12-14 22:14:18 +01:00
ccb80c82e7 Symfony3: slides + revue planning journée 1 2017-12-14 20:05:25 +01:00
cb42e8734b Remise à niveau Symfony3: slides + planning 2017-12-14 17:32:17 +01:00
729f2c318a CESI: Mise à jour slides/planning "Sécurité en entreprise" 2017-12-12 11:35:12 +01:00
3050355eb5 CESI: Mise à jour programme formation "Sécurité en entreprise" 2017-12-11 17:17:43 +01:00
0ed669f1ae Ajout des fichiers de lock LibreOffice à la liste des ignorés 2017-12-11 15:48:06 +01:00
0c3263693a CESII: Mise à jour slides, planning et notes 2017-12-11 15:46:52 +01:00
f357f5ac72 CESII: Slides formation sécurité entreprise 2017-12-11 14:06:38 +01:00
ee8cfea049 DIIAGE: mise à jour sujet TP 2017-12-08 12:03:24 +01:00
8085490457 DIIAGE: Préparation session 20171208 2017-12-08 11:38:41 +01:00
e3e4b6291f Ajout rendus TP 2017-12-08 11:37:44 +01:00
bd7082e887 Préparation cours DIIAGE 08/12/2017 2017-12-06 22:04:40 +01:00
00f9d125d1 Création de fiches d'exemple 2017-11-17 12:07:08 +01:00
f383613cbd Ajout supports formation DIIAGE (DEV & RES 3) 2017-11-16 16:27:53 +01:00
affa70b31c algo avancée 2017-10-24 17:13:41 +02:00
63c4a7e2fc exercices de programmation raisonnée 2017-10-23 18:05:32 +02:00
05e68b4d5e algo avancée 2017-10-17 16:23:38 +02:00
2edd0ea2f1 algo : problèmes NP complets 2017-10-17 14:18:26 +02:00
9ad29e7541 méthodes de tri rapide en python 2017-10-16 17:16:19 +02:00
75bb842bb6 support de cours algo avancée - correction unicode 2017-10-16 16:27:16 +02:00
6a50f7f261 support de cours algo avancée 2017-10-16 15:35:34 +02:00
dd24407b76 contrainte de type par signature 2017-10-12 18:21:33 +02:00
2214b33090 corrections cours poo 2017-10-05 09:18:23 +02:00
b73e7c85ff premiere version stable du cours de poo 2017-10-02 09:11:10 +02:00
86e9646de9 Correction du public pour les méthodes AGile 2017-09-29 16:05:30 +02:00
adde21ff9d Merge branch 'master' of https://forge.cadoles.com/Cadoles/formations 2017-09-29 16:02:54 +02:00
99ff34a750 relecture de qualification 2017-09-29 15:42:15 +02:00
a4f78eb243 relecture des méthodes agiles 2017-09-29 15:38:04 +02:00
2d247ba285 relecture de la messagerie électronique 2017-09-29 15:33:03 +02:00
52f602e8bf relecture 2017-09-29 15:27:14 +02:00
512951e208 relecture 2017-09-29 15:23:47 +02:00
b607c5717a relecture 2017-09-29 15:19:14 +02:00
c92060f849 relecture 2017-09-29 15:12:55 +02:00
b3b2cde6a1 relecture 2017-09-29 15:06:13 +02:00
bfe90bfcac Mise à jour durée 2017-09-29 14:55:42 +02:00
1b6b43878b Coquillesé 2017-09-29 14:27:49 +02:00
d499847408 Programme de formation Logomotion - version LaTeX 2017-09-29 14:12:15 +02:00
5193436497 Retour de inc dans le dépôt 2017-09-29 13:22:52 +02:00
354a2bbb40 Merge branch 'master' of https://forge.cadoles.com/Cadoles/formations 2017-09-29 13:20:11 +02:00
af6e948714 Relecture - Corrections 2017-09-29 13:19:50 +02:00
c88cd4938a Retour du style dans le dépôt 2017-09-29 13:16:31 +02:00
12b0b87911 Mise à jour du tire de la formation 2017-09-29 12:58:36 +02:00
e8bd5fbff7 Mise à jour du tire de la formation 2017-09-29 12:55:13 +02:00
da9fdc71a2 Mise à jour des plans de formation methodes agiles, qualification et smtp-imap 2017-09-29 12:53:34 +02:00
78931654ac Now we can build only one program
./programme.sh my_directory
2017-09-29 12:49:00 +02:00
1eacf73b67 Ajout du programme de qualification 2017-09-29 11:42:47 +02:00
1a75329228 Merge branch 'master' of https://forge.cadoles.com/Cadoles/formations 2017-09-29 11:09:30 +02:00
2a02aec42b Ajout du programme de la formation AGILE 2017-09-29 11:09:12 +02:00
8515e2c8ef Precisions partie symfony 3 2017-09-29 10:29:41 +02:00
789ec739ae Ajout du plan de formation pour Logomotion 2017-09-29 09:40:16 +02:00
cfe5783d6d Ajout du programme pour la formation smtp-imap 2017-09-28 14:02:18 +02:00
1645146d0d modèle objet de python 2017-09-05 09:25:48 +02:00
2ddd3e2c18 méchanismes objets 2017-09-04 17:33:56 +02:00
075a54ecf1 debut du cours de poo 2017-09-04 14:54:33 +02:00
a0040a3b00 tronc commun algo/algo approfondie 2017-08-29 15:42:31 +02:00
898dc77569 tronc commun 2017-08-28 17:52:56 +02:00
3bf7596972 menage 2017-08-28 17:37:01 +02:00
dc02e78fff mise en place des cours algo + poo 2017-08-28 17:36:36 +02:00
2843f25795 mise en place des cours poo et algo approfondie 2017-08-21 10:44:20 +02:00
870a4d7743 alog : rappels de cybernétique 2017-08-21 09:32:10 +02:00
abba666231 notes pour amélioration du cours 2017-06-21 10:53:35 +02:00
2ecd65ce3d corrections du cours après la présentation 2017-06-21 10:52:29 +02:00
78cc7f12eb typo 2017-06-09 10:15:08 +02:00
4c53916b12 exercices de travaux pratiques 2017-06-09 09:59:42 +02:00
45f3836f87 premiers sujets de tp 2017-05-29 14:29:23 +02:00
8afd3606f7 logos 2017-05-23 11:16:12 +02:00
357c2ed0a0 diaporama algorithmique 2017-05-23 09:32:17 +02:00
1689ac7145 présentation beamer 2017-05-22 17:54:40 +02:00
fc6208b99c template de présentation beamer 2017-05-19 11:17:58 +02:00
26cc76dcc1 exercices de manipulation des structures de données 2017-05-14 18:17:14 +02:00
5728bb1834 exercices supplémentaires 2017-05-12 11:55:30 +02:00
2840b2627b ajout du diaporama 2017-05-09 09:37:09 +02:00
31835587a6 suprression des warning au build 2017-05-03 09:26:24 +02:00
fd2b6469bf suppression des derniers fixme 2017-05-03 09:21:28 +02:00
ffcd62cd50 cours : premiere version 2017-04-30 08:59:55 +02:00
670c1fe535 algo programmation structurée 2017-04-30 08:44:43 +02:00
48524d751a langage de modules 2017-04-29 23:14:45 +02:00
81545ae4d3 algorithme module python 2017-04-29 20:24:46 +02:00
63a96dbbc3 exercices (maximum d'une liste) 2017-04-28 11:12:19 +02:00
b0f56186f5 modulatié et programmation raisonnée 2017-04-27 16:40:01 +02:00
b49b0690b9 exercices sur les structures de données de base (2) 2017-04-27 14:46:31 +02:00
c8ab39a19e exercices sur les structures de données de base 2017-04-27 14:15:18 +02:00
24cd7ca9c3 exos d'algo 2017-04-27 12:05:13 +02:00
13ca1532ce exercices sur les structures de controle de base 2017-04-27 11:55:24 +02:00
ae3cdd92b3 exercices sur les variables 2017-04-26 11:48:32 +02:00
1470b93a63 exemples d'algorithmes 2017-04-24 15:53:00 +02:00
b634a10b77 Corrections dans l’exercice ircd 2017-04-21 11:36:32 +02:00
32376db319 exemples d'algorithmes sur des structures de données simples 2017-04-21 10:50:53 +02:00
9cdfc16cc5 structures de données (list + dico) 2017-04-20 14:29:38 +02:00
4e29983800 algorithme vague 2017-04-18 21:53:35 +02:00
cf1b3ac498 portée d'une variable 2017-04-13 17:36:25 +02:00
8d16681688 structures de données 2017-04-13 17:08:27 +02:00
12b1a888c6 organisation des exercices 2017-04-13 16:08:30 +02:00
15fd0fa136 programmation modulaire 2017-04-13 10:50:18 +02:00
eb3daeae4e suppresion des Statex des algo de style impératif 2017-04-12 10:22:44 +02:00
2786706b0f ajout d'aperçu des types d'algorithmes 2017-04-11 16:40:26 +02:00
5c9ca22877 utilisation de l'extension ifconfig pour les exercices et les corrections 2017-04-11 14:24:15 +02:00
b37051c78d Merge branch 'master' of ssh://forge.cadoles.com:4242/cadoles/formations 2017-04-11 11:42:53 +02:00
26c756a914 reorganisation du cours 2017-04-11 11:18:17 +02:00
9fb80c6b48 reorganisation du cours 2017-04-10 17:47:40 +02:00
44c153b95c reorganisation (ordonnancement) du cours 2017-04-10 12:36:16 +02:00
86dec22113 presentation du cours d'algo 2017-04-10 12:25:40 +02:00
95231a4253 définition des actions d'un programme 2017-04-07 17:22:05 +02:00
0685998e20 présentation du cours et avant propos 2017-04-07 15:28:36 +02:00
fe81743c51 mise à jour pour PSI + raid logiciel (non inclu) 2017-04-07 13:01:55 +02:00
936de04ce4 algorithme factorielle 2017-04-06 16:57:22 +02:00
813a09034a diveres définitions de la programmation 2017-04-06 14:55:36 +02:00
6de57bca95 définition d'une fonction 2017-04-06 10:36:31 +02:00
6ccddf4cc5 ajout des principales structures de contrôles 2017-04-05 10:36:41 +02:00
b5a77f5212 instruction de saut conditionnel 2017-04-04 10:50:18 +02:00
97d5f66bd5 ajout d'un exemple de procedure 2017-04-03 16:47:10 +02:00
f92c758800 Ajout de la notion de fonction 2017-04-03 16:34:36 +02:00
7e048b9f61 correction orthographique 2017-03-27 14:26:44 +02:00
777323f940 exo avec roundcube et non thunderbird 2017-03-27 14:09:39 +02:00
a769e6bbd7 ajout script création user 2017-03-27 12:14:16 +02:00
ce101ea602 mise en page 2017-03-27 11:57:27 +02:00
7cc6c19799 modification exercice et contenu 2017-03-27 11:36:59 +02:00
7fd17bd06e amelioration création utilisateur Mysql 2017-03-27 11:22:50 +02:00
debf07b509 modification de l'exercice pour l'ajout d'application web 2017-03-27 10:30:27 +02:00
8bc107fa71 maj log squid/e2guardian 2017-03-23 20:24:35 +01:00
b8a3e05f02 maj formation amon 2017-03-23 17:47:51 +01:00
047eb2728d réflexions sur l'abstraction algorithmique 2017-03-23 11:23:49 +01:00
3baed6b4ff définition d'un algorithme 2017-03-22 09:13:07 +01:00
b380a69cfa package algorithm 2017-03-21 11:56:53 +01:00
44f083eb1d section algorithme 2017-03-21 09:10:34 +01:00
aea8e036a3 ajout des annexses 2017-03-20 10:22:04 +01:00
fb6c63feb4 séparation trouver information serveur/internet + ajout info internet dans les différentes formations 2017-03-20 10:13:43 +01:00
2eb826537c ajout des coordonnées du forum EOLE 2017-03-20 09:20:49 +01:00
e1743c32da présentation du cours 2017-03-18 16:37:36 +01:00
ba6fc1b406 debut de glossaire 2017-03-18 16:00:24 +01:00
0d2b2aca4d debut de glossaire 2017-03-18 15:47:40 +01:00
a723cce565 methodes agiles 2017-03-18 07:00:18 +01:00
e9b0afe3ee méthodologies agiles 2017-03-17 11:58:35 +01:00
de765b7431 Merge branch 'master' of ssh://forge.cadoles.com:4242/cadoles/formations 2017-03-17 11:40:30 +01:00
42223ee6bb modification des besoins pour la prépartion de la formation scribe-horus 2017-03-17 11:39:33 +01:00
a967c1e4c5 définition du cours d'algorithmique 2017-03-17 11:36:03 +01:00
9cbe2e337a début du cours d'algorithmique pour le CESI 2017-03-17 11:33:14 +01:00
d7a4bcc466 coorection orthographique et ajout changement bacula-bareos 2017-03-17 10:45:39 +01:00
4d7a2492a7 modification preparation 2017-03-13 16:36:02 +01:00
421c27e85f mise à jour du contenu 2017-03-13 16:16:58 +01:00
64e1002f9b modification formation pour scribe 2.6 et W10 2017-03-13 11:44:03 +01:00
ec18bf72dc modification contenu 2017-02-03 13:47:51 +01:00
1e0822db1c erreur chemin des dicos locals 2017-01-27 17:04:54 +01:00
fceaf18739 mise à jour des excercices tronc-commun-2 2017-01-26 18:06:37 +01:00
09aa743b31 mise à jour formation tc1 et tc2 2017-01-26 17:36:57 +01:00
c0bb8d8cfe Ajout des nouvelles images 2017-01-23 14:33:30 +01:00
2f93009cb2 Ajout 2.6.0 2017-01-23 14:33:13 +01:00
690581f7d6 mise à jour 2017-01-09 15:45:09 +01:00
21700131a0 ajout restauration complète en 2.6 2016-09-19 10:53:05 +02:00
c4bd4b9183 reformulation et correction orthographique 2016-09-01 15:25:47 +02:00
f642003eaf complement dans l'exemple d'exercice 2016-04-27 11:54:37 +02:00
73a5e3d14f corrections 2016-04-26 15:33:54 +02:00
f149b43557 ajout d'un exemple d'exercice corrigé 2016-04-21 17:00:48 +02:00
7987c5bb21 mise à jour de la formation pour 2.6 2016-04-20 10:44:44 +02:00
0ec050b306 Merge branch 'master' of ssh://forge.cadoles.com:4242/cadoles/formations
* 'master' of ssh://forge.cadoles.com:4242/cadoles/formations:
  modification plan et affichage formation
  ajout formation personnalidée sallanches
2015-11-02 16:32:13 +01:00
ee24393082 Fix title 2015-11-02 16:31:06 +01:00
8749c13f6d modification plan et affichage formation 2015-08-04 11:15:47 +02:00
ab17ccefb4 ajout formation personnalidée sallanches 2015-07-28 11:15:56 +02:00
00bda3b860 Adding new background 2015-06-17 15:16:13 +02:00
647a8cb2f2 Update de la formation amon sphynx 2015-06-17 15:01:19 +02:00
d3fedded5e ajout de doc sur les méta classes 2015-06-04 10:10:58 +02:00
5391804ac5 ajout de doc sur les classes et les objets 2015-06-04 09:58:51 +02:00
1e21dbe0f9 corrections coquilles 2015-05-13 15:37:00 +02:00
7ad34d4962 paragraphe generique 2015-05-11 09:16:33 +02:00
47c572334d sphinx et docutils 2015-05-07 09:33:59 +02:00
239097238e ajout des imports et de sys.modules 2015-05-05 15:00:47 +02:00
f52d023781 ajout des design patterns 2015-05-04 17:38:00 +02:00
9d1597fc15 ajout des design patterns 2015-05-04 16:29:15 +02:00
03da3c99a0 ajout de la doc sur les exceptions 2015-05-04 15:38:51 +02:00
03d5f17f6a config pour la version pdf 2015-05-01 10:32:46 +02:00
da6a42f8bb editeurs python : syntaxe 2015-04-30 16:23:39 +02:00
a3552c18c0 editeurs python 2015-04-30 14:57:46 +02:00
30f646581b Exo ngResource 2015-04-10 01:46:41 +02:00
1d015b15d5 Ajout exo protractor 2015-04-10 01:01:21 +02:00
22eb8175fe Ajout exo Karma 2015-04-10 00:30:02 +02:00
24ebf33c75 Ajout exo routage 2015-04-09 23:11:56 +02:00
e0ad7f004d Corrections slides 2015-04-09 20:36:17 +02:00
ccfe7374cc Formation Angular: exos supplémentaires 2015-04-09 01:03:35 +02:00
11b5d82ce4 (not) vanilla todos 2015-04-09 00:19:37 +02:00
16a28eb88b Angular, première partie 2015-04-08 23:22:53 +02:00
de745ba6df Ajout exo services 2015-04-07 22:38:36 +02:00
4df20d8adf Base formation angular+amélioration layout formations JS 2015-04-06 17:50:08 +02:00
e4811d8040 Suppression node_modules exercices 2015-04-03 10:42:28 +02:00
bbcccf4586 Nettoyage exemple tests-unitaires 2015-04-03 10:34:09 +02:00
f4e96ea040 Nettoyage exercices 2015-04-03 10:31:05 +02:00
c645af4112 Correction exo heritge js 2015-04-02 08:43:33 +02:00
b00c6dd3f4 Ajout exercices supplémentaires formation JS 2015-04-01 22:05:05 +02:00
9a2452b334 Corrections typo + exo VanillaTodos complet 2015-04-01 15:11:13 +02:00
16cf72bb59 Ajout exo VanillaTodos 2015-04-01 11:17:02 +02:00
5cf0c82685 Ajout slides supplémentaires formation JS 2015-03-31 23:29:23 +02:00
006c3f5a42 More Javascript 2015-03-30 14:18:55 +02:00
67f3024587 Inversion des paramètres pour bacula 2015-03-27 15:28:59 +01:00
7997272ef5 Ajustement du plan 2015-03-27 10:06:46 +01:00
4ba2e5768b Mise à jour du plan de formation 2015-03-27 10:06:46 +01:00
33d3f5386a Formation JS, ajout slides suppl. 2015-03-26 17:36:34 +01:00
6b0206f399 Essai de markdown pour documenter la génération des plans de formations 2015-03-26 15:27:11 +01:00
dda69187df Ajout de la durée 2015-03-26 15:19:38 +01:00
0672a0bd80 Ajout doc dépendances Latex 2015-03-25 17:27:44 +01:00
a2650f1ebd Ajout base formation Javascript 2015-03-25 17:27:03 +01:00
72ba644959 Relecture 2015-03-23 18:07:42 +01:00
4779875c04 Relecture 2015-03-23 18:06:36 +01:00
3c15ec7fe1 Relecture 2015-03-23 17:03:36 +01:00
d286f5cc66 Couleur différente pour le sous-titre de diapo 2015-03-23 16:55:26 +01:00
42199f9c6e Arrangement des diapos trop longues 2015-03-23 16:49:34 +01:00
b3cd20642a Relecture scribe-horus 2015-03-23 11:02:22 +01:00
5506609770 Relecture scribe-horus 2015-03-23 10:43:35 +01:00
cf58bc6aea Relecture scribe-horus 2015-03-23 09:48:02 +01:00
838027ac1d Relecture scribe/horus 2015-03-23 09:40:51 +01:00
eaad0c234b ajout EOP 2015-03-16 22:05:17 +01:00
5c44c012af plus de <fichier>.eol pour instance 2015-03-16 22:03:51 +01:00
acd25e74a1 mise à jour schedule 2015-03-12 15:09:27 +01:00
2140d0d47d Adaptation pour EOLE 2.4.1 2015-03-11 19:50:42 +01:00
c952079bdf Adaptation des dictionnaire et template pour la 2.4.x 2015-03-11 19:27:10 +01:00
00372ac099 Corrections mineures 2015-03-09 13:46:45 +01:00
b54c863956 Corrections mineures (ou pas) 2015-03-09 12:24:18 +01:00
870477c0b1 Corrections mineures 2015-03-09 12:20:02 +01:00
4e3bcf9231 Adaptations à la 2.4 2015-03-09 12:04:27 +01:00
448455c1ec Échappement des caractères spéciaux 2015-03-09 11:28:00 +01:00
c59da436d5 Relecture de la formation tronc commun 1 2015-03-09 11:20:53 +01:00
0ef2f19837 Relecture et correction 2015-03-09 09:56:36 +01:00
89a2a3604a modif exercices 2015-03-09 09:35:21 +01:00
691 changed files with 4561 additions and 18910 deletions

4
.gitignore vendored
View File

@ -11,10 +11,6 @@
*.bcf
*.idx
*.run.xml
*.pygtex
*.vrb
build-messages-*.txt
plans_de_formation.tar.gz
_minted-*/
.~lock*
_minted-*/

25
README
View File

@ -1,25 +0,0 @@
Pour la formation sur Git, il faut compiler avec XeLaTeX.
XeLaTeX
=======
Langage de description de document avec prise en charge native de l'UTF-8
XeLaTeX est une variante de LaTeX, la structure générale du document reste identique et l'immense majorité des commandes et packages continuent de fonctionner comme d'habitude.
http://doc.ubuntu-fr.org/xelatex
http://fr.wikipedia.org/wiki/XeTeX
Installation
============
Sous Ubuntu 12.04 :
# apt-get install texlive-xetex
Utilisation
===========
Pour la formation sur Git, il faut compiler avec XeLaTeX.
Usage :
$ xelatex --shell-escape skell.tex

BIN
cesi/agilite/AtelierAgile.odp Executable file

Binary file not shown.

BIN
cesi/agilite/CoursAgile.odp Executable file

Binary file not shown.

1
cesi/hebergement_web/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.html

View File

@ -0,0 +1,37 @@
% Introduction à l'hébergement Web
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction
* Qui suis-je ? Développeur web depuis 2003 : agences web, Skyrock, Aéroport d'Auckland, Cadoles… / Administrateur de plusieurs serveurs web depuis 2002.
* Comment fonctionne ce cours ? Présentation d'un sujet, exercice en TP, exercices facultatifs
* Evaluation : bonne réalisation des TP.
---
## Le plan c'est…
1. DNS
2. HTTP et serveur web
3. HTTPS
4. Web dynamique et PHP
5. Sécurité du serveur web
---
## Prérequis
* VirtualBox avec une distribution Linux (Debian ou Ubuntu de préférence)
* Machine virtuelle dispo sur `https://sylvain.eliade.net/cesi/debian.ova`
* Si pas de réseau privé hôte existant, en créer un dans **Fichier > Gestionnaire de réseau hôte**
* Sélectionner le réseau privé hôte dans la config de la VM : **Mode d'accès réseau = réseau privé hôte**
---
## VM Debian
* Login : user / Mot de passe : abcd
* Pour devenir root : `sudo -i`
* Changer de répertoire : `cd /repertoire`
* Éditer un fichier `nano fichier.txt` (puis Ctrl+X pour quitter)

View File

@ -0,0 +1,402 @@
% Introduction au DNS
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction au DNS
* Domain Name System
* Service de base sur Internet
* Permet d'obtenir l'adresse IP d'une machine à partir d'un nom intelligible (résolution de nom)
* Exemple : `www.cesi.fr -> 178.170.102.194`
* Sur le port 53, en UDP (+ TCP pour les réponses de plus de 512 octets) : plus rapide !
---
## Un nom DNS
`www.cesi.fr` comporte trois parties :
* `fr` est le TLD (Top Level Domain)
* `cesi` est le nom de domaine
* `www` est un sous-domaine
Le FQDN (*Fully Qualified Domain Name*) est le nom intégral, suivi d'un point final (= la racine), indiquant que le nom est complet : `www.cesi.fr.`
L'ensemble des enregistrements d'un nom de domaine s'appelle une *zone*.
---
## Les TLD
Plusieurs types :
* pour les pays (`.fr`, `.be`, `.nz`, etc.) = ccTLD (Country-Code)
* génériques (gTLD) : `.com`, `.info`, et les nouveaux : `.paris`, `.ovh` et des centaines d'autres
* infrastructure `.arpa` : ne sert que pour les reverse DNS (trouver un nom à partir d'une IP)
---
### État des TLDs
Plus de 1500 TLD à ce jours. Expansion depuis l'ouverture à la vente des gTLD en 2012 (100.000$ pour déposer un dossier).
TLD réservés : `.example`, `.invalid`, `.localhost`, `.test`, `.local` (multicast), `.onion` (Tor).
Attention à ne pas utiliser des TLD perso en interne : exemple du `.dev` acheté par Google.
---
## Résolution DNS
Le DNS est un système hiérarchique. On commence par la racine (root) et on descend les niveaux.
![](./img/hierarchie_dns.svg)
---
Ainsi pour résoudre le nom `fr.wikipedia.org` on va demander :
* aux serveur racine : quel serveur est responsable du TLD `org` ?
* au serveur responsable de `org` : qui est responsable du domaine `wikipedia.org` ?
* au serveur responsable du domaine `wikipedia.org` : quelle est l'adresse IP de `fr.wikipedia.org` ?
On obtient enfin l'adresse IP du serveur associé à `fr.wikipedia.org`, ou si celui-ci n'existe pas, le serveur DNS renvoie `NXDOMAIN` (Non-eXistent domain).
---
## Les outils d'inspection DNS
* `host` renvoie des réponses courtes et simples. Pratique pour scripter.
* `dig` est plus complet. Mieux pour diagnostiquer des problèmes DNS.
* `nslookup` : simpliste, mais dispo sous Windows et Linux, déconseillé.
Pour leur utilisation : `man dig` et `man host`
```
% host eliade.net
eliade.net has address 91.121.181.110
eliade.net has IPv6 address 2001:41d0:1:f66e::1
eliade.net mail is handled by 10 mail.kd2.org.
```
---
```
% dig eliade.net
;; ANSWER SECTION:
eliade.net. 201 IN A 91.121.181.110
;; Query time: 1 msec
;; SERVER: 192.168.5.253#53(192.168.5.253)
;; WHEN: Mon May 13 10:45:34 CEST 2019
;; MSG SIZE rcvd: 55
```
Attention, par défaut les deux outils utilisent le résolveur configuré dans `/etc/resolv.conf` (ici `192.168.5.253`). Bien utiliser leurs options si on veut faire des requêtes directement sur les serveurs racine, de TLD, ou autoritaires.
---
## Exemple de résolution de domaine : fr.wikipedia.org
On peut reproduire le travail d'un résolveur avec l'outil `dig`.
On demande au serveur racine qui est responsable pour le TLD `org` :
```bash
% dig NS org +short
a0.org.afilias-nst.info.
c0.org.afilias-nst.info.
b0.org.afilias-nst.org.
b2.org.afilias-nst.org.
d0.org.afilias-nst.org.
a2.org.afilias-nst.info.
```
---
On sait que `a0.org.afilias-nst.info` est responsable de la zone `.org`, on va lui demander qui est responsable de la zone `wikipedia.org`
```
% dig wikipedia.org @a0.org.afilias-nst.info
wikipedia.org. 86400 IN NS ns0.wikimedia.org.
wikipedia.org. 86400 IN NS ns2.wikimedia.org.
wikipedia.org. 86400 IN NS ns1.wikimedia.org.
```
---
Reste plus qu'à demander au serveur responsable de `wikipedia.org` quelle est l'adresse de `fr.wikipedia.org` :
```
% dig fr.wikipedia.org @ns0.wikimedia.org
fr.wikipedia.org. 3600 IN CNAME dyna.wikimedia.org.
```
Ah c'est un `CNAME` donc un alias, vers `dyna.wikimedia.org` !
---
Donc il nous faut aller voir à quoi correspond `dyna.wikimedia.org` :
```
% dig dyna.wikimedia.org @ns0.wikimedia.org
dyna.wikimedia.org. 600 IN A 91.198.174.192
```
Et voilà on a notre adresse IP !
(Ici on a pris un raccourci, normalement on aurait dû aller demander quel était le serveur responsable de `wikimedia.org` mais c'est le même que `wikipedia.org`).
---
## Attention au cache !
Évidemment on ne va pas re-demander au serveur racine à chaque fois quels sont les serveurs responsables de chaque TLD, si on a déjà l'information, elle est mise en cache pour un certain temps, à plusieurs niveaux (application, OS, serveur DNS local, etc.).
---
## Syntaxe d'enregistrement
```
dyna.wikimedia.org. 600 IN A 91.198.174.192
```
Chaque enregistrement indique :
* son nom (`dynam.wikimedia.org`)
* son **TTL** (Time-To-Live) : limite de temps avant qu'un résolveur ne doive aller re-demander l'enregistrement au serveur autoritaire (`600` secondes = 10 minutes)
* `IN` pour *INternet*
* le type de l'enregistrement (`A`)
* la valeur (`91.198.174.192`)
---
## Types d'enregistrements
* SOA = Infos sur le domaine (Start of Authority)
* A = Adresse IPv4
* AAAA = Adresse IPv6
* CNAME = Alias vers un autre nom
* MX = Serveur de mail responsable de la zone
* NS = Serveur DNS responsable de la zone
* TXT = Commentaire
Attention : le CNAME ne peut pas être utilisé pour un nom de domaine, seulement pour un sous-domaine ! (car il doit être le seul enregistrement !)
---
## Priorité d'enregistrements
Les enregistrements de type `MX` permettent de spécifier la priorité de chaque enregistrement :
```
% dig MX fastmail.fm +short
20 in2-smtp.messagingengine.com.
10 in1-smtp.messagingengine.com.
```
Ainsi ici les serveurs de mail vont essayer `in1-smtp.messagingengine.com` en premier, et s'il ne répond pas, ils essaieront `in2-smtp.messagingengine.com`.
---
## La syntaxe du SOA
Le SOA est l'enregistrement le plus important avec NS. Il a une syntaxe spécifique : `MNAME RNAME SERIAL REFRESH RETRY EXPIRE TTL`
* MNAME = adresse du serveur DNS primaire (Master)
* RNAME = adresse email du Responsable (en remplaçant le `@` par un point `.`)
* SERIAL = numéro de dernière modification de la zone, doit être incrémenté à chaque modification de la zone (en général on utilise la date du jour + un nombre qui s'incrémente). C'est ce qui indique aux serveurs secondaires qu'ils doivent
---
* REFRESH = nombre de secondes avant que les serveurs secondaires ne doivent aller re-vérifier si le serial a changé. En général c'est 86400 (24 heures).
* RETRY = nombre de secondes avant que les secondaires ne relancent une requête si le primaire ne répond pas (générallement 7200 = 2 heures)
* EXPIRE = nombre de secondes avant que les secondaires doivent arrêter de relayer la zone si le primaire ne répond pas (en général 1000 heures = 41,6 jours)
* TTL = Time To Live = nombre de secondes avant qu'un résolveur doive ré-essayer si le serveur a répondu `NXDOMAIN`
Exemple pour `octopuce.fr` :
```
ubal.octopuce.fr. support.octopuce.fr.
2019051305 21600 3600 604800 3600
```
---
## Les différents types de serveurs DNS
* Serveur racine : 13 serveurs (13 lettres) en Anycast (= 13 adresses IP, mais 600+ serveurs physiques répartis dans le monde), indique le serveur autoritaire d'un TLD
* Serveur responsable de TLD : serveur qui indique le serveur autoritaire d'un nom de domaine
* Serveur autoritaire de nom de domaine
* Serveur récursif : en général celui de votre FAI, ou de votre réseau local, c'est lui qui va faire les requêtes vers les serveurs racine, de TLD et autoritaire et renvoyer directement la réponse finale au client
---
## Le serveur autoritaire
C'est celui qu'on est susceptible de mettre en place en tant que sysadmin, il répond aux requêtes pour un ou plusieurs domaines particuliers.
* C'est lui qui fait autorité sur un/des domaines (`AUTHORITY`)
* Son autorité ne vaut rien si le serveur du TLD n'indique pas ce serveur comme étant responsable du domaine
Donc bien vérifier auprès du registrar (auquel vous avez payé le nom de domaine), que le domaine est bien configuré.
---
## Serveur autoritaire primaire et secondaire
Il est possible de n'avoir qu'un seul serveur autoritaire pour un domaine, mais si celui-ci devient injoignable, tous vos noms de domaines sont aussi injoignables. En général on a donc un serveur primaire et un ou plusieurs serveurs secondaires.
Les serveurs secondaires enregistrent une copie de la zone depuis le serveur primaire. Pour faire cette copie ils envoient une requête `AXFR` au serveur primaire qui leur renvoie tous les enregistrements de la zone.
Les clients eux iront demander à n'importe quel serveur listé comme `NS` pour la zone, au hasard, qu'il soit primaire ou secondaire.
---
## Notification des serveurs secondaires
Il existe deux manières pour un serveur secondaire de savoir s'il a besoin de mettre à jour une zone :
* le serveur primaire notifie les serveurs secondaires (message `NOTIFY`)
* les secondaires vont demander le `SOA` toutes les *x* secondes (spécifié dans le paramètre `REFRESH` du `SOA`), et regarder si le `SERIAL` du `SOA` a changé depuis la dernière fois
De nos jours on utilise plutôt le `NOTIFY` car ça permet d'avoir une répercussion immédiate des changements.
---
## Le serveur récursif (résolveur)
C'est celui à qui on parle en général ! (enfin à qui son OS et ses applications parlent)
Il enregistre dans son cache les réponses qu'il a faites (en fonction )
---
## Exemple pratique : mise en place d'un nom de domaine
* Achat du domaine `miammiammiam.com` auprès d'un registrar (par exemple OVH)
* Configuration du domaine chez le registrar pour pointer sur nos serveurs DNS : `ns1.superboite.fr` et `ns2.superboite.fr`
* Installation d'un serveur DNS sur nos deux serveurs NS1 et NS2
* Configuration de notre zone `miammiammiam.com` sur NS1 en *master*, et configuration de NS2 en *secondaire*
* Vérification du fonctionnement : le SOA renvoyé par NS1 doit être le même que celui envoyé par NS2, et le serveur DNS de `.fr` doit bien indiquer nos deux serveurs DNS
---
## Problèmes courants
* Mauvais serveur DNS indiqué auprès du registrar
* Problème de synchronisation entre le DNS primaire et un ou plusieurs DNS secondaires (le serial du SOA est-il identique ?)
* Problème de cache dans le résolveur de l'entreprise
Le résolveur envoie ses requêtes au hasard sur le DNS primaire ou l'un des DNS secondaires ! Il n'envoie pas déjà sur le primaire et ensuite sur les secondaires, c'est pas comme ça que ça marche !
---
## Serveurs DNS
* Bind (le plus répandu)
* PowerDNS (très puissant et versatile)
Les deux permettent de faire résolveur et/ou serveur autoritaire. Pour 90% des cas, Bind suffit amplement.
Il est conseillé de séparer les deux fonctions toutefois. Je conseille de mettre un serveur résolveur qui n'écoute qu'en local sur `127.0.0.1` (ou sur une IP du réseau interne), et le serveur autoritaire sur l'IP publique (accessible depuis Internet). Perso je met un bind en local, et un PowerDNS (avec MySQL) en public.
---
## Le futur
DNS n'est pas très sécurisé… Plusieurs solutions sont disponibles :
* DNSSEC : signature des zones, permet de valider que la réponse DNS n'a pas été modifiée par le résolveur en cours de route. N'empêche pas d'espionner les requêtes et réponses DNS.
* DNS over TLS, DNS over HTTPS : chiffrement de la connexion entre le client et le résolveur
* DNSCrypt : chiffrement et signature entre résolveur et client
DNSSEC peut être combiné avec DoT, DoH et DNSCrypt.
Comparaison DoH, DoT et DNSCrypt : [https://dnscrypt.info/faq/](https://dnscrypt.info/faq/)
---
## Aller plus loin
* [Problèmes courants de mauvaise configuration DNS](https://www.howtoforge.com/troubleshooting-common-dns-misconfiguration-errors)
---
## Exercice 1
Identifier le parcours DNS d'un résolveur récursif pour `www.cesi.fr` avec `dig`. (Copier/coller chaque étape)
---
## Exercice 2
Identifier les adresses IP du serveur de mail le plus prioritaire pour `gmail.com`.
---
## Exercice 3
J'ai créé un nouveau site web sur `dns1.sylvain.eliade.net` mais il ne marche pas.
Identifier la ou les erreurs commises et indiquer une solution.
---
## Exercice 4
Identifier le reverse DNS de l'adresse IP correspondant au serveur de `www.cesi.fr`
---
## Exercice 5 (facultatif)
Créer une zone Bind pour un domaine fictif avec un A et un AAAA sur le domaine lui-même, deux serveurs DNS, un SOA valide, deux serveurs de mail, et un CNAME de www qui redirige sur le domaine lui-même. Exemple :
```
$TTL 3600
@ IN SOA ns1.domain.tld. hostmaster.domain.tld. (
2017090401 ; SERIAL (DATE+NUMBER)
86400 ; REFRESH (SEC)
3600 ; RETRY (SEC)
3600000 ; EXPIRE (SEC)
300 ) ; MINIMUM (SEC)
@ IN NS ns1.domain.tld.
@ IN NS ns2.domain.tld.
ns1 IN A 10.1.2.2
ns2 IN A 10.1.2.3
@ IN A 127.0.0.1
@ IN AAAA ::1
@ IN MX 10 mx1.domain.tld.
@ IN MX 20 mx2.domain.tld.
mx1 IN A 10.1.1.1
mx2 IN A 10.1.1.2
www IN CNAME domain.tld.
```
Les point-virgules indiquent les commentaires
## Exercice 6 (facultatif)
Installer bind (`apt install bind9`). Par défaut il est configuré comme résolveur récursif local. L'utiliser pour faire des requêtes locales, par exemple : `dig www.cesi.fr @localhost`
## Exercice 7 (facultatif)
Mettre en place la zone bind créée à l'exercice 6 dans l'installation du Bind local. Un tuto utile : [https://www.adrienfuret.fr/2017/09/04/debian-dns-bind/](https://www.adrienfuret.fr/2017/09/04/debian-dns-bind/)
Tester le fonctionnement avec dig : `dig domain.tld @localhost`

View File

@ -0,0 +1,440 @@
% Introduction au HTTP
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction au HTTP
* HyperText Transport Protocol
* Protocole texte
* Client-serveur
* En général sur TCP, port 80
* Stateless, aucun état n'est conservé entre les requêtes
* Très simple
* Requêtes **toujours** initiées par le client
---
## À quoi ça ressemble ?
Un simple `telnet` permet de faire des requêtes HTTP !
```
% telnet sylvain.eliade.net 80
Trying 91.121.181.110...
Connected to eliade.net.
Escape character is '^]'.
GET /resume/ HTTP/1.1
Host: sylvain.eliade.net
```
---
Le serveur nous répond :
```
HTTP/1.1 200 OK
Date: Mon, 13 May 2019 10:02:02 GMT
Server: Apache
Last-Modified: Fri, 19 Apr 2019 07:36:32 GMT
ETag: "2abb-586dd2d7c21de"
Accept-Ranges: bytes
Content-Length: 10939
Vary: Accept-Encoding
Content-Type: text/html
Connection: close
<!DOCTYPE html>
<html>
```
---
Un outil plus pratique est quand même `curl` !
```
% curl -v http://sylvain.eliade.net/resume/
```
---
## Structure d'une requête
Première ligne : `MÉTHODE RESSOURCE PROTOCOLE`
* Méthode (ou verbe) HTTP = action que l'on souhaite utiliser (`GET`, `DELETE`, `POST`, etc.)
* Ressource sur laquelle on souhaite effectuer l'action
* Version du protocole : `HTTP/1.0` ou `HTTP/1.1` (il existe encore des clients HTTP/0.9 mais bon…)
Lignes suivantes : les entêtes. Puis : une ligne vide.
Puis éventuellement (méthodes `POST`, `PUT`, `PATCH`, etc.) : corps (contenu) de la requête.
---
### Méthodes HTTP
* GET : la plus courante, renvoie la ressource demandée (exemple : visualiser une page web)
* POST : envoyer des données liées à la ressource (exemple : envoyer un formulaire web)
Les méthodes suivantes sont rarements utilisées par les navigateurs mais souvent dans les API :
* HEAD : obtenir des infos sur la ressource. En pratique c'est souvent pareil que GET, mais ça ne renvoie que les entêtes et pas le corps.
* PUT : ajouter / remplacer une ressource
* OPTIONS : savoir quelles sont les méthodes supportées par le serveur pour une ressource
---
## Structure d'une réponse
Première ligne : `PROTOCOLE CODE MESSAGE`
* Code = code de réponse du serveur (200 = OK, 404 = Not Found, etc.)
* Message = message de réponse associé au code
Lignes suivantes : les entêtes de réponse.
Puis : une ligne vide.
Puis éventuellement (tout le temps sauf avec requête `HEAD`) : corps de la réponse.
---
### Codes de réponses HTTP
Le premier chiffre indique le type de code :
* 1xx = requête reçue mais son exécution n'est pas terminée
* 2xx = succès
* 3xx = redirection
* 4xx = erreur du client
* 5xx = erreur du serveur
---
### Codes courants
* 200 OK = la plus courante
* 301 Moved Permanently = ressource déplacée définitivement (voir l'entête `Location` pour la nouvelle adresse)
* 302 Found = ressource déplacée temporairement
* 400 Bad Request = erreur dans la requête du client
* 401 Unauthorized = le client n'a pas accès, il lui faut s'authentifier
* 403 Forbidden = accès refusé (par exemple mauvais login/mot de passe)
* 404 Not Found = ressource non trouvée
* 500 Internal Server Error
* 503 Service Unavailable = serveur surchargé
---
## Entêtes
```
Host: sylvain.eliade.net
User-Agent: telnet/1.0
```
Chaque entête est une clé (en général avec une majuscule au début de chaque mot, les mots étant séparés par des tirets), suivi de deux points `:`, d'un espace et de la valeur de l'entête.
Liste des entêtes : [https://en.wikipedia.org/wiki/List_of_HTTP_header_fields](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
---
### Entêtes courants pour les requêtes
* `Host` : pour indiquer le nom de domaine que l'on essaye d'atteindre (car le serveur HTTP ne sais pas quelle requête DNS on a fait pour le contacter)
* `Accept-Language` : indique les langues préférées du client (`fr-BE, fr, en-AU, en`)
* `Accept` : les formats de fichier gérés par le client (`text/html, image/jpeg…`)
* `Connection` : pour garder la connexion TCP ouverte pour faire plusieurs requêtes de suite
* `User-Agent` : nom du client utilisé
* `Cookie` : contenu d'un cookie
* `Authorization` : identifiants de connexion HTTP (accès par mot de passe)
---
### Entêtes courants pour les réponses
* `Connection` : état de la connexion TCP
* `Date` : date de réponse
* `Content-Type` : type du contenu (`text/html; charset=utf-8`)
* `Location` : nouvelle adresse du contenu quand il a changé d'adresse
* `Server` : nom du serveur
* `Set-Cookie` : le client doit enregistrer ce cookie
* `WWW-Authenticate` : demande d'authentification
---
## Aparté : les URLs
Uniform Resource Locator (interchangeable avec URI, Uniform Resource Identifier)
`protocol://[user[:password]@]host[:port]path[?query][#fragment]`
Entre crochets les parties facultatives.
---
* protocol : http ou https
* user[:password] : nom d'utilisateur (et éventuellement mot de passe), pour l'authentification HTTP
* host : nom de domaine (ou adresse IP, pour une IPv6 elle doit être entre crochets, exemple : `http://[::1]/page`)
* port : numéro de port optionnel
* path : chemin de la ressource
* query (ou query string) : liste de clés et valeurs, séparées par des `&`
* fragment : identifiant d'une sous-ressource à l'intérieur de la ressource (en pratique, utilisé pour se rendre à une point particulier de la page web, ou en javascript)
---
`https://catalogue.cesi.fr/recherche/?domaine=informatique&niveau=bac4#type`
* protocol: `https`
* host: `catalogue.cesi.fr`
* path: `/recherche/`
* query: `domaine=informatique&niveau=bac4`
* fragment: `type`
---
## Les serveurs HTTP les plus courants
* Apache (29% des serveurs)
* nginx (29%) : plus rapide qu'Apache sur les fichiers statiques, même performance sur le contenu dynamique (PHP)
* Microsoft IIS (19%)
Apache est le plus courant, historiquement le plus utilisé, mais on trouve de plus en plus du nginx aussi. La configuration de nginx est un peu plus lisible que celle d'Apache.
---
## Apache et ses MPM
Apache possède plusieurs MPM (multi-processing module) qui ont des comportements différents :
* prefork : moins performant (sans threads), chaque processus ne peut traiter qu'une seule requête à la fois
* worker ou event : plus performant, chaque processus a plusieurs threads, et peut donc traiter plusieurs requêtes à la fois
Quel MPM choisir ? En production on utilisera *worker* ou *event*, car plus rapides, mais pour tester des trucs rapidement avec PHP on peut utiliser *prefork* qui est plus simple à metter en place.
---
## Un mot sur l'utilisateur www-data
Par défaut Apache est lancé avec l'utilisateur `www-data`. Ça va si on n'a qu'un seul site hébergé sur la machine.
Si on veut héberger plusieurs sites, il vaut mieux pouvoir avoir un utilisateur par site, pour pas qu'un site puisse aller modifier les fichiers d'un autre site.
Pour cela une version de *prefork* appelée **ITK** (`apt install libapache2-mpm-itk`) permet d'avoir des processus Apache qui se lancent avec les droits d'utilisateurs différents.
---
## Installation Apache sous Debian
* Installer le serveur : `apt install apache2`
* Statut du serveur : `apache2ctl status` (permet de voir les requêtes traitées en ce moment, le nombre de *workers* etc.)
* Tester si la config n'a pas d'erreur : `apache2ctl configtest`
* Recharger la configuration après modification : `apache2ctl graceful`
---
## Gérer les modules Apache sous Debian
* Activer un module : `a2enmod NOM_DU_MODULE` (exemple : `a2enmod rewrite`)
* L'outil préviendra s'il y a un conflit entre deux modules incompatibles :)
* Désactiver : `a2dismod NOM_DU_MODULE`
* Même chose pour les MPM : `a2dismod mpm_prefork` puis `a2enmod mpm_worker`
Astuce : lancer `a2enmod` sans argument liste les modules disponibles.
La configuration du module est dans le fichier `/etc/apache2/mods-available/NOM_DU_MODULE.conf`
---
## Configuration Apache
Syntaxe simple. Ce n'est pas du XML !
```
Listen 80
KeepAlive Off # Ne pas autoriser les connexions persistantes
<Directory /var/www/monsite>
Require all granted
Options -Indexes
</Directory>
```
---
## VirtualHost
Apache permet d'héberger plusieurs sites sur le même serveur avec des hôtes virtuels. L'hôte est reconnu avec l'entête "Host". Pour cela on utilise des hôtes virtuels.
```
<VirtualHost *:80>
ServerName cadoles.com
DocumentRoot /var/www/monsite
</VirtualHost>
<VirtualHost *:80>
ServerName mail.cadoles.com
DocumentRoot /var/www/roundcube
</VirtualHost>
```
Le premier vhost de la liste sera utilisé comme vhost "par défaut" si aucun vhost n'est trouvé pour l'hôte demandé.
---
### VirtualHost dans Debian/Ubuntu
Les vhost disponibles sont séparés par fichiers dans `/etc/apache2/sites-available`, triés par ordre alpha-numérique.
Ensuite : `a2ensite nomduvhost` pour activer, ou `a2dissite nomduvhost` pour désactiver.
Ne pas oublier de tester la config et recharger ensuite !
Astuce : lancer `a2ensite` ou `a2dissite` sans argument liste les sites disponibles.
---
## Fichiers .htaccess
Apache permet de configurer des options pour un répertoire donné à l'aide d'un fichier `.htaccess` (en UNIX, les fichiers avec un point au début sont des fichiers "cachés").
C'est pratique, mais attention, cela veut dire qu'Apache sera beaucoup plus lent, car il va chercher ce fichier dans tous les sous-répertoires à chaque requête !
Donc il est recommandé de désactiver ce comportement par défaut, et de ne l'activer que pour les sites qui en ont besoin. Tant que possible il vaut mieux mettre toute la configuration dans les fichiers de configuration Apache du vhost.
---
```
<Directory />
AllowOverride None
</Directory>
<Directory /var/www/wordpress>
AllowOverride All
</Directory>
```
[AllowOverride](https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride) permet de configurer le type de directive autorisée dans le fichier `.htaccess`.
None = aucune directive autorisée = Apache ne va même pas lire les fichier `.htaccess`
---
## Restriction d'accès
Un exemple courant de `.htaccess` est la restriction d'accès par mot de passe. Pour cela il faut dire à Apache de n'autoriser que les utilisateurs connectés avec `Require valid-user` :
```
Require valid-user
AuthType basic
AuthName "Accès restreint"
AuthUserFile /var/www/monsite/secret/.htpasswd
```
---
### Fichier htpasswd
Pour créer le fichier `.htpasswd` qui contiendra la liste de nos utilisateurs autorisés et leurs mots de passe nous devons utiliser l'outil `htpasswd`.
A installer avec `apt install apache2-utils`.
---
* Créer le fichier avec `htpasswd -c /var/www/monsite/secret/.htpasswd NOM_UTILISATEUR` (`-c` comme **Création** du fichier)
* L'outil demande de taper, puis re-taper le mot de passe
* Pour ajouter un utilisateur ou modifier son mot de passe, simplement : `htpasswd /var/www/monsite/secret/.htpasswd NOM_UTILISATEUR` (sans le `-c` donc)
```
sylvain:$apr1$vfxnPOnt$gI7MkAizYirxT/CrUfCqU0
```
---
## Exercice 1
Faire une requête avec `curl` sur `http://www.cesi.fr/`. Quel est le code HTTP retourné ? Quel est le serveur web utilisé ?
---
## Exercice 2
Installation de Apache2. Faire une requête sur `http://localhost/` pour voir si ça fonctionne.
Puis essayer d'accéder à l'IP de la VM depuis un navigateur de la machine hôte pour voir si ça fonctionne bien.
(Pour obtenir l'IP : `ip addr` depuis la console)
---
## Exercice 3
Prérequis : créer un répertoire `/var/www/cesi.test` et un fichier `/var/www/cesi.test/index.html` avec :
```
mkdir /var/www/cesi.test
echo "Hello monde !" > /var/www/cesi.test/index.html
```
Exercice : Mettre en place un VirtualHost `cesi.test` proprement, l'activer.
Pour vérifier son fonctionnement, ajouter la ligne suivante dans `/etc/hosts` : `127.0.0.1 cesi.test`. Puis faire `curl http://cesi.test/`, le message "Hello monde" devrait apparaître.
---
## Exercice 4
Prérequis : créer un répertoire `/var/www/cesi.test/secret` : `mkdir /var/www/cesi.test/secret`
Désactiver les vhosts existants, sauf celui de `cesi.test`. Recharger apache.
Mettre en place une protection par mot de passe du répertoire `/var/www/cesi.test/secret` avec un fichier `.htaccess`.
Vérifier que ça marche correctement en utilisant le navigateur de la machine hôte sur l'IP de la VM.
---
## Exercice 5 (facultatif)
Tester la charge du serveur avec ApacheBench :
* installer `ab` : `apt install apache2-utils`
* dans une première console, lancer `watch -d -n 0.1 sudo apache2ctl status`
* lancer dans une seconde console `ab -n 5000 -c 100 http://localhost/` (va lancer 5000 requêtes, par vagues de 100 en même temps)
* observer l'évolution du nombre de workers, et de la charger serveur (*Server load*)
---
## Exercice 6 (facultatif)
Changer de MPM, passer de *prefork* (celui utilisé par défaut normalement) à *event*.
Répéter le test de l'exercice 5 et observer les différences.
---
## Exercice 7 (facultatif)
On nous demande de faire de la réécriture d'adresse.
Faire en sorte que `http://cesi.test/etu` redirige vers `http://localhost/infos-etudiant` en utilisant la directive `Redirect` dans le vhost créé précédemment (voir la [documentation de Redirect](https://httpd.apache.org/docs/2.4/mod/mod_alias.html#redirect) pour un exemple).
Pour cela il faudra activer le module `alias`.
Il est courant d'utiliser `RewriteRule` pour faire cela (module `rewrite`), mais il est plus lent et complexe ([Documentation](https://httpd.apache.org/docs/2.4/rewrite/intro.html)), mais permet plus de possibilités.
---
## Exercice 8 (facultatif)
Installer `nginx` et créer un virtualhost `cesi.test`.
Un exemple de configuration de virtualhost est dispo dans `/etc/nginx/sites-available/default`.
Pour créer le vhost, créer un fichier `/etc/nginx/sites-available/cesi.test`.
Pour l'activer exécuter `ln -s /etc/nginx/sites-available/cesi.test /etc/nginx/sites-enabled/cesi.test`, cela va créer un lien symbolique (pas de commande comme avec Apache type `a2ensite`).
Puis `nginx -t` pour vérifier la configuration et `service nginx reload` pour recharger.

View File

@ -0,0 +1,174 @@
% Introduction au HTTPS
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction au HTTPS
* HTTP encapsulé dans une connexion chiffrée
* Historiquement avec le protocole SSL
* Aujourd'hui c'est TLS
---
## Chiffrement à clé publique et privée
* La clé publique est distribuée (non secrète) et ne sert qu'à chiffrer
* La clé privée est secrète et sert à déchiffrer
Le serveur possède une clé privée (secrète) et une clé publique (appelée certificat), signée par une *autorité*.
---
## Certificats
* Prouve l'identité du propriétaire du certificat
* Doivent être signés par une autorité reconnue (ou plusieurs)
* Peuvent être signés par soi-même (*self signed*) mais c'est relou (difficile à utiliser), et du coup ça ne prouve pas grand chose
---
## Autorités
* Système hiérarchique (une autorité peut signer des certificats d'une sous-autorité, etc.) : on parle de *chaîne* de certificats
* Combine des acteurs publics (états, ministères, etc.) et privés (entreprises)
* On doit avoir confiance envers ces autorités
* Chaque OS a un « app store » de certificats d'autorités (paquet `ca-certificates` dans Debian/Ubuntu)
* Système centralisé, moyennement sûr (nombreux cas d'autorités qui font n'importe quoi)
* Un peu mieux depuis Let's Encrypt
---
## Phase de négociation (handshake) TLS
![](./img/tls_handshake.gif)
---
En simplifié :
1. Le client se connecte au serveur, lui indique les protocoles cryptographiques qu'il supporte (cipher suite)
2. Le serveur lui répond, en indiquant le protocole choisi, ainsi que son certificat public (signé par une autorité).
3. Le client vérifie le certificat.
4. Échange de clé entre le client et le serveur. Cette clé est spécifique à cette session entre client et serveur.
Ensuite le client et le serveur communiquent en HTTP entre eux, mais tout est chiffré à l'aide des clés échangées.
---
La phase de négociation ne se reproduit pas à chaque requête HTTP : normalement la connexion TLS reste ouverte une ou deux minutes, permettant de faire passer d'autres requêtes.
De même, les étapes 1 à 3 peuvent être ignorées quand le serveur et le client se connaissent déjà et ont encore les infos de chacun en cache.
---
## Vérification OCSP
A l'étape 3, le client peut aller vérifier auprès d'un serveur OCSP (*Online Certificate Status Protocol*) que le certificat du serveur est bien valide.
De nos jours, le serveur peut s'en charger lui-même (*OCSP stapling*), il envoie une certification OCSP (avec la date) au client : évite un aller-retour du client avec le serveur OCSP.
---
## SNI (Server Name Indication)
Rappel du HTTP : le nom d'hôte demandé est transmis dans l'entête `Host` de la requête HTTP.
Donc : l'hôte demandé est dans la requête chiffrée, AVANT que le serveur web ne puisse savoir quel certificat utiliser pour le HTTPS !
Solution : le SNI !
---
* Le nom d'hôte demandé est inscrit dans la connexion TLS par le client
* Très bien supporté de nos jours (si pas supporté : utilisation du vhost par défaut)
* Inconvénient : le nom n'est pas chiffré (possibilité d'interception pour voir quel site vous visitez)
---
## Configuration Apache HTTPS
Attention : il faut créer un vhost différent, car le port est différent.
```
<VirtualHost *:443>
ServerName cesi.test
SSLEngine on
SSLCertificateFile "/var/www/certs/cesi.cert"
SSLCertificateKeyFile "/var/www/certs/cesi.private"
</VirtualHost>
```
Si on a un site en HTTPS il est recommandé que la version HTTP ne fasse que rediriger vers le site en HTTPS (plus simple niveau config serveur).
---
## Let's Encrypt
* Autorité de certification à but non lucratif qui délivre des certificats signés gratuits.
* Avant LE, il fallait payer (en général cher) pour avoir un certificat signé par une autorité !
* Inconvénient : durée du certificat limitée à 90 jours.
* Inconvénient : ne marche pas pour les domaines privés (réseau privé).
* Plusieurs manières de valider qu'on est bien propriétaire d'un domaine : HTTP ou DNS
* Plusieurs clients : certbot, dehydrated, etc.
---
## Let's Encrypt : certbot
* `# apt install certbot python-certbot-apache`
* `# certbot --apache`
C'est tout, il va poser des questions et va tout configurer à votre place… Mais des fois ça ne marche pas trop du coup quand notre configuration est un peu complexe.
---
## Let's Encrypt : [dehydrated](https://github.com/lukas2511/dehydrated)
Plus léger que certbot, un peu plus manuel.
* `# apt install dehydrated dehydrated-apache2`
* Ajouter les noms de domaine dans le fichier `/etc/dehydrated/domains.txt` (un par ligne)
* Lancer `dehydrated -c`
* Configurer son vhost :
```
SSLCertificateFile /var/lib/dehydrated/certs/example.org/fullchain.pem
SSLCertificateKeyFile /var/lib/dehydrated/certs/example.org/privkey.pem
```
Tester la config et recharger Apache.
---
## Attention !
Dans certains cas, `apache2ctl configtest` ne renvoie pas d'erreur s'il y a un problème au niveau des certificats, mais ensuite le `reload` (ou `graceful`) plantera !
Exemple : si on utilise `chain.pem` de Let's encrypt (qui ne contient que la chaîne de certification, et pas le certificat lui-même) à la place de `fullchain.pem`.
Solution : vérifier `/var/log/apache2/error.log` après un reload si on a modifié des trucs dans la config SSL !
---
## Exercice 1
Installer `dehydrated` et le configurer pour le domaine `cesi.sylvain.eliade.net`. Lancer dehydrated.
Il va tenter de vérifier l'appartenance du domaine et échouer (logique). A la place, prendre les fichiers `.pem` fournis et les recopier dans le bon répertoire.
Configurer un vhost Apache pour ce domaine, utilisant les certificats fournis. Ne pas oublier d'activer `mod_ssl` : `a2enmod ssl` et redémarrer Apache.
Dans `/etc/hosts` inscrire une ligne avec `127.0.0.1 cesi.sylvain.eliade.net`.
Tester la config avec curl, et si possible le navigateur de la machine hôte.
## Exercice 2 (facultatif)
Générer un certificat auto-signé :
```
# mkdir /etc/ssl/localcerts/
# openssl req -new -x509 -days 365 -nodes -out /etc/ssl/localcerts/apache.pem -keyout /etc/ssl/localcerts/apache.key
```
Le mettre en place dans Apache, et vérifier que ça fonctionne avec un navigateur (qui affichera un message d'avertissement).

View File

@ -0,0 +1,271 @@
% Introduction au web dynamique
% Sylvain Eliade — S.C.O.P. Cadoles
## Introduction web dynamique
* Dans le web *statique*, le serveur web ne fait que renvoyer le contenu d'un fichier existant
* Dans le web *dynamique*, le serveur web délègue la génération du contenu à un sous-programme
* Ce sous-programme peut réagir aux demandes de l'utilisateur, retourner des données d'une base de données, etc.
---
## Script CGI
À l'origine, le serveur web interagissait avec des scripts CGI (Common Gateway Interface) : il exécutait un programme, auquel il passait les données de la requête HTTP, et retournait ce que le script lui renvoyait.
---
Configuration Apache :
```
<Directory "/var/www/cesi.test">
Options +ExecCGI
AddHandler cgi-script .cgi
</Directory>
```
---
Exemple de script basique `date.cgi`
```
#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "Nous sommes le "
date
```
Résultat :
```
Nous sommes le mercredi 15 mai 2019, 14:38:57 (UTC+0200)
```
---
Exemple d'interaction avec la requête `methode.cgi` :
```
#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "Méthode de requête utilisée : "
echo "$REQUEST_METHOD"
```
Résultat :
```
Méthode de requête utilisée : GET
```
---
Avantage : très simple !
Inconvénient : peu performant, chaque requête crée un nouveau processus qui est détruit à la fin de la requête.
---
## FastCGI
* Un second serveur (FastCGI), qui communique avec le serveur web
* Il garde le processus lancé en permanence
* Il reçoit les requêtes du serveur web
* Il lui envoie des requêtes et reçoit des réponses
* Il renvoie les réponses au serveur web
Ainsi il n'y a plus de création/destruction de processus, plus rapide. De plus le serveur FastCGI peut avoir plusieurs processus lancés en même temps, et répartir les requêtes. C'est un modèle similaire aux *workers* Apache !
---
## Présentation de PHP
* Langage de programmation
* Créé en 1994
* Originellement conçu comme proche de Perl et C
* Pour faire des pages web dynamiques (en CGI !)
* Mal considéré (à tort)
* Utilisé sur 79% des sites web (WordPress sur 32% des sites !)
---
### Les versions
* PHP 7 est 2-3 fois plus rapide que PHP 5.6
* PHP 5 n'est plus supporté (plus de mises à jour de sécurité), PHP 7.0 non plus !
Les versions de PHP sont supportées environ 3 ans (mais les distributions peuvent allonger ce délai en backportant les correctifs).
Moralité : beaucoup de boîtes sont à la ramasse, et se traînent des PHP qui ne sont pas à jour… Et ça peut durer longtemps.
---
### A quoi ça ressemble ?
```
<?php
echo "Aujourd'hui nous sommes le ";
echo date('d/m/Y');
```
---
```
<?php
$colors = ['blue', 'white', 'rainbow', 'yellooooollipop'];
$color = $colors[array_rand($colors)];
?>
<p>My favorite unicorn color is <?=$color?></p>
```
## Installation et configuration de PHP
Il existe plusieurs versions de PHP :
* En ligne de commande : CLI (`apt install php-cli`), utile pour lancer des scripts, tester rapidement avec le serveur web intégré…
* mod_php pour Apache (`apt install libapache2-mod-php`)
* FPM (FastCGI Process Manager) pour serveur web (`apt install php-fpm`)
---
### PHP CLI
Cette version en ligne de commande permet de lancer un script (`php monscript.php`) ou un serveur web de test pour essayer un site, etc. (`php -S localhost:8080 /var/www/monsite` et le site sera joignable sur http://localhost:8080/).
Le serveur web ne peut traiter qu'une seule requête en même temps… pas très indiqué pour un vrai site web !
---
### mod_php
* Très simple à mettre en place
* Nécessite mpm-prefork = pas très rapide
* Convient pour des petits sites
Rien à configurer dans Apache : les fichiers `.php` seront exécutés directement.
---
### Rappel sur MPM-ITK
Pour configurer MPM-ITK sur un vhost pour qu'il se limite à utilisateur :
```
<IfModule mpm_itk_module>
AssignUserId USER GROUP
</IfModule>
```
---
### FPM
* Basé sur FastCGI
* Crée un serveur d'application PHP
* Un peu de configuration à faire
* Permet de créer plusieurs *pools* pour des sites/utilisateurs différents
* Rapide !
---
## Configuration FPM
Création de pool dans `/etc/php/7.0/fpm/pool.d/cesi.conf` :
```
[cesi]
user = cesi
group = cesi
listen = /run/php/php7.0-fpm-cesi.sock
```
---
Configuration du VHost :
```
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php7.0-fpm-cesi.sock"
</FilesMatch>
```
---
## Exercice 1
Faire un script PHP qui va afficher la date du jour.
L'exécuter avec `php` en ligne de commande.
---
## Exercice 2
Installer `mod_php`.
Déplacer le script créé dans un répertoire d'un vhost existant.
Vérifier sa bonne exécution avec curl, ou un navigateur.
---
## Exercice 3
Prérequis : avoir au moins deux vhosts actifs différents.
* Créer un utilisateur par vhost avec `useradd -G www-data USER`
* Installer et activer le MPM ITK de Apache.
* Pour chaque vhost, configurer le vhost pour utiliser ITK et l'utilisateur du vhost et le groupe *www-data* (via `AssignUserId`)
Puis :
Dans chaque répertoire de chaque vhost mettre un fichier `compteur.php` dont le contenu est :
```
<?php
if (file_exists('stats.txt')) {
$nb_visites = file_get_contents('stats.txt');
}
else {
$nb_visites = 0;
}
$nb_visites++;
file_put_contents('stats.txt', $nb_visites);
echo "Vous êtes le visiteur n° " . $nb_visites;
```
Vérifier que les permissions de chaque répertoire de chaque vhost sont restreintes à l'utilisateur du vhost ! (et les fichiers du répertoire)
Enfin : visiter le fichier `compteur.php` de chaque vhost. Vérifier les utilisateurs propriétaires des fichiers `stats.txt`.
---
## Exercice 4
Installer `php-fpm`.
Activer avec `a2enmod proxy_fcgi setenvif` et `a2enconf php7.0-fpm`.
Créer un fichier `fcgi.php` contenant `<?php echo php_sapi_name();` et vérifier qu'il renvoie bien `fpm-fcgi` quand il est consulté.
---
## Exercice 5 (facultatif)
Mettre en place au moins deux pools FPM avec deux utilisateurs différents pour deux vhosts différents, comme avec ITK, mais avec FPM.

View File

@ -0,0 +1,306 @@
% Introduction à la sécurité d'un serveur web
% Sylvain Eliade — S.C.O.P. Cadoles
## Introduction à la sécurité d'un serveur web
## Fail2ban
S'il ne faut en retenir qu'un c'est celui-là !
`apt install fail2ban`
Il lit les logs en permanence et détecte les tentatives d'intrusion (mauvais mot de passe SSH, email, HTTP…) et bloque les IP automatiquement !
Activer les filtres dans `/etc/fail2ban/jail.conf` (passer `enabled` à `true`). Normalement la plupart des filtres nécessaires sont activés par défaut, mais ça vaut le coup de regarder si on peut en activer d'autres, ou de faire les siens !
## Mises à jours de sécurité
Ça semble évident, mais ça ne l'est pas pour tout le monde.
Activer les mises à jour automatique de sécurité avec `unattended-upgrades`.
```
apt install unattended-upgrades
```
---
## Pare-feu (firewall)
Sous Linux, les ports sont fermés par défaut si un service n'écoute pas dessus, donc c'est "sécurisé" par défaut. Alors pourquoi un firewall ?
Parce que si un attaquant parvient à ouvrir un port sur votre machine il peut s'en servir pour lui donner des ordres, ou faire des requêtes vers d'autres machines (par exemple transformer votre serveur en attaquant DDoS).
Du coup un firewall est utile pour restreindre le risque en cas d'attaque.
---
## Pare-feu Linux
Le noyau Linux contient déjà un pare-feu, c'est Netfilter, accessible via la commande `iptables`.
Comme elle est un peu complexe, on conseille en général d'utiliser `ufw` (Uncomplicated FireWall), qui est une interface iptables simplifiée.
---
## UFW
Installer avec `apt install ufw`, et activer avec `ufw enable`.
Consulter le statut avec `ufw status verbose`.
```
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
```
Lister les règles disponibles : `ufw app list`
---
(Dés)Activer le blocage par défaut :
```
ufw default allow incoming
ufw default deny outgoing
```
Activer un service :
```
ufw allow in WWW
ufw allow out VNC
```
---
Autoriser un port :
```
ufw allow 53
ufw allow 25/tcp
```
Bloquer une IP :
```
ufw deny from X.X.X.X to any
```
---
## Restriction par IP
Si on veut restreindre l'accès à un serveur web à certaines IP il y a plusieurs stratégies possibles :
* au niveau du firewall (mieux, car le plus tôt dans la connexion réseau)
* via TCP Wrappers ou systemd
* via le serveur web
---
## Avec UFW
```
ufw deny 80
ufw allow from X.X.X.X to any port 80
```
---
## TCP Wrappers
Mécanisme ancien, simple, mais aujourd'hui on utilise un firewall.
Malgré le nom, il gère aussi UDP.
La configuration se fait dans les fichiers `/etc/hosts.allow` et `/etc/hosts.deny`.
N'est plus supporté par systemd.
---
```
# /etc/hosts.allow
sshd: 192.168.1.0/255.255.255.0
# /etc/hosts.deny
sshd: ALL
````
---
## Restriction avec systemd
Se fait au niveau du fichier `.service` :
```
IPAddressDeny=1.1.1.1
IPAddressAllow=8.8.8.8
```
Encore une fois, mieux vaut préférer un firewall.
---
## Restriction avec Apache
Avantage : peut se faire par répertoire, vhost, fichier…
Tout autoriser sauf une IP :
```
<RequireAll>
Require all granted
Require not ip 10.252.46.165
</RequireAll>
```
---
Tout bloquer sauf si connexion valide OU adresse IP spécifique :
```
<RequireAll>
Require all denied
<RequireAny>
Require ip 192.168.1.12
Require valid-user
</RequireAny>
</RequireAll>
```
---
## Ne pas se tirer une balle dans le pied
* Utiliser PHP 7.2 ou 7.3 ! Abandonnez PHP 5 et PHP 7.0 (plus supportés !) ! Enfin si c'est possible…
* Configurer le serveur web pour n'écouter que sur l'interface / port nécessaire (`/etc/apache2/ports.conf`)
* Ne pas exposer sa version de PHP ou Apache (ou nginx)
* Désactiver le vhost par défaut d'apache, dont la page HTML peut contenir des infos utiles à un attaquant
* Bloquer l'accès aux répertoires .svn et .git !
```
RedirectMatch 404 /\.git
RedirectMatch 404 /\.svn
```
---
## Cacher les versions
Pourquoi ? Contre les bots qui scannent les serveurs pas à jour.
Dans `/etc/apache2/conf-enabled/security.conf` :
```
ServerTokens Prod
ServerSignature Off
```
---
Avant :
`Server: Apache/2.4.25 (Debian)`
Après :
`Server: Apache`
---
Dans `/etc/php/7.0/apache/conf.d/local.ini` ajouter :
```
expose_php = off
```
---
## Restreindre la surface d'attaque (Apache)
Désactiver les index de répertoires, l'exécution de CGI, les liens symboliques et les inclusions :
```
<Directory />
Options -Indexes -ExecCGI -FollowSymLinks -Includes
</Directory>
```
Désactiver les .htaccess si possible.
---
## Restreindre la surface d'attaque (PHP)
Restreindre les répertoires accessibles de PHP (dans le vhost Apache) :
```
php_admin_value open_basedir /var/www/monsite.com
```
Interdire l'exécution de programme externe :
```
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
```
à mettre dans le `/etc/php/7.0/apache/conf.d/local.ini`, ou dans un `php_admin_value` par vhost.
---
## Aller plus loin
Vérifier sa config :
* Audit automatisé : mieux que ne rien faire, mais à ne pas faire en prod, laisse pas mal de traces (logs), peut surcharger le serveur
* Audit manuel : de bonnes connaissances en sécu, ou un bon chéquier !
* Hardening PHP : ça restreint certaines fonctions et attaques, mais c'est bien mais ça peut casser des applis :(
* WAF (Web Application Firewall) : idem, ça détecte des attaques connues, bonne stratégie défensive, mais attention aux effets de bord.
---
* [Auditer son site avec Nikto](https://doc.ubuntu-fr.org/nikto)
* [Hardening PHP : snuffleupagus (Apache)](https://github.com/nbs-system/snuffleupagus)
* [Tester son certificat SSL avec SSL Labs](https://www.ssllabs.com/ssltest/)
* [Mise en place de WAF avec mod_security pour Apache](https://www.it-connect.fr/installation-de-mod_security-devant-un-serveur-web-apache/)
* [WAF pour nginx avec naxsi](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-naxsi-on-ubuntu-16-04)
---
## Exercice 1
Installer `ufw` et n'autoriser que le port 80 en entrée.
Vérifier avec :
```
nmap -p 80 ADRESSE_IP
nmap -p 443 ADRESSE_IP
```
La première doit renvoyer que le port est ouvert, mais pas la seconde.
---
## Exercice 2
Modifier le `.htaccess` du répertoire `secret` précédemment créé pour autoriser aussi l'adresse IP `127.0.0.1` à y accéder sans mot de passe.
Vérifier avec curl.
---
## Exercice 3
Cacher les versions de PHP et Apache. Vérifier avec Curl.
---
## Exercice 4 (facultatif)
Installer Nikto et scanner les vhosts du serveur web. Nikto est dans les dépôts `non-free` de Debian : https://debian-facile.org/doc:systeme:apt:sources.list:sources.list-non-free

View File

@ -0,0 +1,11 @@
.PHONY: slides pdf all
all: slides pdf
slides:
for i in 0*.md; do pandoc -t s5 -s -o $$i.html $$i; done;
rename 's/.md.html/.html/' *.html
pdf:
for i in 0*.html; do prince $$i; done;
rename 's/.html.pdf/.pdf/' *.pdf

View File

@ -0,0 +1,37 @@
Préparation pour intervenant :
== Partie 1 - DNS
1. Mettre en place un enregistrement CNAME d'un sous-domaine qui pointe sur un autre sous-domaine qui n'existe pas.
2. Bonus si possible : désynchroniser le DNS primaire et les secondaires de la zone pour que seul le primaire ait le CNAME, et que le serial du SOA soit différent entre primaire et secondaire.
== Partie 2 - HTTP
Rien à faire.
== Partie 3 - HTTPS
Faire signer un sous-domaine réel (mais non utilisé) par Let's Encrypt, et recopier le certificat (fullchain.pem et privkey.pem) pour que les étudiants puissent mettre en place ce vhost signé sur leur VM.
== Partie 4 - Web dynamique
== TODO - améliorations et idées à prendre en compte pour prochaine session
- pas assez de schémas visuels dans les slides / supports
- texte (tags pre) qui dépassent des slides
Difficultés rencontrées le 16 mai 2019 :
- DNS : problèmes de DNS menteur sur certains réseaux 4G (Bouygues) qui altèrent les réponses DNS
- mauvaise assimilation / confusion sur différence entre IP et host DNS, confusion entre host DNS et vhost HTTP chez certains étudiants (environ 3-4 sur 17)
- certains recopient de tutos datés du net sans réfléchir…
- certains ne lisent pas les énoncés…
- rythme relativement soutenu, parfois un peu dur pour les élèves de suivre d'une partie à l'autre (beaucoup de sujets abordés)
Idées pour la partie DNS :
- Mettre en place un DNS sur réseau local, avec un TLD virtuel, et pouvoir déléguer des zones NS à chacun des postes des étudiants, pour qu'ils puissent mettre en place leur propre serveur autoritaire et se faire des requêtes entre eux
Pour le web dynamique ça serait bien de leur faire installer un CMS flatfile (pas de base de données, pour simplifier).

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="951"
height="519"
version="1.1"
id="svg4707"
sodipodi:docname="DNS_schema.svg"
inkscape:version="0.92.1 r15371">
<metadata
id="metadata4713">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4711" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1055"
id="namedview4709"
showgrid="false"
inkscape:zoom="0.67893756"
inkscape:cx="752.78408"
inkscape:cy="272.96054"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="1"
inkscape:current-layer="svg4707"
fit-margin-top="10"
fit-margin-left="10"
fit-margin-right="10"
fit-margin-bottom="10" />
<g
id="g4627"
style="stroke-width:3"
transform="translate(-116.5,-72.5)">
<path
d="m 236,516 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 236 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z M 140,372 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 140 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z M 332,228 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 332 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z m 0,-144 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 332 c -7,0 -12,-5 -12,-12 V 96 c 0,-7 5,-12 12,-12 z m 68,64 v 80 m 0,64 -192,80 m 1,65 95,79"
id="path4619"
inkscape:connector-curvature="0"
style="fill:#d8e2c3;stroke:#bd1220" />
<path
d="m 428,516 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 428 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z m 96,-144 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 524 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z M 908,228 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 908 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z m -192,0 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 716 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z m -192,0 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 524 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z m -384,0 h 136 c 7,0 12,5 12,12 v 40 c 0,7 -5,12 -12,12 H 140 c -7,0 -12,-5 -12,-12 v -40 c 0,-7 5,-12 12,-12 z M 592,372 400,292 M 496,516 208,436 M 976,228 400,148 m 384,80 -384,-80 m 0,0 192,80 m -384,0 192,-80"
id="path4621"
inkscape:connector-curvature="0"
style="fill:#d3e2ea;stroke:#006ab2"
sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssssssssssssssssssssscccccccccccc" />
</g>
<g
font-size="48"
id="g4705"
style="font-size:48px;font-family:'Liberation Sans';text-anchor:middle;fill:#006ab2"
transform="translate(-116.5,-72.5)">
<text
x="401"
y="134"
font-size="85"
id="text4645"
style="font-size:85px">.</text>
<text
x="208"
y="276"
id="text4647">com</text>
<text
x="400"
y="276"
id="text4649">org</text>
<text
x="592"
y="276"
id="text4651">net</text>
<switch
transform="translate(784,276)"
id="switch4665">
<text
id="text4663">fr</text>
</switch>
<text
x="976"
y="276"
id="text4667">...</text>
<text
x="592"
y="420"
id="text4671">...</text>
<text
x="208"
y="416"
font-size="32"
id="text4673"
style="font-size:32px">wikipedia</text>
<switch
transform="translate(304,564)"
id="switch4701">
<text
systemLanguage="de"
id="text4687">de</text>
<text
systemLanguage="en"
id="text4689">en</text>
<text
systemLanguage="es"
id="text4691">es</text>
<text
systemLanguage="jbo"
id="text4693">jbo</text>
<text
systemLanguage="pl"
id="text4695">pl</text>
<text
systemLanguage="ru"
id="text4697">ru</text>
<text
id="text4699">fr</text>
</switch>
<text
x="496"
y="564"
id="text4703">...</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,23 @@
/* The following styles size and place the slide components.
Edit them if you want to change the overall slide layout.
The commented lines can be uncommented (and modified, if necessary)
to help you with the rearrangement process. */
div#header, div#footer, div.slide {width: 100%; top: 0; left: 0;}
div#header {top: 0; left: 0; z-index: 1;}
div#footer {top: auto; bottom: 0; width: 100%; z-index: 5;}
div.slide {top: 0; width: 88%; padding: 1em 7% 2em 5%; z-index: 2;}
#footer div#controls {bottom: 1.5em; left: 0; width: 100%; text-align: center; z-index: 1;}
div#controls form {margin: 0; padding: 0;}
#currentSlide {position: absolute; left: 0; bottom: 0.5em; z-index: 10;
width: 100%; text-align: center;}
html>body #currentSlide {position: fixed;}
/*
div#header {background: #FCC;}
div#footer {background: #CCF;}
div#controls {background: #BBD;}
div#currentSlide {background: #FFC;}
*/

View File

@ -0,0 +1,7 @@
/* DO NOT CHANGE THESE unless you really want to break Opera Show */
.slide {
visibility: visible !important;
position: static !important;
page-break-before: always;
}
#slide0 {page-break-before: avoid;}

View File

@ -0,0 +1,15 @@
/* don't change this unless you want the layout stuff to show up in the outline view! */
.layout div, #footer *, #controlForm * {display: none;}
#footer, #controls, #controlForm, #navLinks, #toggle {
display: block; visibility: visible; margin: 0; padding: 0;}
#toggle {float: right; padding: 0.5em;}
html>body #toggle {position: fixed; top: 0; right: 0;}
/* making the outline look pretty-ish */
#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
#slide0 h1 {padding-top: 1.5em;}
.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em;
border-top: 1px solid #888; border-bottom: 1px solid #AAA;}
#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}

View File

@ -0,0 +1,38 @@
/* Following are the presentation styles -- edit away!
Note that the 'body' font size may have to be changed if the resolution is
different than expected. */
body {background: #95A7D4 url(bg-slide.jpg) 100% 100% no-repeat; color: #210; font: 29px Arial, sans-serif;}
a {text-decoration: none; color: #336; border-bottom: 1px dotted;}
h1, h2, h3, h4, h5, h6 {font-size: 1em; margin: 0;}
sup {font-size: 0.75em; font-weight: normal;
vertical-align: 0.5em; line-height: 1px;}
ul {margin-left: 1em; padding-left: 0;}
li {margin-bottom: 0.66em;}
li li {margin: 0.33em 0; font-size: smaller;}
#header {background: url(bg-shade.png); border-bottom: 1px solid #333;
padding-bottom: 2em;}
#footer {background: url(bg-shade.png); color: #BBB; border-top: 1px solid #333;}
#header, #footer {font-size: 0.5em;}
#footer h1, #footer h2 { padding: 0.5em 0.75em;
font-weight: normal; font-style: italic;}
#footer h1 {left: 0; font-size: 1em; letter-spacing: 1px;}
#footer h2 {position: absolute; bottom: 0; right: 0;}
#controls a {display: none;}
#controls select {visibility: hidden;}
#controls div:hover select {visibility: visible;}
#currentSlide {font-size: 0.5em;}
#currentSlide span {font-size: 13px; color: rgb(49%,47%,66%);}
#currentSlide #csSep {display: none;}
#currentSlide #csHere {font-weight: bold;}
#currentSlide #csHere:before {content: "#"; font-weight: normal;}
#currentSlide #csTotal:before {content: " of ";}
.slide h1 {font-size: 1.66em; line-height: 1; letter-spacing: -1px;
margin: 0 -15% 1em 0; padding: 0.25em 15% 0.06125em 0; border-bottom: 0.06125em solid rgb(90,94,120);}
#slide0 h1 {border: none; font-size: 2.25em; letter-spacing: 0; margin: 3em 0 1.5em;}
#slide0 h3 {margin-bottom: 0;}
#slide0 h4 {margin-top: 0; font-size: smaller;}

View File

@ -0,0 +1 @@
/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */

View File

@ -0,0 +1,9 @@
/* Do not edit or override these styles! The system will likely break if you do. */
div#header, div#footer, div.slide {position: absolute;}
html>body div#header, html>body div#footer, html>body div.slide {position: fixed;}
div.slide {visibility: hidden;}
#slide0 {visibility: visible;}
div#controls {position: absolute;}
#footer>div#controls {position: fixed;}
.handout {display: none;}

View File

@ -0,0 +1,5 @@
@import url("s5-core.css"); /* required to make the slide show run at all */
@import url("framing.css"); /* sets basic placement and size of slide components */
@import url(pretty.css); /* stuff that makes the slides look better than blah */
img { max-height: 25rem; }

View File

@ -0,0 +1,553 @@
// S5 v1.1 slides.js -- released into the Public Domain
//
// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
// about all the wonderful and talented contributors to this code!
var undef;
var slideCSS = '';
var snum = 0;
var smax = 1;
var incpos = 0;
var number = undef;
var s5mode = true;
var defaultView = 'slideshow';
var controlVis = 'visible';
var isIE = navigator.appName == 'Microsoft Internet Explorer' && navigator.userAgent.indexOf('Opera') < 1 ? 1 : 0;
var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
function hasClass(object, className) {
if (!object.className) return false;
return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
}
function hasValue(object, value) {
if (!object) return false;
return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
}
function removeClass(object,className) {
if (!object) return;
object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
}
function addClass(object,className) {
if (!object || hasClass(object, className)) return;
if (object.className) {
object.className += ' '+className;
} else {
object.className = className;
}
}
function GetElementsWithClassName(elementName,className) {
var allElements = document.getElementsByTagName(elementName);
var elemColl = new Array();
for (var i = 0; i< allElements.length; i++) {
if (hasClass(allElements[i], className)) {
elemColl[elemColl.length] = allElements[i];
}
}
return elemColl;
}
function isParentOrSelf(element, id) {
if (element == null || element.nodeName=='BODY') return false;
else if (element.id == id) return true;
else return isParentOrSelf(element.parentNode, id);
}
function nodeValue(node) {
var result = "";
if (node.nodeType == 1) {
var children = node.childNodes;
for (var i = 0; i < children.length; ++i) {
result += nodeValue(children[i]);
}
}
else if (node.nodeType == 3) {
result = node.nodeValue;
}
return(result);
}
function slideLabel() {
var slideColl = GetElementsWithClassName('*','slide');
var list = document.getElementById('jumplist');
smax = slideColl.length;
for (var n = 0; n < smax; n++) {
var obj = slideColl[n];
var did = 'slide' + n.toString();
obj.setAttribute('id',did);
if (isOp) continue;
var otext = '';
var menu = obj.firstChild;
if (!menu) continue; // to cope with empty slides
while (menu && menu.nodeType == 3) {
menu = menu.nextSibling;
}
if (!menu) continue; // to cope with slides with only text nodes
var menunodes = menu.childNodes;
for (var o = 0; o < menunodes.length; o++) {
otext += nodeValue(menunodes[o]);
}
list.options[list.length] = new Option(n + ' : ' + otext, n);
}
}
function currentSlide() {
var cs;
if (document.getElementById) {
cs = document.getElementById('currentSlide');
} else {
cs = document.currentSlide;
}
cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
'<span id="csSep">\/<\/span> ' +
'<span id="csTotal">' + (smax-1) + '<\/span>';
if (snum == 0) {
cs.style.visibility = 'hidden';
} else {
cs.style.visibility = 'visible';
}
}
function go(step) {
if (document.getElementById('slideProj').disabled || step == 0) return;
var jl = document.getElementById('jumplist');
var cid = 'slide' + snum;
var ce = document.getElementById(cid);
if (incrementals[snum].length > 0) {
for (var i = 0; i < incrementals[snum].length; i++) {
removeClass(incrementals[snum][i], 'current');
removeClass(incrementals[snum][i], 'incremental');
}
}
if (step != 'j') {
snum += step;
lmax = smax - 1;
if (snum > lmax) snum = lmax;
if (snum < 0) snum = 0;
} else
snum = parseInt(jl.value);
var nid = 'slide' + snum;
var ne = document.getElementById(nid);
if (!ne) {
ne = document.getElementById('slide0');
snum = 0;
}
if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
if (incrementals[snum].length > 0 && incpos == 0) {
for (var i = 0; i < incrementals[snum].length; i++) {
if (hasClass(incrementals[snum][i], 'current'))
incpos = i + 1;
else
addClass(incrementals[snum][i], 'incremental');
}
}
if (incrementals[snum].length > 0 && incpos > 0)
addClass(incrementals[snum][incpos - 1], 'current');
ce.style.visibility = 'hidden';
ne.style.visibility = 'visible';
jl.selectedIndex = snum;
currentSlide();
number = 0;
}
function goTo(target) {
if (target >= smax || target == snum) return;
go(target - snum);
}
function subgo(step) {
if (step > 0) {
removeClass(incrementals[snum][incpos - 1],'current');
removeClass(incrementals[snum][incpos], 'incremental');
addClass(incrementals[snum][incpos],'current');
incpos++;
} else {
incpos--;
removeClass(incrementals[snum][incpos],'current');
addClass(incrementals[snum][incpos], 'incremental');
addClass(incrementals[snum][incpos - 1],'current');
}
}
function toggle() {
var slideColl = GetElementsWithClassName('*','slide');
var slides = document.getElementById('slideProj');
var outline = document.getElementById('outlineStyle');
if (!slides.disabled) {
slides.disabled = true;
outline.disabled = false;
s5mode = false;
fontSize('1em');
for (var n = 0; n < smax; n++) {
var slide = slideColl[n];
slide.style.visibility = 'visible';
}
} else {
slides.disabled = false;
outline.disabled = true;
s5mode = true;
fontScale();
for (var n = 0; n < smax; n++) {
var slide = slideColl[n];
slide.style.visibility = 'hidden';
}
slideColl[snum].style.visibility = 'visible';
}
}
function showHide(action) {
var obj = GetElementsWithClassName('*','hideme')[0];
switch (action) {
case 's': obj.style.visibility = 'visible'; break;
case 'h': obj.style.visibility = 'hidden'; break;
case 'k':
if (obj.style.visibility != 'visible') {
obj.style.visibility = 'visible';
} else {
obj.style.visibility = 'hidden';
}
break;
}
}
// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
function keys(key) {
if (!key) {
key = event;
key.which = key.keyCode;
}
if (key.which == 84) {
toggle();
return;
}
if (s5mode) {
switch (key.which) {
case 10: // return
case 13: // enter
if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
if (key.target && isParentOrSelf(key.target, 'controls')) return;
if(number != undef) {
goTo(number);
break;
}
case 32: // spacebar
case 34: // page down
case 39: // rightkey
case 40: // downkey
if(number != undef) {
go(number);
} else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
go(1);
} else {
subgo(1);
}
break;
case 33: // page up
case 37: // leftkey
case 38: // upkey
if(number != undef) {
go(-1 * number);
} else if (!incrementals[snum] || incpos <= 0) {
go(-1);
} else {
subgo(-1);
}
break;
case 36: // home
goTo(0);
break;
case 35: // end
goTo(smax-1);
break;
case 67: // c
showHide('k');
break;
}
if (key.which < 48 || key.which > 57) {
number = undef;
} else {
if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
if (key.target && isParentOrSelf(key.target, 'controls')) return;
number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
}
}
return false;
}
function clicker(e) {
number = undef;
var target;
if (window.event) {
target = window.event.srcElement;
e = window.event;
} else target = e.target;
if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true;
if (!e.which || e.which == 1) {
if (!incrementals[snum] || incpos >= incrementals[snum].length) {
go(1);
} else {
subgo(1);
}
}
}
function findSlide(hash) {
var target = null;
var slides = GetElementsWithClassName('*','slide');
for (var i = 0; i < slides.length; i++) {
var targetSlide = slides[i];
if ( (targetSlide.name && targetSlide.name == hash)
|| (targetSlide.id && targetSlide.id == hash) ) {
target = targetSlide;
break;
}
}
while(target != null && target.nodeName != 'BODY') {
if (hasClass(target, 'slide')) {
return parseInt(target.id.slice(5));
}
target = target.parentNode;
}
return null;
}
function slideJump() {
if (window.location.hash == null) return;
var sregex = /^#slide(\d+)$/;
var matches = sregex.exec(window.location.hash);
var dest = null;
if (matches != null) {
dest = parseInt(matches[1]);
} else {
dest = findSlide(window.location.hash.slice(1));
}
if (dest != null)
go(dest - snum);
}
function fixLinks() {
var thisUri = window.location.href;
thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
var aelements = document.getElementsByTagName('A');
for (var i = 0; i < aelements.length; i++) {
var a = aelements[i].href;
var slideID = a.match('\#slide[0-9]{1,2}');
if ((slideID) && (slideID[0].slice(0,1) == '#')) {
var dest = findSlide(slideID[0].slice(1));
if (dest != null) {
if (aelements[i].addEventListener) {
aelements[i].addEventListener("click", new Function("e",
"if (document.getElementById('slideProj').disabled) return;" +
"go("+dest+" - snum); " +
"if (e.preventDefault) e.preventDefault();"), true);
} else if (aelements[i].attachEvent) {
aelements[i].attachEvent("onclick", new Function("",
"if (document.getElementById('slideProj').disabled) return;" +
"go("+dest+" - snum); " +
"event.returnValue = false;"));
}
}
}
}
}
function externalLinks() {
if (!document.getElementsByTagName) return;
var anchors = document.getElementsByTagName('a');
for (var i=0; i<anchors.length; i++) {
var anchor = anchors[i];
if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
anchor.target = '_blank';
addClass(anchor,'external');
}
}
}
function createControls() {
var controlsDiv = document.getElementById("controls");
if (!controlsDiv) return;
var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
var hideDiv, hideList = '';
if (controlVis == 'hidden') {
hideDiv = hider;
} else {
hideList = hider;
}
controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
'<div id="navLinks">' +
'<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>' +
'<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>' +
'<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>' +
'<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
'<\/div><\/form>';
if (controlVis == 'hidden') {
var hidden = document.getElementById('navLinks');
} else {
var hidden = document.getElementById('jumplist');
}
addClass(hidden,'hideme');
}
function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
if (!s5mode) return false;
var vScale = 22; // both yield 32 (after rounding) at 1024x768
var hScale = 32; // perhaps should auto-calculate based on theme's declared value?
if (window.innerHeight) {
var vSize = window.innerHeight;
var hSize = window.innerWidth;
} else if (document.documentElement.clientHeight) {
var vSize = document.documentElement.clientHeight;
var hSize = document.documentElement.clientWidth;
} else if (document.body.clientHeight) {
var vSize = document.body.clientHeight;
var hSize = document.body.clientWidth;
} else {
var vSize = 700; // assuming 1024x768, minus chrome and such
var hSize = 1024; // these do not account for kiosk mode or Opera Show
}
var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
fontSize(newSize + 'px');
if (isGe) { // hack to counter incremental reflow bugs
var obj = document.getElementsByTagName('body')[0];
obj.style.display = 'none';
obj.style.display = 'block';
}
}
function fontSize(value) {
if (!(s5ss = document.getElementById('s5ss'))) {
if (!isIE) {
document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
s5ss.setAttribute('media','screen, projection');
s5ss.setAttribute('id','s5ss');
} else {
document.createStyleSheet();
document.s5ss = document.styleSheets[document.styleSheets.length - 1];
}
}
if (!isIE) {
while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
} else {
document.s5ss.addRule('body','font-size: ' + value + ' !important;');
}
}
function notOperaFix() {
slideCSS = document.getElementById('slideProj').href;
var slides = document.getElementById('slideProj');
var outline = document.getElementById('outlineStyle');
slides.setAttribute('media','screen');
outline.disabled = true;
if (isGe) {
slides.setAttribute('href','null'); // Gecko fix
slides.setAttribute('href',slideCSS); // Gecko fix
}
if (isIE && document.styleSheets && document.styleSheets[0]) {
document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
}
}
function getIncrementals(obj) {
var incrementals = new Array();
if (!obj)
return incrementals;
var children = obj.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (hasClass(child, 'incremental')) {
if (child.nodeName == 'OL' || child.nodeName == 'UL') {
removeClass(child, 'incremental');
for (var j = 0; j < child.childNodes.length; j++) {
if (child.childNodes[j].nodeType == 1) {
addClass(child.childNodes[j], 'incremental');
}
}
} else {
incrementals[incrementals.length] = child;
removeClass(child,'incremental');
}
}
if (hasClass(child, 'show-first')) {
if (child.nodeName == 'OL' || child.nodeName == 'UL') {
removeClass(child, 'show-first');
if (child.childNodes[isGe].nodeType == 1) {
removeClass(child.childNodes[isGe], 'incremental');
}
} else {
incrementals[incrementals.length] = child;
}
}
incrementals = incrementals.concat(getIncrementals(child));
}
return incrementals;
}
function createIncrementals() {
var incrementals = new Array();
for (var i = 0; i < smax; i++) {
incrementals[i] = getIncrementals(document.getElementById('slide'+i));
}
return incrementals;
}
function defaultCheck() {
var allMetas = document.getElementsByTagName('meta');
for (var i = 0; i< allMetas.length; i++) {
if (allMetas[i].name == 'defaultView') {
defaultView = allMetas[i].content;
}
if (allMetas[i].name == 'controlVis') {
controlVis = allMetas[i].content;
}
}
}
// Key trap fix, new function body for trap()
function trap(e) {
if (!e) {
e = event;
e.which = e.keyCode;
}
try {
modifierKey = e.ctrlKey || e.altKey || e.metaKey;
}
catch(e) {
modifierKey = false;
}
return modifierKey || e.which == 0;
}
function startup() {
defaultCheck();
if (!isOp)
createControls();
slideLabel();
fixLinks();
externalLinks();
fontScale();
if (!isOp) {
notOperaFix();
incrementals = createIncrementals();
slideJump();
if (defaultView == 'outline') {
toggle();
}
document.onkeyup = keys;
document.onkeypress = trap;
document.onclick = clicker;
}
}
window.onload = startup;
window.onresize = function(){setTimeout('fontScale()', 50);}

2
cesi/nosql/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pdf
Slides/*.html

View File

@ -0,0 +1,238 @@
# Initiation à NoSQL
## Sylvain Eliade, Cadoles
------
## C'est quoi NoSQL ?
* Désigne toutes les bases de données non-relationnelles
* Base relationnelle (RDBMS) = généralement SQL
* Mais on peut faire du SQL non-relationnel !
* Donc maintenant, NoSQL = "Not Only SQL"
* Au final, un mot un peu trop vague, comme "Web 2.0"
---
## Rappel : RDBM
<figure>
<img src="Images/rdbm.svg" alt="" />
</figure>
---
## Rappel : ACID
* Atomique = tout changement (transaction) à la BDD doit fonctionner ou échouer en entier (mais pas être exécuté à moitié et échouer à moitié !)
* Consistant = toutes les règles imposées doivent être valides (clés, triggers, contraintes, etc.) pour empêcher la corruption de la BDD
* Isolation = les transactions pouvant être exécutées en même temps, une requête concurrente ne doit pas avoir accès à un état transitoire de la BDD
* Durabilité = une transaction écrite dans la BDD doit le rester en cas de crash logiciel ou coupure du serveur
---
## Différences entre RDBMS et NoSQL
* Généralement pas ACID (Atomicity, Consistency, Isolation, Durability)
* Mais parfois oui (CouchDB), parfois partiellement
* Théoriquement plus facile à dimensionner horizontalement
* En pratique les RDBMS se dimensionnent très bien aussi
* La plus grosse différence et intérêt : non relationnel ! :)
---
### Quand utiliser une BDD noSQL ?
* Besoin de très grosses performances
* … ou stockage de très gros volume de données
* Données très spécifiques et non-relationnelles
* Et surtout : pas de besoins relationnels !
---
### Quand utiliser une BDD noSQL ?
* … mais même dans ces cas, un RDBM est souvent plus simple et rapide à mettre en œuvre
* Et un RDBM supporte aussi de très grandes quantités de données et de bonnes performances… si vous savez bien l'utiliser :)
* Vous n'êtes pas Google, Amazon ou Alibaba !
* Une solution SQL (Postgre, MySQL, SQL Server, Oracle…) sera adaptée à 95% des besoins
* Sinon : petit projet, "pour tester", qui ne sera pas amené à évoluer, car changer de BDD est lourd !
---
## NoSQL : une solution parmi d'autres
* Les bases NoSQL ont été créées pour répondre à des besoins de très gros acteurs
* Besoins qui sont rarement atteints ailleurs
* NoSQL est une solution, pas LA solution
* Bien évaluer le problème avant de choisir la ou les solutions :)
* Le bon côté : NoSQL a initié une modernisation des RDBMs
---
## Google abandonne NoSQL
* Google, à l'origine de BigTable et MapReduce, premières solutions NoSQL
* … sont repassés à SQL avec [Spanner et le "Standard SQL"](https://blog.timescale.com/blog/why-sql-beating-nosql-what-this-means-for-future-of-data-time-series-database-348b777b847a/) commun à plusieurs outils internes.
* Car SQL facilite l'arrivée de nouveaux développeurs et la possibilité de communiquer avec des outils différents mais avec le même langage.
* Résultat : solutions NoSQL requêtables en SQL :)
---
## NoSQL dans SQL, le meilleur des deux mondes ?
* Stockage JSON dans PostgreSQL (depuis la version 9.2), MySQL (5.7.8), SQLite (3.9.0), SQL Server
* Recherche plein texte, index sur les données JSON, jointures !
* Implémentation légèrement différente dans SQLite
* Performance : pas forcément lent
* PostgreSQL est plus rapide avec JSONB que MongoDB par exemple (mais nécessite plus d'optimisation de la configuration)
---
## Les familles de bases NoSQL
* Clé-valeur (Berkeley DB, memcached, Redis, Apache Ignite, etc.)
* Document (MongoDB, Apache CouchDB, etc.)
* Colonnes ou "wide column" (Cassandra, HBase, etc.)
* Graph (Neo4j, Apache Giraph…)
---
## Bases de données clé-valeur
* Aussi vieilles que l'informatique !
* On référence une valeur à l'aide d'une clé pour aider à retrouver la valeur
* La valeur ne fait pas de différence pour le moteur de BDD (opaque)
* On ne peut donc pas trouver une entrée juste avec une partie de la valeur
* Du plus simple (memcached, Berkeley DB) au plus évolué (Redis)
* Rapide, simple, efficace
---
## Bases de données clé-valeur
<figure>
<img src="Images/kv.png" alt="" />
</figure>
---
### Quand utiliser une BDD clé-valeur ?
* Données simples et à une seule dimension
* Données qui peuvent expirer
* Pas forcément besoin de persistance
* Exemples : cache, queue, statistiques…
---
### Quand ne pas utiliser une BDD clé-valeur ?
* Données structurées sur plusieurs niveaux (2D+)
* Besoins de jointures entre les données
* Besoin d'index sur le contenu des valeurs
* Besoin de chercher dans les valeurs
* Besoin de lister toutes les clés (lent)
* Données très grandes (selon le moteur de BDD, par exemple si les données sont stockées en RAM)
---
## Bases de données document
* Évolution du modèle clé-valeur (document = valeur)
* Sauf que le contenu de la valeur peut être indexé / référencé
* Plutôt adapté à un modèle où les documents sont indépendants et n'ont pas de relation entre eux
* Exemples : MongoDB, CouchDB, etc.
---
## Bases de données document
<figure>
<img src="Images/document.png" alt="" />
</figure>
---
### Quand utiliser une BDD document ?
* Données structurées ou complexes
* Structure des données très variable
* Données non relationnelles
* Pas de schéma
* Exemple : fiches produit d'un site ecommerce
---
## Base de données orientée colonnes
* Comme une BDD clé-valeur, mais en 2D !
* On retrouve une donnée à l'aide d'une clé (ligne) et d'un nom de colonne
* Toutes les lignes n'ont pas forcément les même colonnes (contrairement à une table dans un RDBM)
* Les colonnes sont donc indépendantes d'une ligne à l'autre
* Exemples : Cassandra, HBase (historiquement : Google BigTable)
---
### Quand utiliser une BDD orientée colonnes ?
* Beaucoup d'écritures (ajouts)
* Grand volume de données
* Besoins de réplication
* Données peu structurées
* Données en 2D uniquement (clé d'accès + colonnes)
* Exemple idéal : statistiques, messageries temps réel
---
### Quand ne pas utiliser une BDD orientée colonnes ?
* Beaucoup de mises à jour / suppression de lignes
* Besoin de transactions, de rollbacks, de triggers, joins, etc.
* Besoin ACID : ce n'est pas du tout fait pour
* Besoin de parcourir toutes les données stockées : lent !
---
## Base de données graph
* Documents (= nœuds) liés ensemble par des relations (= arcs ou graphs)
* Les relations peuvent disposer de propriétés selon le contexte
* On peut accéder aux nœuds via leurs relations
---
## Base de données graph
<figure>
<img src="Images/graph.png" alt="" />
</figure>
---
### Quand utiliser une BDD graph ?
* Données non structurées (pas de schéma)
* Liées ensemble de manière non ordonnée
* Exemples : graph d'amis (réseau social), recommandations de produits, détection de fraude…
---
### Quand ne pas utiliser une BDD graph ?
* Données non liées
* Données séquentielles
* Pas de besoin de lire les données
* Données dans un schéma fixe
* Besoin de stocker beaucoup de données dans les propriétés
---
### Exemples de NoSQL chez Skyrock
* Skyrock : 20+ millions d'utilisateurs, 4+ milliards de commentaires, 500.000 articles / jour, 2 millions de commentaires / jour… 2ème site de France 2007-2010
* [Sharedance](https://github.com/jedisct1/sharedance) (clé-valeur, ancêtre de memcached) : stockage de sessions PHP dans un système de fichier en ramdisk
* Topy : serveur de statistiques en RAM (avec autodump sur disque). Exemple : utilisateurs les plus actifs, blogs les plus consultés, etc.
* [Fluxy](http://zmoo.fr/fluxy.php) : serveur de newsfeed en RAM (avec autodump). Liste des événements liés à un utilisateur. 2 serveurs pour 20+ millions d'utilisateurs
* memcached puis Redis : cache de résultats MySQL, liste des utilisateurs connectés, cache des images uploadées en cours de traitement…
* MongoDB : application mobile de chat Smax

46
cesi/nosql/02-Redis.md Normal file
View File

@ -0,0 +1,46 @@
# Introduction à Redis
## Sylvain Eliade, Cadoles
---
## Redis
* Stockage en mémoire
* Mais pas que… Stockage persistant optionnel
* Base de données, cache, pub-sub
* Réplication, transactions, partitionnement…
* Nombreux types de structures de données, majoritairement clé-valeur
* Très très rapide
* Un seul thread, mais c'est pas grave, c'est pas le CPU qui limite
* Scriptable avec Lua
---
## Types de structures de données
* Chaînes de caractère
* Listes simples
* Jeux de données uniques non-ordonnées (sets)
* Dictionnaires (hashes)
* Liste triée (sorted set)
---
## Le protocole de Redis
* Protocole texte simple (utilisable par telnet !)
* Commandes texte suivies d'arguments : `SET clé valeur`
* Réponse texte : `OK`, chaînes, etc.
---
## Commandes de base
* [Commandes Redis](https://redis.io/commands)
* [Types Redis](https://redis.io/topics/data-types)
* Redis-cli !
* `SET test coucou``OK`
* `GET test``"coucou"`
* `DEL test``(integer) 1` = une clé supprimée, c'est bon !
* `KEYS *` = lister toutes les clés

View File

@ -0,0 +1,83 @@
# Exercices Redis
* Utiliser redis-cli et copier/coller le résultat de chaque exercice (commandes et retours de Redis) dans un fichier texte.
* [Installer Redis sous Windows](https://www.supinfo.com/articles/single/8843-redis-installation-windows)
---
## Exercice 1
* créer une clé "normale" avec sa valeur
* récupérer le résultat
* supprimer la clé
---
## Exercice 2 : expiration
* créer une clé
* lui donner une expiration courte (quelques secondes)
* vérifier que la clé "disparaît" toute seule
---
## Exercice 3 : compteurs
* Créer une clé contenant un numéro
* L'incrémenter et le décrementer avec les commandes Redis adaptées
---
## Exercice 4 : liste unique non ordonnée
* Créer une liste unique non ordonnée (set, `SADD`)
* Y insérer plusieurs entrées
* Insérer des entrées en double
* Vérifier que la liste ne contient pas de doublons
* Supprimer des entrées
---
## Exercice 5 : liste ordonnée par ordre d'insertion
* Créer une liste ordonnée (`LPUSH`)
* Ajouter des entrées par la gauche et la droite (`LPUSH` et `RPUSH`)
* Récupérer une partie de la liste
* Supprimer des éléments par la gauche, la droite (pop) et arbitrairement (rem)
---
## Exercice 6 : hashes
* Créer un hash avec plusieurs sous-clés et sous-valeurs (`HSET` et `HMSET`)
* Récupérer toutes les sous-valeurs du hash
* Modifier une seule sous-valeur
* Récupérer une seule sous-valeur
---
## Exercice 7 : liste ordonnée par score
* Enregistrer les scores de 10 joueurs de Tetris dans une liste ordonnée (`ZADD`), avec leurs noms et leurs scores
* Récupérer la liste des 5 meilleurs joueurs (`ZRANGE`)
* Récupérer le score du joueur Bob
---
## Mini-projet : newsfeed de réseau social
* Note : tout le monde doit utiliser le même serveur Redis au final !
* Travail en équipe (groupes et classe).
* Prérequis avant de coder : se mettre d'accord avec le reste de la classe de la structure des données à stocker dans Redis (types, noms des clés, etc.) !
* Pour rendre les choses plus faciles : la base Redis contiendra une liste unique non ordonnée "utilisateurs" contenant la liste des noms/pseudo des utilisateurs du réseau social.
* L'application doit permettre d'ajouter des posts à sa propre timeline
* Les posts doivent contenir : date, nom de l'utilisateur, contenu du post
* Chaque utilisateur a une timeline différente selon qui il veut suivre
* Mais le contenu des posts ne doit être stocké qu'une seule fois !
* L'application doit propager ces posts aux utilisateurs inscrits à sa propre timeline
* L'application doit permettre de lire les derniers posts des utilisateurs auxquels on s'est inscrit
* Note : l'implémentation de la gestion des utilisateurs et de l'inscription aux timelines des autres utilisateurs est facultative (création d'utilisateur et inscription aux timelines sont possibles à la main avec redis-cli).
* Note 2 : certaines données associatives peuvent être doublonnées (présence dans plusieurs clés) si nécessaire.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
cesi/nosql/Images/graph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
cesi/nosql/Images/kv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="195.79131" height="40.452461" id="svg3780" version="1.1" inkscape:version="0.48.3.1 r9886" sodipodi:docname="logo.svg">
<defs id="defs3782"/>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="4.2416268" inkscape:cx="45.753768" inkscape:cy="19.200676" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1366" inkscape:window-height="744" inkscape:window-x="0" inkscape:window-y="24" inkscape:window-maximized="1">
<inkscape:grid type="xygrid" id="grid3015" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true" originx="-8.39956px" originy="-37.93714px"/>
</sodipodi:namedview>
<metadata id="metadata3785">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g inkscape:label="Calque 1" inkscape:groupmode="layer" id="layer1" transform="translate(-335.39956,-499.83558)">
<path style="fill:#078eb5;fill-opacity:1;stroke:none;display:inline;enable-background:new" d="m 356.56825,499.83558 c -13.23043,0 -21.16869,13.23042 -21.16869,23.81477 l 2.64609,0 0,10.58433 c 5.29217,7.93824 32.07212,8.20297 37.04519,0 l 0,-10.58433 2.64607,0 c 0,-4.29058 -1.30219,-9.01755 -3.73483,-13.12018 l -2.99063,3.03198 0,7.12513 1.61247,2.21885 -2.39802,2.31533 -2.43937,-2.31533 1.72272,-2.14993 -0.0688,-7.71776 3.87264,-3.6108 c -0.97461,-1.47147 -2.10693,-2.84403 -3.37655,-4.0656 l -4.87871,5.18192 0,7.13891 1.61245,2.21886 -2.41179,2.31532 -2.43936,-2.31532 1.73648,-2.16374 -0.0826,-7.71774 5.37486,-5.63672 c -1.29755,-1.09094 -2.7222,-2.03518 -4.27232,-2.77012 l -5.59538,5.93992 0,7.12513 1.62625,2.23264 -2.4118,2.31532 -2.43936,-2.31532 1.73649,-2.16373 -0.0826,-7.71774 5.88478,-5.95371 c -2.05509,-0.79293 -4.29761,-1.24034 -6.72546,-1.24034 z m 6.72545,1.24034 1.2817,0.53749 z m 5.55403,3.30761 1.08875,0.97851 z m 4.46526,5.04411 0.68909,1.10253 z M 352,526.57486 l 8.85806,-0.11137 0.0557,10.43027 -8.91375,0.1018 z" id="path3773" inkscape:connector-curvature="0" sodipodi:nodetypes="scccccccccccccccccccccccccccccccccscccccccccccccc"/>
<g style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#777777;fill-opacity:1;stroke:none;font-family:Liberation Sans Narrow;-inkscape-font-specification:Liberation Sans Narrow Bold Condensed" id="text2983" transform="translate(42.28018,-8.4690297)">
<path d="m 374.16131,539.65491 1.40625,0.95703 c -1.35419,1.86198 -3.07294,3.33333 -5.15625,4.41406 -2.08335,1.06771 -4.32945,1.60156 -6.73828,1.60156 -2.00522,0 -3.91928,-0.39062 -5.74219,-1.17187 -1.82292,-0.78125 -3.39193,-1.83594 -4.70703,-3.16406 -1.31511,-1.32812 -2.36328,-2.91015 -3.14453,-4.7461 -0.78125,-1.83592 -1.17188,-3.76301 -1.17188,-5.78125 0,-2.01821 0.39063,-3.94529 1.17188,-5.78125 0.78125,-1.83591 1.82942,-3.41794 3.14453,-4.74609 1.3151,-1.3281 2.88411,-2.38279 4.70703,-3.16406 1.82291,-0.78122 3.73697,-1.17185 5.74219,-1.17188 2.39581,3e-5 4.63539,0.5469 6.71875,1.64063 2.08331,1.08075 3.80857,2.55862 5.17578,4.43359 l -1.40625,1.03516 c -1.21096,-1.62758 -2.7344,-2.91013 -4.57031,-3.84766 -1.82294,-0.95049 -3.79559,-1.42575 -5.91797,-1.42578 -2.36981,3e-5 -4.5573,0.58596 -6.5625,1.75781 -1.9922,1.1719 -3.56772,2.76695 -4.72656,4.78516 -1.15886,2.00522 -1.73829,4.19923 -1.73828,6.58203 -10e-6,1.77084 0.33853,3.46355 1.01562,5.07812 0.6901,1.61459 1.61458,3.00782 2.77344,4.17969 1.15884,1.17188 2.54556,2.10938 4.16015,2.8125 1.61457,0.69011 3.30728,1.03516 5.07813,1.03516 2.12238,0 4.09503,-0.47526 5.91797,-1.42578 1.83591,-0.95052 3.35935,-2.24609 4.57031,-3.88672" style="font-weight:normal;font-stretch:normal;fill:#777777;fill-opacity:1;font-family:Sawasdee;-inkscape-font-specification:Sawasdee" id="path2997" inkscape:connector-curvature="0"/>
<path d="m 435.4735,526.29553 c 1.36717,2e-5 2.67576,0.26695 3.92578,0.80078 1.24998,0.53388 2.33071,1.25653 3.24218,2.16797 0.91144,0.91148 1.6341,1.99872 2.16797,3.26172 0.53383,1.26303 0.80076,2.58465 0.80078,3.96484 -2e-5,1.39324 -0.26695,2.72137 -0.80078,3.98438 -0.53387,1.26303 -1.25653,2.35026 -2.16797,3.26172 -0.91147,0.89844 -1.9922,1.62109 -3.24218,2.16797 -1.25002,0.53385 -2.55861,0.80078 -3.92578,0.80078 -2.79949,0 -5.18881,-0.99609 -7.16797,-2.98828 -1.97917,-1.99219 -2.96876,-4.40104 -2.96875,-7.22657 -10e-6,-1.84894 0.44921,-3.55467 1.34765,-5.11718 0.91146,-1.57551 2.14192,-2.81248 3.69141,-3.71094 1.56249,-0.91144 3.26171,-1.36717 5.09766,-1.36719 m -8.39844,10.19531 c -1e-5,2.33074 0.82031,4.32944 2.46094,5.9961 1.65363,1.65365 3.64582,2.48047 5.97656,2.48047 2.33071,0 4.31639,-0.82682 5.95703,-2.48047 1.65362,-1.66666 2.48045,-3.66536 2.48047,-5.9961 -2e-5,-2.31769 -0.82685,-4.30337 -2.48047,-5.95703 -1.64064,-1.65362 -3.62632,-2.48045 -5.95703,-2.48047 -2.33074,2e-5 -4.32293,0.82685 -5.97656,2.48047 -1.64063,1.65366 -2.46095,3.63934 -2.46094,5.95703" style="font-weight:normal;font-stretch:normal;fill:#777777;fill-opacity:1;font-family:Sawasdee;-inkscape-font-specification:Sawasdee" id="path3003" inkscape:connector-curvature="0"/>
<path d="m 451.22209,546.41272 -1.75781,0 0,-29.18754 1.75781,0 0,29.18754" style="font-weight:normal;font-stretch:normal;fill:#777777;fill-opacity:1;font-family:Sawasdee;-inkscape-font-specification:Sawasdee" id="path3005" inkscape:connector-curvature="0"/>
<path d="m 456.99022,534.83069 14.39453,0 c -0.3646,-1.96613 -1.22398,-3.58723 -2.57812,-4.86328 -1.35419,-1.27603 -2.90366,-1.91405 -4.64844,-1.91407 -1.73178,2e-5 -3.27475,0.63804 -4.62891,1.91407 -1.34115,1.27605 -2.1875,2.89715 -2.53906,4.86328 m 16.30859,1.66015 -16.58203,0 c 0,2.33074 0.72916,4.30991 2.1875,5.9375 1.45833,1.62761 3.18359,2.44141 5.17578,2.44141 1.31509,0 2.60416,-0.35156 3.86719,-1.05469 1.263,-0.70312 2.22655,-1.64713 2.89063,-2.83203 l 1.54296,0.87891 c -0.79429,1.41927 -1.96616,2.58464 -3.51562,3.49609 -1.54949,0.89844 -3.14455,1.34766 -4.78516,1.34766 -1.65365,0 -3.17709,-0.46224 -4.57031,-1.38672 -1.38021,-0.92448 -2.46745,-2.16797 -3.26172,-3.73047 -0.78125,-1.57551 -1.17188,-3.27473 -1.17187,-5.09766 -1e-5,-1.80988 0.39713,-3.49608 1.1914,-5.05859 0.80729,-1.56248 1.90755,-2.80597 3.30078,-3.73047 1.40625,-0.93748 2.93619,-1.40623 4.58985,-1.40625 1.56248,2e-5 3.01431,0.4232 4.35547,1.26953 1.35415,0.83335 2.44789,1.95966 3.28125,3.37891 0.83331,1.41928 1.32159,2.97527 1.46484,4.66797 l 0.0391,0.8789" style="font-weight:normal;font-stretch:normal;fill:#777777;fill-opacity:1;font-family:Sawasdee;-inkscape-font-specification:Sawasdee" id="path3007" inkscape:connector-curvature="0"/>
<path d="m 487.66068,530.10413 -1.62109,0.5664 c -0.27345,-0.87238 -0.73569,-1.53644 -1.38672,-1.99219 -0.65105,-0.46873 -1.34767,-0.7031 -2.08984,-0.70312 -0.85939,2e-5 -1.59506,0.27346 -2.20703,0.82031 -0.59897,0.54689 -0.89845,1.28908 -0.89844,2.22656 -10e-6,0.49481 0.13671,0.94403 0.41015,1.34766 0.27344,0.40366 0.63151,0.73569 1.07422,0.99609 0.4427,0.26043 0.94401,0.52736 1.50391,0.80079 0.57291,0.27345 1.15233,0.52735 1.73828,0.76171 0.58593,0.23439 1.15884,0.52736 1.71875,0.87891 0.5729,0.35157 1.08072,0.72918 1.52344,1.13281 0.44269,0.40366 0.80076,0.92449 1.07422,1.5625 0.27342,0.63803 0.41014,1.35418 0.41015,2.14844 -1e-5,1.8099 -0.64454,3.28125 -1.93359,4.41406 -1.28908,1.1198 -2.78647,1.67969 -4.49219,1.67969 -0.74219,0 -1.45183,-0.11719 -2.1289,-0.35156 -0.67709,-0.2474 -1.30209,-0.60547 -1.875,-1.07422 -0.57293,-0.46875 -1.06121,-1.09375 -1.46485,-1.875 -0.40365,-0.78125 -0.66406,-1.67317 -0.78125,-2.67578 l 1.73828,-0.25391 c 0.18229,1.48438 0.69661,2.60417 1.54297,3.35938 0.85937,0.75521 1.86197,1.13281 3.00781,1.13281 1.21093,0 2.28515,-0.40364 3.22266,-1.21094 0.93749,-0.82031 1.40624,-1.86848 1.40625,-3.14453 -1e-5,-0.70312 -0.17579,-1.32161 -0.52734,-1.85547 -0.35158,-0.54686 -0.80731,-0.98957 -1.36719,-1.32812 -0.54689,-0.33854 -1.15887,-0.65755 -1.83594,-0.95703 -0.67709,-0.29947 -1.35417,-0.60546 -2.03125,-0.91797 -0.67709,-0.31249 -1.29558,-0.65103 -1.85547,-1.01563 -0.54688,-0.37759 -0.9961,-0.86587 -1.34765,-1.46484 -0.35157,-0.61197 -0.52735,-1.30858 -0.52735,-2.08985 0,-1.45831 0.48177,-2.61716 1.44532,-3.47656 0.97655,-0.85935 2.12889,-1.28904 3.45703,-1.28906 1.09374,2e-5 2.11587,0.33205 3.0664,0.99609 0.95051,0.65106 1.62759,1.60158 2.03125,2.85157" style="font-weight:normal;font-stretch:normal;fill:#777777;fill-opacity:1;font-family:Sawasdee;-inkscape-font-specification:Sawasdee" id="path3009" inkscape:connector-curvature="0"/>
<g style="font-weight:normal;fill:#777777;fill-opacity:1;font-family:Sans" id="text3011">
<path d="m 377.53329,536.50769 c 0,-2.8203 0.99577,-5.22622 2.98731,-7.21777 1.99153,-1.99152 4.39127,-2.98729 7.19922,-2.98731 2.8203,2e-5 5.22622,0.99579 7.21777,2.98731 0.38344,0.39585 0.73598,0.81023 1.05762,1.24316 l 0,-2.5791 1.66992,0 0,18.2207 -1.66992,0 0,-3.71093 c -0.32164,0.43294 -0.67418,0.84733 -1.05762,1.24316 -1.99155,1.99154 -4.39747,2.9873 -7.21777,2.9873 -2.80795,0 -5.20769,-0.99576 -7.19922,-2.9873 -1.99154,-1.99153 -2.98731,-4.39127 -2.98731,-7.19922 m 1.7627,0 c 0,2.32553 0.82259,4.31088 2.46777,5.95606 1.64518,1.63281 3.63053,2.44922 5.95606,2.44921 2.3255,10e-6 4.31085,-0.82259 5.95605,-2.46777 1.23696,-1.23697 2.01007,-2.66568 2.31934,-4.28613 l 0,-3.30274 c -0.30927,-1.6328 -1.08238,-3.06769 -2.31934,-4.30468 -1.6452,-1.64517 -3.63055,-2.46776 -5.95605,-2.46778 -2.32553,2e-5 -4.31088,0.82261 -5.95606,2.46778 -1.64518,1.64519 -2.46777,3.63054 -2.46777,5.95605" style="font-size:38px;font-variant:normal;font-stretch:normal;letter-spacing:-1.11000001000000004px;fill:#777777;fill-opacity:1;font-family:Caviar Dreams;-inkscape-font-specification:Caviar Dreams" id="path3018" inkscape:connector-curvature="0"/>
<path d="m 401.65767,536.50769 c 0,-2.8203 0.99576,-5.22622 2.9873,-7.21777 1.99153,-1.99152 4.39127,-2.98729 7.19922,-2.98731 2.8203,2e-5 5.22622,0.99579 7.21778,2.98731 0.38344,0.39585 0.73598,0.81023 1.05761,1.24316 l 0,-14.0459 1.66993,0 0,29.6875 -1.66993,0 0,-3.71093 c -0.32163,0.43294 -0.67417,0.84733 -1.05761,1.24316 -1.99156,1.99154 -4.39748,2.9873 -7.21778,2.9873 -2.80795,0 -5.20769,-0.99576 -7.19922,-2.9873 -1.99154,-1.99153 -2.9873,-4.39127 -2.9873,-7.19922 m 1.76269,0 c 0,2.32553 0.82259,4.31088 2.46778,5.95606 1.64517,1.63281 3.63052,2.44922 5.95605,2.44921 2.32551,10e-6 4.31086,-0.82259 5.95606,-2.46777 1.23696,-1.23697 2.01007,-2.66568 2.31933,-4.28613 l 0,-3.30274 c -0.30926,-1.6328 -1.08237,-3.06769 -2.31933,-4.30468 -1.6452,-1.64517 -3.63055,-2.46776 -5.95606,-2.46778 -2.32553,2e-5 -4.31088,0.82261 -5.95605,2.46778 -1.64519,1.64519 -2.46778,3.63054 -2.46778,5.95605" style="font-size:38px;font-variant:normal;font-stretch:normal;letter-spacing:-1.11000001000000004px;fill:#777777;fill-opacity:1;font-family:Caviar Dreams;-inkscape-font-specification:Caviar Dreams" id="path3020" inkscape:connector-curvature="0"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg
PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="135 125 577 535" width="442px" height="410px" xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="288" y1="170" x2="298" y2="170" style="stroke:#333;stroke-width:1;"/>
<line x1="420" y1="170" x2="430" y2="170" style="stroke:#333;stroke-width:1;"/>
<line x1="298" y1="170" x2="420" y2="170" style="stroke:#333;stroke-width:1;"/>
<line x1="295.5" y1="170" x2="291.96446609407" y2="173.53553390593" style="stroke:#333;stroke-width:2;"/>
<line x1="295.5" y1="170" x2="291.96446609407" y2="166.46446609407" style="stroke:#333;stroke-width:2;"/>
<line x1="425" y1="170" x2="421.46446609407" y2="173.53553390593" style="stroke:#333;stroke-width:2;"/>
<line x1="425" y1="170" x2="421.46446609407" y2="166.46446609407" style="stroke:#333;stroke-width:2;"/>
<line x1="328" y1="290" x2="338" y2="290" style="stroke:#333;stroke-width:1;"/>
<line x1="420" y1="170" x2="430" y2="170" style="stroke:#333;stroke-width:1;"/>
<line x1="338" y1="290" x2="420" y2="170" style="stroke:#333;stroke-width:1;"/>
<line x1="335.5" y1="290" x2="331.96446609407" y2="293.53553390593" style="stroke:#333;stroke-width:2;"/>
<line x1="335.5" y1="290" x2="331.96446609407" y2="286.46446609407" style="stroke:#333;stroke-width:2;"/>
<line x1="425" y1="170" x2="421.46446609407" y2="173.53553390593" style="stroke:#333;stroke-width:2;"/>
<line x1="425" y1="170" x2="421.46446609407" y2="166.46446609407" style="stroke:#333;stroke-width:2;"/>
<rect width="138" height="20" x="430" y="140" style="fill:#007;stroke:black;"/>
<text width="138" height="20" x="435" y="154" style="fill:#fff;" font-family="Arial" font-size="16px"> product</text>
<rect width="138" height="20" x="430" y="160" style="fill:#aea;stroke:black;"/>
<text width="138" height="20" x="435" y="174" style="fill:black;" font-family="Arial" font-size="16px">id</text>
<rect width="138" height="20" x="430" y="180" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="194" style="fill:black;" font-family="Arial" font-size="16px">name</text>
<rect width="138" height="20" x="430" y="200" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="214" style="fill:black;" font-family="Arial" font-size="16px">seo_name</text>
<rect width="138" height="20" x="430" y="220" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="234" style="fill:black;" font-family="Arial" font-size="16px">slug</text>
<rect width="138" height="20" x="430" y="240" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="254" style="fill:black;" font-family="Arial" font-size="16px">reference</text>
<rect width="138" height="20" x="430" y="260" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="274" style="fill:black;" font-family="Arial" font-size="16px">short_description</text>
<rect width="138" height="20" x="430" y="280" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="294" style="fill:black;" font-family="Arial" font-size="16px">seo_description</text>
<rect width="138" height="20" x="430" y="300" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="314" style="fill:black;" font-family="Arial" font-size="16px">position</text>
<rect width="138" height="20" x="430" y="320" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="334" style="fill:black;" font-family="Arial" font-size="16px">weight</text>
<rect width="138" height="20" x="430" y="340" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="354" style="fill:black;" font-family="Arial" font-size="16px">created</text>
<rect width="138" height="20" x="430" y="360" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="374" style="fill:black;" font-family="Arial" font-size="16px">updated</text>
<rect width="138" height="20" x="430" y="380" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="394" style="fill:black;" font-family="Arial" font-size="16px">long_description</text>
<rect width="138" height="20" x="430" y="400" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="414" style="fill:black;" font-family="Arial" font-size="16px">details</text>
<rect width="138" height="20" x="430" y="420" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="434" style="fill:black;" font-family="Arial" font-size="16px">ingredients</text>
<rect width="138" height="20" x="430" y="440" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="454" style="fill:black;" font-family="Arial" font-size="16px">status</text>
<rect width="138" height="20" x="430" y="460" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="474" style="fill:black;" font-family="Arial" font-size="16px">tva</text>
<rect width="138" height="20" x="430" y="480" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="494" style="fill:black;" font-family="Arial" font-size="16px">label</text>
<rect width="138" height="20" x="430" y="500" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="435" y="514" style="fill:black;" font-family="Arial" font-size="16px">description_comp</text>
<rect width="138" height="20" x="150" y="140" style="fill:#007;stroke:black;"/>
<text width="138" height="20" x="155" y="154" style="fill:#fff;" font-family="Arial" font-size="16px"> product_categories</text>
<rect width="138" height="20" x="150" y="160" style="fill:#aea;stroke:black;"/>
<text width="138" height="20" x="155" y="174" style="fill:black;" font-family="Arial" font-size="16px">product_id</text>
<rect width="138" height="20" x="150" y="180" style="fill:#aea;stroke:black;"/>
<text width="138" height="20" x="155" y="194" style="fill:black;" font-family="Arial" font-size="16px">category_id</text>
<rect width="138" height="20" x="190" y="240" style="fill:#007;stroke:black;"/>
<text width="138" height="20" x="195" y="254" style="fill:#fff;" font-family="Arial" font-size="16px"> product_price</text>
<rect width="138" height="20" x="190" y="260" style="fill:#aea;stroke:black;"/>
<text width="138" height="20" x="195" y="274" style="fill:black;" font-family="Arial" font-size="16px">id</text>
<rect width="138" height="20" x="190" y="280" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="195" y="294" style="fill:black;" font-family="Arial" font-size="16px">product_id</text>
<rect width="138" height="20" x="190" y="300" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="195" y="314" style="fill:black;" font-family="Arial" font-size="16px">price</text>
<rect width="138" height="20" x="190" y="320" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="195" y="334" style="fill:black;" font-family="Arial" font-size="16px">context_id</text>
<rect width="138" height="20" x="190" y="340" style="fill:none;stroke:black;"/>
<text width="138" height="20" x="195" y="354" style="fill:black;" font-family="Arial" font-size="16px">price_ttc</text>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

14
cesi/nosql/Makefile Normal file
View File

@ -0,0 +1,14 @@
.PHONY: all slides
.ONESHELL:
all: pdf
slides:
for i in *.md; do php Slides/make.php "$$i" > "Slides/$${i##.md}.html"; done;
pdf: slides
cd Slides; for i in *.html; do prince -o "../$${i##.html}.pdf" "$$i"; done;
clean:
rm -f Slides/*.html
rm -f *.pdf

1
cesi/nosql/Slides/Images Symbolic link
View File

@ -0,0 +1 @@
../Images

View File

@ -0,0 +1,99 @@
<?php
if (empty($argv[1])) {
die("Usage: make.php SOURCE_MARKDOWN > DESTINATION_HTML\n");
}
$lines = file($argv[1]);
$out = '';
$in_list = $in_section = false;
$section_class = null;
function escape($str) {
$str = htmlspecialchars($str);
$str = str_replace('&lt;!--', '<sup>', $str);
$str = str_replace('--&gt;', '</sup>', $str);
$str = preg_replace_callback('/`(.*?)`/', function ($match) {
return '<code>' . $match[1] . '</code>';
}, $str);
$str = preg_replace_callback('/\[(.*?)\]\((.*?)\)/', function ($match) {
return sprintf('<a href="%s">%s</a>', $match[2], $match[1]);
}, $str);
return $str;
}
foreach ($lines as $line)
{
if (preg_match('/^---+(?:\s*=(\w+))?$/', $line, $match)) {
if ($in_section) {
if ($in_list) {
$out .= ' </ul>' . PHP_EOL;
$in_list = false;
}
$out .= '</section>' . PHP_EOL . PHP_EOL;
$in_section = false;
}
$section_class = !empty($match[1]) ? $match[1] : null;
continue;
}
if ('' === trim($line)) {
continue;
}
if (!$in_section) {
$out .= sprintf('<section class="%s">', $section_class) . PHP_EOL;
$in_section = true;
}
if (preg_match('/^(#+)\s+/', $line, $match)) {
$size = strlen($match[1]);
$title = trim(substr($line, strlen($match[0])));
$out .= sprintf(' <h%d>%s</h%d>', $size, escape($title), $size) . PHP_EOL;
}
elseif (preg_match('/^\*\s+/', $line)) {
if (!$in_list) {
$out .= ' <ul>' . PHP_EOL;
$in_list = true;
}
$out .= sprintf(' <li>%s</li>', escape(trim(substr($line, 2)))) . PHP_EOL;
}
else {
$out .= ' ' . trim($line) . PHP_EOL;
}
}
if ($in_section) {
if ($in_list) {
$out .= ' </ul>' . PHP_EOL;
$in_list = false;
}
$out .= '</section>' . PHP_EOL . PHP_EOL;
$in_section = false;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Slides</title>
<link rel="stylesheet" type="text/css" href="style.css" media="screen,presentation" />
<link rel="stylesheet" type="text/css" href="print.css" media="print" />
<script type="text/javascript" src="slides.js"></script>
</head>
<body>
<?=$out?>
</body>
</html>

View File

@ -0,0 +1,11 @@
body {
color: #000;
}
sup {
vertical-align: baseline;
font-size: 1.2em;
display: block;
font-style: italic;
color: #000;
}

148
cesi/nosql/Slides/slides.js Normal file
View File

@ -0,0 +1,148 @@
var slides;
var current_slide = 0;
var current_slide_items;
var current_item = 0;
var slide_window;
var clock;
var timer;
var timer_interval;
var slideCounter;
var planned_duration = 30;
function changeSlide(i, hide_items) {
if (current_slide + i < 0 || current_slide + i >= slides.length)
{
return true;
}
if (slide_window)
{
slide_window.window.changeSlide(i, hide_items);
}
slides[current_slide].classList.remove('current');
current_slide += i;
// Change URL
window.location.hash = "#" + current_slide;
// Get all items in a list
current_slide_items = slides[current_slide].getElementsByTagName('li');
current_item = 0;
for (var i = 0; i < current_slide_items.length; i++)
{
if (hide_items)
{
current_slide_items[i].classList.remove('shown');
}
else
{
current_slide_items[i].classList.add('shown');
}
}
slides[current_slide].classList.add('current');
slideCounter.innerHTML = current_slide + 1;
return true;
}
function progressSlide() {
if (current_item + 1 > current_slide_items.length || current_slide_items[current_item].classList.contains('shown'))
{
return changeSlide(1, true);
}
current_slide_items[current_item++].classList.add('shown');
if (slide_window)
{
slide_window.window.progressSlide();
}
return true;
}
function addTime() {
if (!clock)
{
clock = document.createElement('div');
clock.className = 'clock';
document.body.appendChild(clock);
}
function zerofill(v) {
return ("0" + v).slice(-2);
}
timer = 0;
window.clearInterval(timer_interval);
timer_interval = window.setInterval(function () {
timer += 1;
clock.style.width = Math.round(timer / (planned_duration * 60) * 100) + '%';
}, 1000);
}
function initSlides () {
slides = document.getElementsByTagName('section');
var current = window.location.hash.substr(1);
if (current > 0)
{
current_slide = parseInt(current, 10);
}
slides[current_slide].classList.add('current');
current_slide_items = slides[current_slide].getElementsByTagName('li');
slideCounter = document.createElement('div');
slideCounter.className = 'counter';
document.body.appendChild(slideCounter);
document.onkeydown = function (e) {
var prevent = false;
if (e.key == " ")
{
prevent = progressSlide();
}
else if (e.key == "ArrowRight" || e.key == "ArrowDown" || e.key == "PageDown")
{
prevent = changeSlide(1, false);
}
else if (e.key == "ArrowLeft" || e.key == "ArrowUp" || e.key == "PageUp")
{
prevent = changeSlide(-1, false);
}
else if (e.key == "Home")
{
prevent = changeSlide(-(current_slide), false);
}
else if (e.key == "End")
{
prevent = changeSlide(slides.length - 1, false);
}
else if (e.key == "o")
{
slide_window = window.open(document.location.href);
document.body.className = "notes";
prevent = true;
}
else if (e.key == "s")
{
addTime();
}
if (prevent)
{
e.preventDefault();
return false;
}
return true;
};
}
window.onload = initSlides;

158
cesi/nosql/Slides/style.css Normal file
View File

@ -0,0 +1,158 @@
html, body {
height: 100%;
}
body, section, h1, h2, h3, h4, h5, h6, p, ol, ul, li {
margin: 0;
padding: 0;
}
h1 {
font-size: 400%;
}
h2 {
font-size: 250%;
font-weight: normal;
}
h3 {
font-size: 200%;
font-weight: normal;
}
h1, h2, h3 {
margin-bottom: 1rem;
}
ul, ol {
margin-left: 2em;
font-size: 200%;
}
li {
margin: 1rem 0;
}
ul ul, ul ol, ol ul, ol ol {
font-size: 100%;
}
body {
background: #000;
font-family: "Eras Medium ITC", sans-serif;
overflow: hidden;
color: #fff;
font-size: 16pt;
}
section {
width: 90%;
opacity: 0;
transition: all .7s ease-in-out;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 5%;
background: #000;
display: flex;
flex-direction: column;
justify-content: space-around;
text-shadow: 0px 0px 10px #000;
visibility: hidden;
}
section.current {
transform: translate(0);
opacity: 1;
visibility: visible;
}
a {
color: inherit;
cursor: pointer;
text-decoration: none;
border-bottom: 2px dashed darkblue;
line-height: .8em;
display: inline-block;
transition: all .5s;
border-radius: .2em;
padding: 0 .1em;
}
a:hover {
border-color: #fff;
background: darkblue;
}
.companyLogo {
margin-top: 3rem;
}
section {
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,0.7) 70%), url("Images/logo.svg") no-repeat center bottom;
background-size: contain;
}
li {
transform: translateX(-500px);
opacity: 0;
transition: all .5s;
}
li.shown {
transform: translate(0);
opacity: 1;
}
sup {
display: none;
}
.notes sup {
display: block;
background: #fff;
padding: .2em;
color: #000;
}
.notes {
font-size: 12pt;
}
.clock {
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
font-size: 2em;
background: #333;
height: 5px;
width: 0px;
transition: width 1s linear;
}
.counter {
position: absolute;
right: 5px;
bottom: 5px;
font-size: 1.5em;
}
figure {
margin: 0;
border-radius: .5em;
padding: 1em;
background: rgba(255, 255, 255, 0.3);
text-align: center;
height: 70%;
}
figure img {
height: 95%;
background: #fff;
padding: .5em;
border-radius: .5em;
}

View File

@ -1,5 +0,0 @@
\begin{frame}
\begin{exampleblock}{}
Des questions ?
\end{exampleblock}
\end{frame}

View File

@ -1,11 +0,0 @@
\section{Licence}
Cette œuvre est mise à disposition sous licence \href{http://creativecommons.org/licenses/by-nc-sa/2.0/fr/}{\textsc{cc-by-sa-2.0}}
\begin{itemize}
\item Attribution
\item Partage dans les Mêmes Conditions 2.0
\item France
\end{itemize}
Pour voir une copie de cette licence, visitez
\href{http://creativecommons.org/licenses/by-sa/2.0/fr/}{http://creativecommons.org/licenses/by-sa/2.0/fr/}
ou écrivez à Creative Commons, 444 Castro Street, Suite 900,
Mountain View, California, 94041, USA.

View File

@ -1,18 +0,0 @@
\skbheading{Lannuaire de module Scribe}
Lannuaire du module Scribe est opéré à laide du logiciel OpenLDAP.
Les schémas mis en place sont définis selon les règles métiers de lÉducation nationale.
Les schémas mis en place sont les suivants :
\begin{itemize}
\item core.schema
\item cosine.schema
\item inetorgperson.schema
\item nis.schema
\item samba.schema
\item eole.schema
\item eoleshare.schema
\item radius.schema
\item ent.schema
\end{itemize}
Les schémas \emph{core.schema}, \emph{cosine.schema} et \emph{nis.schema} sont des schémas classiques pour les annuaires décrivant des personnes.
Les autres schémas, placés dans le sous-répertoire \emph{eole}, décrivent les objets nécessaires pour Samba (\emph{samba.schema}), les objets précisant les types de personnes (\emph{eole.schema}) et les partages (\emph{eoleshare.schema}), les attributs pour lutilisation de Radius (\emph{radius.schema}) et, enfin, les objets et attributs pour limplémentation du schéma directeur des espaces numériques de travail (\emph{ent.schema}).

View File

@ -1,33 +0,0 @@
\skbheading{Les classes dobjets métiers de lannuaire du module Scribe}
Les classe dobjets métiers de lannuaire du module Scribe sont celles décrites dans les schémas de plus haut niveau.
Ces classes dobjets décrivent des utilisateurs, des groupes dutilisateurs et des ressources comme les partages.
Plusieurs classes dobjets peuvent être utilisées conjointement pour préciser le type de la ressource décrite : les classes dobjects sont complémentaires et ne sont pas organisées de manière hiérarchique.
Les classes dont le nom débute par \emph{ENT} sont issues du schéma directeur des espaces numériques de travail.
Les classes dobjets susceptibles dêtre utilisées pour les personnes sont les suivantes :
\begin{itemize}
\item Eleves
\item administrateur
\item responsable
\item administratif
\item ENTPerson
\item ENTEleve
\item ENTAuxPersRelEleve
\item ENTAuxEnseignant
\item ENTAuxNonEnsServAc
\item ENTAuxNonEnsCollLoc
\item ENTAuxNonEnsEtab
\item ENTAuxPersExt
\item ENTAuxTuteurStage
\item ENTAuxRespEntrp
\item eolemail
\item autre
\end{itemize}
Les classes dobjets susceptibles dêtre utilisées pour les groupes sont les suivantes :
\begin{itemize}
\item eolegroupe
\item classe
\item ENTGroupe
\item ENTClasse
\end{itemize}

View File

@ -1,79 +0,0 @@
\skbheading{La fiche du personnel administratif dans lannuaire du module Scribe}
Le personnel administratif, dans lannuaire du module Scribe, est la conjonction de plusieurs classes dobjets :
\begin{itemize}
\item top
\item person
\item organizationalPerson
\item posixAccount
\item shadowAccount
\item inetOrgPerson
\item sambaSamAccount
\item administratif
\item ENTPerson
\item ENTAuxNonEnsEtab
\item radiusprofile
\end{itemize}
La partie métier est portée par les classes \emph{administratif}, \emph{ENTPerson} et \emph{ENTAuxNonEnsEtab}.
Les attributs susceptibles dêtre associés à un personnel administratif sont les suivants :
\begin{itemize}
\item les attributs issus de la classe administratif :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item typeadmin
\item codecivilite
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item dateNaissance
\item mailDir
\item mailHost
\item intid
\item FederationKey
\item Divcod
\item ManagedGroup
\item LastUpdate
\item mailAlternateAddress
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTPerson :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item ENTPersonLogin
\item ENTPersonJointure
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTPersonAutresPrenoms
\item ENTPersonNomPatro
\item ENTPersonSexe
\item ENTPersonCentresInteret
\item ENTPersonAdresse
\item ENTPersonCodePostal
\item ENTPersonVille
\item ENTPersonPays
\item ENTPersonAlias
\item ENTPersonStructRattach
\item ENTPersonFonctions
\item ENTPersonProfils
\item ENTPersonDateNaissance
\item personalTitle
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTAuxNonEnsEtab :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item aucun attribut obligatoire
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTAuxNonEnsEtabService
\end{itemize}
\end{itemize}
\end{itemize}

View File

@ -1,97 +0,0 @@
\skbheading{La fiche de lélève dans lannuaire du module Scribe}
Lélève, dans lannuaire du module Scribe, est la conjonction de plusieurs classes dobjets :
\begin{itemize}
\item top
\item person
\item organizationalPerson
\item posixAccount
\item shadowAccount
\item inetOrgPerson
\item sambaSamAccount
\item Eleves
\item ENTPerson
\item ENTEleve
\item radiusprofile
\end{itemize}
La partie métier est portée par les classes \emph{Eleves} et \emph{ENTEleve}.
Les attributs susceptibles dêtre associés à un élève sont les suivants :
\begin{itemize}
\item les attributs issus de la classe Eleves :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item givenName
\item codecivilite
\item mail
\item mailHost
\item userPassword
\item employeeNumber
\item dateNaissance
\item Meflcf
\item Divcod
\item uid
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item mailDir
\item telephoneNumber
\item mailForwardingAddress
\item mailAlternateAddress
\item textelibre
\item photo
\item diffusion
\item dermaj
\item Meflcm
\item Divcodmso
\item mailparent
\item FederationKey
\item Ine
\item postalAddress
\item rne
\item LastUpdate
\item intid
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTEleve :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item ENTEleveStatutEleve
\item ENTEleveMEF
\item ENTEleveLibelleMEF
\item ENTEleveNivFormation
\item ENTEleveFiliere
\item ENTEleveEnseignements
\item ENTEleveClasses
\item ENTEleveMajeur
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTEleveVilleNaissance
\item ENTEleveDeptNaissance
\item ENTElevePaysNaissance
\item ENTEleveParents
\item ENTEleveAutoriteParentale
\item ENTElevePersRelEleve1
\item ENTEleveQualitePersRelEleve1
\item ENTElevePersRelEleve2
\item ENTEleveQualitePersRelEleve2
\item ENTEleveBoursier
\item ENTEleveRegime
\item ENTEleveTransport
\item ENTEleveMEFRattach
\item ENTEleveNivFormationDiplome
\item ENTEleveSpecialite
\item ENTEleveGroupes
\item ENTEleveEnsRespStage
\item ENTEleveEnsTutStage
\item ENTEleveEntrTutStage
\item ENTEleveEntrAutres
\item ENTEleveDelegClasse
\item ENTEleveDelegAutres
\item ENTEleveMajeurAnticipe
\item ENTEleveStructRattachId
\end{itemize}
\end{itemize}
\end{itemize}

View File

@ -1,89 +0,0 @@
\skbheading{La fiche de lenseignant dans lannuaire du module Scribe}
Lenseignant, dans lannuaire du module Scribe, est la conjonction de plusieurs classes dobjets :
\begin{itemize}
\item top
\item person
\item organizationalPerson
\item posixAccount
\item shadowAccount
\item inetOrgPerson
\item sambaSamAccount
\item administrateur
\item ENTPerson
\item ENTAuxEnseignant
\item radiusprofile
\end{itemize}
La partie métier est portée par les classes \emph{administrateur}, \emph{ENTPerson} et \emph{ENTAuxEnseignant}.
Les attributs susceptibles dêtre associés à un enseignant sont les suivants :
\begin{itemize}
\item les attributs issus de la classe administrateur :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item typeadmin
\item codecivilite
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item dateNaissance
\item mailDir
\item mailHost
\item mailForwardingAddress
\item mailAlternateAddress
\item Meflcf
\item Divcod
\item FederationKey
\item ManagedGroup
\item LastUpdate
\item intid
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTPerson :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item ENTPersonLogin
\item ENTPersonJointure
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTPersonAutresPrenoms
\item ENTPersonNomPatro
\item ENTPersonSexe
\item ENTPersonCentresInteret
\item ENTPersonAdresse
\item ENTPersonCodePostal
\item ENTPersonVille
\item ENTPersonPays
\item ENTPersonAlias
\item ENTPersonStructRattach
\item ENTPersonFonctions
\item ENTPersonProfils
\item ENTPersonDateNaissance
\item personalTitle
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTAuxEnseignant :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item aucun attribut obligatoire
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTAuxsEnsMEF
\item ENTAuxEnsCategoDiscipline
\item ENTAuxEnsMatiereEnseignEtab
\item ENTAuxEnsClasses
\item ENTAuxEnsGroupes
\item ENTAuxEnsClassePrincipal
\item ENTAuxEnsRespStage
\item ENTAuxEnsTutStage
\end{itemize}
\end{itemize}
\end{itemize}

View File

@ -1,73 +0,0 @@
\skbheading{La fiche du responsable délève dans lannuaire du module Scribe}
Le responsable délève, dans lannuaire du module Scribe, est la conjonction de plusieurs classes dobjets :
\begin{itemize}
\item inetOrgPerson
\item responsable
\item ENTPerson
\item ENTAuxPersRelEleve
\end{itemize}
La partie métier est portée par les classes \emph{responsable}, \emph{ENTPerson} et \emph{ENTAuxPersRelEleve}.
Les attributs susceptibles dêtre associés à un responsable délève sont les suivants :
\begin{itemize}
\item les attributs issus de la classe responsable  :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item aucun attribut obligatoire
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item mailDir
\item mailHost
\item sambaLMPassword
\item sambaNTPassword
\item codecivilite
\item LastUpdate
\item gecos
\item eleve
\item intid
\item dateNaissance
\item mailPerso
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTPerson :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item ENTPersonLogin
\item ENTPersonJointure
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTPersonAutresPrenoms
\item ENTPersonNomPatro
\item ENTPersonSexe
\item ENTPersonCentresInteret
\item ENTPersonAdresse
\item ENTPersonCodePostal
\item ENTPersonVille
\item ENTPersonPays
\item ENTPersonAlias
\item ENTPersonStructRattach
\item ENTPersonFonctions
\item ENTPersonProfils
\item ENTPersonDateNaissance
\item personalTitle
\end{itemize}
\end{itemize}
\item les attributs issus de la classe ENTAuxPersRelEleve :
\begin{itemize}
\item dont les attributs obligatoires :
\begin{itemize}
\item ENTAuxPersRelEleveEleve
\end{itemize}
\item et les attributs optionnels :
\begin{itemize}
\item ENTAuxPersRelEleveRepresentant
\end{itemize}
\end{itemize}
\end{itemize}

View File

@ -1,2 +0,0 @@
\skbheading{schemas.tex}
fichier content/modules\_eole\_envole/scribe/annuaire/schemas.tex à éditer

View File

@ -1,29 +0,0 @@
\skbheading{Les outils du backend Scribe}
Le module Scribe amène des scripts pour la gestion des utilisateurs et des fonctions liées.
Ces fonctions utilisent les mêmes bibliothèques que lEAD2 pour la gestion des utilisateurs et groupes et sont donc une façon équivalente de manipuler lannuaire.
La liste des scripts disponibles est la suivante :
\begin{itemize}
\item ajout\_partage.py
\item change-classe.py
\item config-controle-vnc.py
\item creation-administratif.py
\item creation-eleve.py
\item creation-groupe.py
\item creation-prof.py
\item desinscription.py
\item droits\_partage.sh
\item droits\_user.py
\item inscription.py
\item mailsync.py
\item maj\_regle\_esu.sh
\item manage\_special\_shares.py
\item migre-domaine-messagerie.sh
\item modifie\_profil.py
\item regenalias.sh
\item regen\_maillist.py
\item suppression\_groupe.py
\item suppression\_utilisateur.py
\item zenity\_console.py
\end{itemize}

View File

@ -1,2 +0,0 @@
\skbheading{creation-administratif.tex}
fichier content/modules\_eole\_envole/scribe/backend/creation-administratif.tex à éditer

View File

@ -1,28 +0,0 @@
\skbheading{creation-eleve.py}
Le script \emph{creation-eleve.py} est utilisé pour créer un nouvel utilisateur du type élève dans lannuaire du module Scribe.
La fiche dun élève dans lannuaire du scribe contient obligatoirement :
\begin{itemize}
\item un identifiant de connexion ;
\item la classe de rattachement ;
\item un mot de passe ;
\item le prénom de lélève ;
\item le nom de famille de lélève ;
\item la date de naissance de lélève ;
\item le numéro de lélève ;
\item la civilité de lélève.
\end{itemize}
En complément, il est possible de renseigner les éléments suivants :
\begin{itemize}
\item le niveau de lélève ;
\item le type de domaine pour le courriel de lélève ;
\item un quota disque à assigner à lélève ;
\item le type de profil pour lutilisation dun poste client Windows ;
\item lactivation du shell pour permettre la connexion sur un poste client GNU/Linux.
\end{itemize}
\begin{description}
\item[emplacement] /usr/share/eole/backend
\item[aide] creation-eleve.py
\end{description}

View File

@ -1,2 +0,0 @@
\skbheading{creation-groupe.tex}
fichier content/modules\_eole\_envole/scribe/backend/creation-groupe.tex à éditer

View File

@ -1,2 +0,0 @@
\skbheading{creation-prof.tex}
fichier content/modules\_eole\_envole/scribe/backend/creation-prof.tex à éditer

View File

@ -1,9 +0,0 @@
\begin{frame}
\frametitle{Source Code Management}
\begin{description}
\item[SCM] Système de gestion du code source
\end{description}
\begin{exampleblock}{}
Outil permettant le développement de code informatique en conservant les étapes de création.
\end{exampleblock}
\end{frame}

View File

@ -1,11 +0,0 @@
\begin{frame}
\frametitle{Fonctionnalités d'un SCM}
\framesubtitle{Que peut faire un SCM pour vous ?}
Avec un SCM :
\begin{itemize}
\item produisez des bugs en toute quiétude
\item déterminez qui est responsable du bug bloquant
\item corrigez facilement ce bug
\item identifiez cet état du code comme stable
\end{itemize}
\end{frame}

View File

@ -1,47 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{Récapitulatif}
\tiny{
\begin{columns}
\begin{column}{.3\textwidth}
Faire le point :
\begin{itemize}
\item status
\item ls-files
\item diff
\item log
\item grep
\item cherry
\item show
\item bisect
\item blame
\end{itemize}
\end{column}
\begin{column}{.3\textwidth}
Modifier le contenu :
\begin{itemize}
\item checkout
\item pull
\item fetch
\item merge
\item rebase
\item add
\item reset
\item clean
\item commit
\item cherry-pick
\item revert
\item push
\item filter-branch
\end{itemize}
\end{column}
\begin{column}{.3\textwidth}
Organiser le développement :
\begin{itemize}
\item branch
\item tag
\end{itemize}
\end{column}
\end{columns}
}
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{add}
\begin{description}
\item[\commande{git add}] Ajouter le contenu d'un fichier à l'index.
\end{description}
\skbinput[from=fig]{apps/git_commande_add}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-u}] ajout des modifications des fichiers déjà connus de git
\item[\commande{-i}] ajout interactif
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,7 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{bisect}
\begin{description}
\item[\commande{git bisect start}] Démarrer une session de recherche du commit problématique par division binaire
\end{description}
\end{frame}

View File

@ -1,7 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{blame}
\begin{description}
\item[\commande{git blame}] Afficher l'auteur et la référence de la dernière modification pour chaque ligne d'un fichier
\end{description}
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{branch}
\begin{description}
\item[git branch] Gérer les branches
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--list}] Lister les branches (\commande{-a} les branches locales et distantes, \commande{-r} les branches distantes uniquement)
\item[\commande{-d}] Supprimer une branche
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{checkout}
\begin{description}
\item[\commande{git checkout}] Synchroniser le répertoire de travail avec une version
\end{description}
\skbinput[from=fig]{apps/git_commande_checkout}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-b}] Créer une nouvelle branche et déplacer HEAD dessus
\item[\commande{--ours --theirs}] Conserver des modifications explicitement
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,12 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{cherry-pick}
\begin{description}
\item[\commande{git cherry-pick}] Appliquer les changements introduits dans un commit donné
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--abort}] Interrompre le processus
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,7 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{cherry}
\begin{description}
\item[\commande{git cherry}] Trouver les commit qui ne sont pas encore appliqués dans le dépôt distant
\end{description}
\end{frame}

View File

@ -1,13 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{clean}
\begin{description}
\item[\commande{git clean}] Supprime les fichiers non suivis du répertoire de travail
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-xdf}] Combinaison pour supprimer du répertoire de travail les dossiers et fichiers non suivis
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{clone}
\begin{description}
\item[\commande{git clone <url du dépôt>}] Récupérer un dépôt git depuis une source distante
\end{description}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,15 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{commit}
\begin{description}
\item[\commande{git commit}] Créer un commit à partir du contenu de l'index
\end{description}
\skbinput[from=fig]{apps/git_commande_commit}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-a}] Court-circuiter l'index en intégrant au commit les modifications des fichiers suivis dans le répertoire de travail
\item[\commande{--amend}] Modifier le dernier commit
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{diff}
\begin{description}
\item[\commande{git diff}] Afficher la différence entre deux états (entre le répertoire de travail ou l'index et la branche par exemple)
\end{description}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,13 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{checkout}
\begin{description}
\item[git fetch] Mettre à jour la copie locale d'un dépôt distant
\end{description}
\skbinput[from=fig]{apps/git_commande_fetch}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[-all] Mettre à jour les copies locales de tous les dépôts distants configurés
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,13 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{filter-branch}
\begin{description}
\item[\commande{git filter-branch}] Exécuter une commande sur un ensemble de commit
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--tree-filter}] Modifier le contenu de l'arborescence pour chaque version du projet
\item[\commande{--env-filter}] Modifier la teneur des variables d'environnement pour chaque commit
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{grep}
\begin{description}
\item[\commande{git grep}] Rechercher dans chaque fichier d'un arbre quelconque
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--break}] Sépare les résultats pour une meilleure lisibilité
\item[\commande{--heading}] Donne le contexte du résultat
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{init}
\begin{description}
\item[\commande{git init}] Convertir le dossier courant en dépôt git
\end{description}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,15 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{log}
\begin{description}
\item[\commande{git log}] Afficher une liste de commit
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-L}] Retracer l'historique d'un morceau de code
\item[\commande{<c1>..<c2>}] Lister les commit accessibles depuis c2 mais pas c1
\item[\commande{<c1>...<2>}] Lister les commit accessibles depuis l'un ou l'autre mais pas des deux à la fois
\item[\commande{--not Ref}] Lister les commit qui ne sont pas accessibles depuis Ref
\end{description}
\end{exampleblock}
\end{frame}

View File

@ -1,7 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{ls-files}
\begin{description}
\item[\commande{git ls-files}] Afficher les informations sur les fichiers de l'index et du répertoire de travail.
\end{description}
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{merge}
\begin{description}
\item[\commande{git merge}] Intégrer les commit d'une branche à une autre
\end{description}
%\skbinput[from=fig]{apps/git_commande_merge}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--abort}] Pour faire machine arrière lors d'un merge manuel
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{pull}
\begin{description}
\item[\commande{git pull}] Synchroniser une branche locale avec la branche distante
\end{description}
\skbinput[from=fig]{apps/git_commande_pull}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--rebase}] Choisir la stratégie rebase pour incorporer les changements (équivalent à la succession des commandes \commande{fetch} et \commande{rebase})
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,15 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{push}
\begin{description}
\item[\commande{git push}] Synchroniser une branche distante avec une branche locale
\end{description}
\skbinput[from=fig]{apps/git_commande_push}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--tags}] Pousser les tags locaux sur le dépôt distant
\item[\commande{--all}] Pousser toutes les branches
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{rebase}
\begin{description}
\item[\commande{git rebase}] Rejouer les modifications après mise à jour de la branche
\end{description}
%\skbinput[from=fig]{apps/git_commande_rebase}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-i}] Réordonner les modifications manuellement
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{reset}
\begin{description}
\item[\commande{git reset}] Revenir à une version antérieure
\end{description}
%\skbinput[from=fig]{apps/git_commande_reset}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--hard}] Écraser le contenu du répertoire de travail et de l'index
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,14 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{revert}
\begin{description}
\item[\commande{git revert}] Créer le commit annulant un autre commit
\end{description}
%\skbinput[from=fig]{apps/git_commande_revert}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{--abort}] Interrompre le traitement
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{show}
\begin{description}
\item[\commande{git show}] Afficher la description d'un commit
\end{description}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{status}
\begin{description}
\item[\commande{git status}] Afficher le statut du répertoire de travail, et de l'index relativement à la branche
\end{description}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,15 +0,0 @@
\begin{frame}
\frametitle{Commandes git}
\framesubtitle{tag}
\begin{description}
\item[\commande{git tag}] Gérer les étiquettes attachées à un commit
\end{description}
\begin{exampleblock}{Options à retenir}
\begin{description}
\item[\commande{-l}] Lister les étiquettes (éventuellement correpondant à un motif)
\item[\commande{-a}] Annoter l'étiquette
\item[\commande{-s}] Signer l'étiquette
\end{description}
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,33 +0,0 @@
\begin{frame}
\frametitle{Ergonomie}
\framesubtitle{alias}
Les alias sont des raccourcis gérés pas git.
\commande{git config alias.<nom de l'alias> "<commande>"}
\begin{exampleblock}{Nature des commandes}
Les commandes peuvent aussi bien être des options et sous-commandes de git que des commandes externes accessibles au shell.
\end{exampleblock}
\end{frame}
\begin{frame}[fragile]
\frametitle {Ergonomie}
\framesubtitle{Exemples d'alias}
\begin{minted}[fontsize=\tiny]{ini}
[alias]
co = checkout
st = status
fe = fetch
lo = log --oneline
re = reset --hard HEAD~1
br = branch
mnf = merge --no-ff
sw = checkout @{-1}
lu = log ..@{upstream}
luo = log --oneline ..@{upstream}
ul=log @{upstream}..HEAD
ulo=log --oneline @{upstream}..HEAD
cslt = !git describe --long --first-parent | awk -F'/' '{print $NF}' | awk -F'-' '{print $(NF-1)}'
clf = !git lo --no-merges $(git lo -1 --pretty=format:"%h" debian/changelog)..
\end{minted}
\end{frame}

View File

@ -1,10 +0,0 @@
\begin{frame}
\frametitle{Ergonomie}
\framesubtitle{Interface}
\begin{itemize}
\item \commande{git config --global core.editor "vim"}
\item \commande{git config --global core.pager "less"}
\item \commande{git config --global color.ui auto}
\end{itemize}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,47 +0,0 @@
\begin{frame}
\frametitle{Ergonomie}
\framesubtitle{Hooks}
Les hooks sont des actions déclenchées par des évènements concernant le dépôt git.
\begin{exampleblock}{}
Les hooks sont des scripts exécutables (pas de langage imposé) posés dans le dossier .git/hooks.
\end{exampleblock}
\end{frame}
\begin{frame}
\frametitle{Ergonomie}
\framesubtitle{Hooks pour le client}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item pre-commit
\item prepare-commit-msg
\item commit-msg
\item post-commit
\item applypatch-msg
\item preapply-patch
\item postapply-patch
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item pre-rebase
\item post-rewrite
\item post-checkout
\item post-merge
\item pre-push
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}
\frametitle{Ergonomie}
\framesubtitle{Hooks pour le serveur}
\begin{itemize}
\item pre-receive
\item update
\item post-receive
\end{itemize}
\end{frame}

View File

@ -1,8 +0,0 @@
\begin{frame}
\frametitle{Configurer git}
\framesubtitle{Une configuration souple}
\begin{itemize}
\item configuration globale
\item configuration par dépôt
\end{itemize}
\end{frame}

View File

@ -1,16 +0,0 @@
\begin{frame}[fragile]
\frametitle{Ergonomie}
\framesubtitle{bash}
\begin{minted}{bash}
source ~/.git-prompt.sh
GIT_PS1_SHOWDIRTYSTATE=1
GIT_PS1_SHOWSTASHSTATE=1
GIT_PS1_SHOWUNTRACKEDFILES=1
GIT_PS1_SHOWUPSTREAM="auto"
PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
\end{minted}
\begin{exampleblock}{git-prompt}
git-prompt.sh est un script définissant la fonction \_\_git\_ps1 permettant d'afficher des informations pertinentes sur l'état du dépôt git dans l'invite de commande.
\end{exampleblock}
% contenu (pas trop long) de la diapositive
\end{frame}

View File

@ -1,9 +0,0 @@
\begin{frame}
\frametitle{Configurer git}
\framesubtitle{Identifier l'utilisateur}
git associe à chaque commit des informations sur la personne ayant commité et sur la personne ayant mergé le commit.
\begin{itemize}
\item \commande{git config --global user.name "<nom d'utilisateur>"}
\item \commande{git config --global user.email "<courriel>"}
\end{itemize}
\end{frame}

View File

@ -1,6 +0,0 @@
\begin{frame}
\frametitle{Décentralisé}
\begin{description}
\item[DVCS] Système de gestion de version décentralisé
\end{description}
\end{frame}

View File

@ -1,12 +0,0 @@
\begin{frame}
\frametitle{Les trois états des fichiers}
\begin{itemize}
\item non-suivi (avec la variante ignoré)
\item suivi :
\begin{itemize}
\item non modifié (par rapport au dernier état archivé)
\item modifié (par rapport au dernier état archivé)
\item sélectionné pour être archivé
\end{itemize}
\end{itemize}
\end{frame}

Some files were not shown because too many files have changed in this diff Show More