Ceci est la documentation haut-niveau de sigma, décrivant le projet du point de vue développeur de façon globale, sans trop rentrer dans le détail du code. 

## Pourquoi Sigma ?

### Deux constats

Frankiz est obsolète et plus maintenable. Le jour où Frankiz tombe, il emportera le BR, et peut-être tout le platâl, avec lui. Il est plus que temps de développer un outil nouveau, documenté, clair, moderne et qu'il sera beaucoup plus facile de faire évoluer. En outre, la centralisation des pouvoirs des admins et l'interface vieillie font qu'il s'agit d'un service largement sous-utilisé.

L'organisation actuelle des associations à l'école n'est également pas satisfaisante ; tout passe par Facebook, qui trie des données dans le dos de la plupart des utilisateurs, fait remonter les messages aléatoirement et complexifie beaucoup la constitution d'un emploi du temps compréhensible pour tous les acteurs. Ne jamais oublier la maxime du grand maître : « Facebook est centré sur l’individu, Sigma est centré sur le groupe. » – Quentin Gendre, X2015. 

En revanche, le LDAP généré par Frankiz tous les quarts d'heure est indispensable au fonctionnement de nombreux sites binets. En conséquence il n'est pas envisageable sans passer beaucoup de temps à modifier tous ces sites de laisser tomber le LDAP Frankiz.

Ainsi, l'idée est de conserver le LDAP Frankiz mais pas sa BDD, inutilisable car non documentée, et utiliser exclusivement le LDAP Frankiz pour la gestion des utilisateurs.

### L'idée

Il s'agit de reprendre un nouveau Frankiz plus moderne et clairement documenté, mais pas seulement. Plusieurs fonctionnalités intéressantes sont envisageables :
- fil d'actualité avec filtre personnalisable
- gestion des inscriptions (notamment avec nombre de places limité)
- inscription par trigramme
- minimodules ou greffons à étudier
- intégration des événements d'autres écoles

## Structure du dossier

La structure générale du projet est détaillée ci-dessous ; pas d'inquiétude, la plupart des fichiers .js sont aussi extensivement documentés dans la doc générée par JSDoc (ou plus bas si vous lisez depuis JSDoc).

Divers fichiers de configuration à la racine du projet :
- `.eslintignore` : dit à eslint de ne pas linter ces fichiers
- `.eslintrc.json` : config pour eslint. Le plus susceptible d'être modifié est le champ rules. env spécifie l'environnement, et donc quelle syntaxe est utilisée
- `.gitignore` : dit à git de ne pas track ces fichiers
- `package-lock.json` : spécifie à npm les dépendances du projet avec leur version précise. équivalent de pip freeze pour flask/django
- `package.json` : spécifie à npm les dépendances du projet, mais aussi l'auteur, la license, le repo git... bref tout ce qui peut être intéressant pour [npm](https://www.npmjs.com/package/shitpost). Spécifie aussi les scripts à utiliser quand on utilise la commande `npm run (blablabla)`
- `configfile_doc.json` : config pour JSDoc, l'outil de génération automatique de documentation
- autres fichiers relatifs à des modules particuliers ou à la gestion de paquets
  - tsconfig.json : pour typescript
  - webpack.config.js : pour Webpack
  - .gitlab-ci.yml : pour le CI (continuous integration) de gitlab
  - .gitattributes : ??
  - .dockerignore : pour Docker
  - Dockerfile : pour déployer dans un conteneur Docker
- `config.json` : données "sensibles" spécifique au projet à priori non partageable (adresse du LDAP, mots de passe)

