diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/docker-compose.yml b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/docker-compose.yml index 10ee182..a4521a7 100644 --- a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/docker-compose.yml +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/docker-compose.yml @@ -28,6 +28,7 @@ services: SESSION_SECRET: "absolutly_not_secret" links: - redis + - statuses volumes: - ./services/home_page/src:/app/src:ro @@ -71,6 +72,17 @@ services: - https_proxy=${HTTP_PROXY} volumes: - ./services/users/src:/app/src:ro + + statuses: + build: + context: services/statuses + args: + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - http_proxy=${HTTP_PROXY} + - https_proxy=${HTTP_PROXY} + volumes: + - ./services/statuses/src:/app/src:ro redis: image: redis:5.0-alpine diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/package.json b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/package.json index 6b3533a..116ac33 100644 --- a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/package.json +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/package.json @@ -15,6 +15,7 @@ "connect-redis": "^3.4.0", "morgan": "^1.9.1", "request": "^2.83.0", - "request-promise-native": "^1.0.5" + "request-promise-native": "^1.0.5", + "body-parser": "^1.18.2" } } diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/server.js b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/server.js index f8f1bfe..2d7d810 100644 --- a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/server.js +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/server.js @@ -3,6 +3,8 @@ const session = require('express-session'); var RedisStore = require('connect-redis')(session); const app = express(); const morgan = require('morgan'); +const request = require('request-promise-native'); +const bodyParser = require('body-parser'); app.set('view engine', 'ejs'); app.set('views', __dirname + '/views'); @@ -16,17 +18,38 @@ app.use(session({ saveUninitialized: true, })); +// On utilise le module "body-parser" +// pour faciliter la désérialisation des données +// du formulaire +app.use(bodyParser.urlencoded({extended: false})); + // GET / // Retourne la page d'accueil de MicroBloggr ou redirige vers la // page de login si l'utilisateur n'est pas identifié app.get('/', (req, res) => { - - const sess = req.session; - // On vérifie si un utilisateur a été associé à la session HTTP if (req.session.user) { - // Si oui, on affichage la page d'accueil - return res.render('index', { user: req.session.user }); + const user = req.session.user; + + // On récupère la liste des statuts depuis le microservice "statuses" + fetchUserStatuses(user.username) + .then(result => { + + // Si le microservice "statuses" n'a pas pu nous renvoyer + // la liste des statuts + if (!result.ok) { + return res.status(500).send(result.error); + } + + // Si oui, on affichage la page d'accueil + return res.render('index', { user: req.session.user, statuses: result.statuses }); + + + }) + .catch(err => { + console.error(err); + return res.status(500).send(err.stack); + }); } else { // Si non, on redirige l'utilisateur vers la page de login return res.redirect(302, '/login'); @@ -34,4 +57,55 @@ app.get('/', (req, res) => { }); +// POST / +// Gère l'envoi du formulaire de création d'un nouveau statut +app.post('/', (req, res) => { + + // On vérifie si un utilisateur a été associé à la session HTTP + if (!req.session.user) { + return res.status(302).redirect("/login"); + } + + const user = req.session.user; + const statusText = req.body.status; + + addUserStatus(user.username, statusText) + .then(result => { + if (!result.ok) { + return res.status(500).send(result.error); + } + // On redirige vers la page d'accueil + // pour afficher le nouveau statut + return res.status(303).redirect("/"); + }) + .catch(err => { + console.error(err); + return res.status(500).send(err.stack); + }); + +}); + + +// Récupère la liste des statuts d'un utilisateur donné +function fetchUserStatuses(username) { + return request({ + uri: `http://statuses:8080/statuses/${username}`, + method: 'GET', + json: true + }) + ; +} + +// Récupère la liste des statuts d'un utilisateur donné +function addUserStatus(username, text) { + return request({ + uri: `http://statuses:8080/statuses`, + method: 'POST', + body: { username, text }, + json: true + }) + ; +} + + app.listen(8080, () => console.log('listening on port 8080')); diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/views/index.ejs b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/views/index.ejs index 457091f..a964dde 100644 --- a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/views/index.ejs +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/home_page/src/views/index.ejs @@ -1,13 +1,28 @@
+
+
Bienvenue <%= user.username; %> ! Se déconnecter
+ +
+ + + +
+ + + diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.dockerignore b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.dockerignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.dockerignore @@ -0,0 +1 @@ +/node_modules diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.gitignore b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.gitignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/.gitignore @@ -0,0 +1 @@ +/node_modules diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/Dockerfile b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/Dockerfile new file mode 100644 index 0000000..f76262d --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:3.7 + +RUN apk add --no-cache nodejs + +COPY ./ /app +WORKDIR /app + +RUN npm install --production +RUN npm install -g nodemon + +CMD ["nodemon", "src/server.js"] diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/package.json b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/package.json new file mode 100644 index 0000000..1e3673e --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/package.json @@ -0,0 +1,16 @@ +{ + "name": "statuses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.18.2", + "express": "^4.16.2", + "morgan": "^1.9.1" + } +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/src/server.js b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/src/server.js new file mode 100644 index 0000000..e50a92d --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_microbloggr_solution/services/statuses/src/server.js @@ -0,0 +1,73 @@ +const express = require('express'); +const app = express(); +const bodyParser = require('body-parser'); +const morgan = require('morgan'); + +// Pour cette démo, les statuts sont uniquement conservés en +// mémoire +const statuses = {}; + +app.use(morgan('combined')); + +// On utilise le module "body-parser" +// pour faciliter la désérialisation des données +// des appels à l'API +app.use(bodyParser.json()); + +// POST /statuses +// Ajoute un nouveau statut pour l'utilisateur donné +app.post('/statuses', (req, res) => { + + const newStatus = req.body; + + if(!newStatus.username || !newStatus.text) { + return res.status(200).send({ + ok: false, + error: "Invalid status.", + }); + } + + if(newStatus.text.length > 200) { + return res.status(200).send({ + ok: false, + error: "Status text too long.", + }); + } + + const userStatuses = statuses[newStatus.username] || []; + userStatuses.unshift({ + text: newStatus.text, + createdAt: new Date(), + }); + statuses[newStatus.username] = userStatuses; + + return res.status(200).send({ + ok: true, + }); + +}); + +// GET /statuses/:username +// Retourne les status de l'utilisateur donné +app.get('/statuses/:username', (req, res) => { + + const username = req.params.username; + + if(!username) { + return res.status(200).send({ + ok: false, + error: "Invalid username.", + }); + } + + const userStatuses = statuses[username] || []; + + return res.status(200).send({ + ok: true, + statuses: userStatuses, + }); + +}); + +app.listen(8080, () => console.log('listening on port 8080')); +