Les dossiers à la racine du projet :
- [`assets/`](./assets) : ressources. on y met les fichiers statiques, e.g. les images
  - images et divers (dont l'essentielle favicon)
- [`build/`](./build) : output de webpack
  - bundle.js est un monstrueux fichier généré par webpack, qui compile et optimise tout notre code de `src/`
- [`db/`](./db) : fichiers utilisés par Knex.js, le traducteur javascript/SQL
  - `knexfile.js` : fichier de config de la commande `knex <...>` *en CLI*
  - `knex_router.js` : exporte l'objet `knex` *utilisé dans le code javascript*. En fait, ne fait que charger la config déjà définie dans `knexfile.js`
  - [`migrations/`](./db/migrations) stocke l'ensemble des migrations Knex
  - [`seeds/`](./db/seeds) : stocke les seeds Knex (scripts de génération de contenu de la BDD)
- [`doc/`](./doc) : documentation bas-niveau, générée par JSDoc à partir des commentaires dans le code-même. Ensemble de pages html et leurs fichiers associés. *index.html* permet de naviguer sereinement sur toute la doc JSDoc
- [`node_modules/`](./node_modules) : les dépendances du projet, téléchargées automatiquement par npm grâce à leur liste dans `package.json`
- [`src/`](./src) : code source de l'application Node.js du backend
  - [`adminview/`](./src/adminview) : code source d'une "mini-application" gérant l'interface administrateur du backend, utilisée lorsque le backend reçoit des requêtes HTTP GET
    - `css/` : les stylesheets CSS utilisés par adminview
    - `views/` : les templates HTML grâce auxquels sont générées les pages renvoyées par adminview
  - [`graphql/`](./src/graphql) : le coeur du backend, c'est là qu'on définit comment répondre à des requêtes GraphQL
    - [`typeDefs/`](./src/graphql/typeDefs) : la définition du schéma GraphQL
    - `connectors/` : (@akka vodol tu peux expliquer ici ?)
    - `resolvers/` : (@akka vodol tu peux expliquer ici ?)
  - [`ldap`](./src/ldap) : gestion des requêtes au LDAP. Fournit une couche d'abstraction permettant aux resolvers GraphQL de ne pas se soucier des spécifités et de la complexité syntaxique des requêtes LDAP

La structure générale du projet peut être résumée comme suit :

![struct_projet](./struct.png "Structure du projet")

## Bases de données

Sigma s'appuie sur deux bases de données (toutes deux hébergées par le BR) :
- Le LDAP frankiz, qui contient identifiants, mots de passe, et toutes les informations sur les utilisateurs et groupes spécifiques X.
  - Plus de détail dans {@tutorial memo_ldap}
- La BDD propre à Sigma, en [PostgreSQL](https://www.postgresql.fr/), contient les groupes et leurs niveaux de visibilité mais peu d'information sur les utilisateurs (seulement son école).
  - Les requêtes à cette BDD sont gérées par [Knex.js](http://knexjs.org), qui permet de construire facilement des requêtes PostgreSQL (voir {@tutorial memo_postgresql} et {@tutorial memo_knexjs}).

Cette structure peut sembler lourde et redondante mais s'explique par plusieurs raisons :
- Volonté de pouvoir intégrer d'autres écoles simplement
  - Rajouter leurs groupes sur la BDD sigma
  - Ne pas les obliger à rejoindre notre LDAP avec notre structure
- Garder et continuer à utiliser le LDAP frankiz, car il est utilisé par beaucoup d'autres sites X
- Enjeu de sécurité
  - La BDD de sigma est publique et ne comporte rien de compromettant
  - Le LDAP contient des informations plus sensibles (c'est là que toutes les données sur les utilisateurs sont stockées)

### Utiliser la BDD sigma avec *Knex.js*
cf. {@tutorial memo_knexjs} pour plus de détails sur la techno.

Le knexfile.js et le knex_router.js sont dans `./db`. La localisation des dossiers [seeds](./db/seeds) et [migrations](./db/migrations), est spécifiée dans le knexfile.js, en l'occurrence également dans `./db`.

### Interagir directement avec la BDD sigma en *PostgreSQL*
cf. {@tutorial memo_postgresql} pour plus de détails sur la techno.

Pour accéder à la "vraie" BDD, sur roued (le serveur qui héberge sigma), il faut

- se connecter dessus en `ssh roued`
- faire un `sudo -s postgres` pour se faire passer pour l'utilisateur Unix postgres
- se connecter à la BDD via la commande `psql`
- faire les requêtes en SQL (version PostgreSQL) par l'interface ainsi `psql`

### Fonctions LDAP
cf. {@tutorial memo_ldap} pour plus de détails sur la techno.

L'idée est de fournir une API minimaliste pour le LDAP de façon à faciliter l'intégration de nouvelles écoles qui privilégierait un autre mode d'authentification - et ce qui permet aussi de leur laisser le contrôle sur leurs propres données.

#### Ne pas se tromper de LDAP...
Il y a deux LDAP à l'X : le LDAP de la DSI et le LDAP de Frankiz (du BR). 

- Le premier, utilisé pour l'authentification sur les services de l'Ecole (mail polytechnique.edu, le Moodle, Synapses...) ne concerne pas du tout sigma.
- C'est le second qu'on utilise, et "le LDAP" dans le contexte de sigma désignera, sauf indication contraire, le LDAP frankiz.

Une documentation vieillissante est disponible sur le [`wikix`](https://wikibr.binets.fr/Admin:LDAP) pour en savoir plus sur ce sujet.

## Gestion des utilisateurs

### Authentification

On utilise [passportjs](https://www.npmjs.com/package/passport) pour l'authentification. La [stratégie "ldapauth"](https://www.npmjs.com/package/passport-ldapauth) de passport permet de s'authentifier contre le LDAP frankiz. 

Lorsqu'une authentification est réussie, on crée une session et on l'associe à un _cookie d'authentification_ qu'on donne à l'utilisateur. Ainsi, les prochaines requêtes venant du même utilisateur seront authentifiées par le cookie, sans besoin de refaire l'authentification contre LDAP. 

La gestion des sessions et de la distribution de cookies est gérée par passport, et est décrite dans `app.ts`.

![auth](./auth.png "Processus d'authentification proposé")

### Vérification des droits

Il semble intéressant de proposer pour Sigma une structure plus souple que Frankiz, avec plusieurs niveaux dans un groupe :
- Admin, qui gère le groupe
- Speaker, qui parle au nom du groupe
- Member, qui est notifié et qui apparait comme membre
- Follower, qui est aussi notifié parfois

L'idée est aussi d'explorer ce qu'on peut faire pour opérer une cascade de privilèges et éviter les super-admins de Frankiz. Dans cette logique, on peut définir un graphe évolutif qui définit les interactions entre groupes et établit des relations de visibilités, d'appartenance et d'administrations. Cela permettrait de définir de façon plus intelligente les droits d'un utilisateur de façon presque graphique, voir :

![auth](./graphDroits.png "Graphe de droits")

## Panneau d'administration ("adminview")

D'habitude, toutes les requêtes arrivent en HTTP POST : les requêtes GraphQL, et les requêtes de connexion (à /login).
Lorsque le site reçoit des requêtes HTTP GET, on l'interprète comme étant une requête venant du navigateur d'une personne qui souhaite se connecter directement au serveur backend, donc probablement un admin.
L'application principale du backend fait alors appel à une "sous-application", adminview (ceci est possible grâce à Express et son objet express.router).

Les identifiants à utiliser sont ceux de Frankiz. L'authentification se fait par le LDAP Frankiz via passport.
Le hruid (i.e. prenom.nom) de l'utilisateur doit de plus être sur une whitelist des hruid autorisés. Pour l'instant cette whitelist est hardcodée dans le code source.

Par cette interface admin, on a accès :
- à une API REST fait-maison (peut-être encore à débugger), permettant de consulter la base de donnée interne à Sigma, via des requêtes construites avec Knex. `/adminview/db/:table?`
- à GraphQL Voyager, un package qui permet d'afficher une représentation sous forme de graphe du schéma GraphQL. `/adminview/voyager`
- à un lien vers GraphQL Playground, qui permet d'écrire ses propres requêtes GraphQL et de les exécuter. Il est en fait accessible sans authentification du tout, au path `/graphql`. GraphQL Playground est désactivé en production.

## Notes sur javascript

La syntaxe adoptée est JavaScript ES6, un standard moderne (2015) de JavaScript. Node ne comprend pas ES6, mais ES5 (un tout petit peu plus que ES5 en fait).

On utilise Webpack pour transpiler les fichiers source [`src/`](./src/) en un [`bundle.js`](./build/bundle.js) qui, lui, suit la syntaxe ES5 compatible avec Node. 
Pour lancer une transpilation, `npm run build` (mode production) ou `npm run dev` (mode développement).
La commande `webpack` est configurable dans le fichier `webpack.config.js`.

### `import` vs `require`
Le standard moderne permet d'importer des dépendances en utilisant le mot-clé `import`, ce que le serveur Node.js ne comprend pas puisque la version 8 de Node ne comprend que le standard ES5 (2009), qui gère les imports avec `require()`.

### `async`/`await`
Il s'agit aussi de mots-clés spécifiques au standard moderne ES6.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

## Outils de développement

Le détail des outils les plus techniques est dans {@tutorial memos}.

### ESLint

On utilise ESLint pour standardiser le style du code. 
Il est ~~préférable~~ nécessaire de l'installer **globalement** avec `npm install -g eslint`.

Lors d'une validation ESLint, un ensemble de règles de style sont appliquées, elles sont configurables dans le fichier `.eslintrc.json`. Par exemple, actuellement, la config ESLint impose d'utiliser quatre espaces pour les indentations et d'utiliser des points-virgule en fin de ligne. 
Les options de configuration sont bien expliquées dans la [doc dédiée](https://eslint.org/docs/rules/).

 Pour faire valider les fichiers source par ESLint, utiliser `npm run lint` (raccourci pour `eslint --ext .js --ext .ts src/ `). L'option `--fix` permet de corriger les fichiers : `npm run lint -- --fix`.
Les différentes façon d'exécuter une validation sont bien expliquées dans la [doc dédiée](https://eslint.org/docs/user-guide/command-line-interface).

Sinon, si vous utilisez Atom ou Visual Studio Code pour éditer votre code, il existe des plugins qui font tourner ESLint _en live_ sur le code et vous préviennent quand il y a une faute de style.

### nodemon

On utilise [`nodemon`](https://nodemon.io/) pour servir l'application.

> "Just use nodemon instead of node to run your code, and now your process will automatically restart when your code changes"

Dans le script `npm run start` on a mis l'option `--watch dist` pour spécifier qu'il n'est nécessaire de reload que lorsque le dist/ est modifié.

> By default nodemon monitors the current working directory. If you want to take control of that option, use the --watch option to choose specific paths.

Rq: comme indiqué dans le README.md, en mode developpement, il est intéressant de combiner le hot-recompile de `webpack --watch` et le hot-reload de `nodemon` : lancer
```bash
npm run watch
```
dans une console, et
```bash
npm run start
```
dans une autre pour avoir un environnement de développement agréable.

### VM

Le BR dispose de plusieurs Virtual Machines (VM) pour faire tourner les outils en développement. Pour l'instant, Sigma est sur roued (129.104.201.10).

## Contact

Le BR 2016, plus particulièrement Wilson Jallet, Guillaume Wang, Quentin Chevalier et Anatole Romon

Le BR 2017, plus particulièrement Olivér Facklam, Grégoire Grzeckowicz et Hadrien Renaud