CESI - Exo Microbloggr Solution - Création de statuts fonctionnelle

This commit is contained in:
wpetit 2018-11-28 16:56:54 +01:00
parent eaa659f3c6
commit a970852f3b
9 changed files with 210 additions and 6 deletions

View File

@ -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

View File

@ -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"
}
}

View File

@ -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'));

View File

@ -1,13 +1,28 @@
<html>
<body>
<div class="layout">
<nav class="main">
<h1 class="brand">MicroBloggr</div>
</nav>
<div class="content">
Bienvenue <%= user.username; %> !
<a href="/logout">Se déconnecter</a>
</div>
<form action="." method="post">
<label>Nouveau statut</label>
<input name="status" type="text" />
<button type="submit">Envoyer</button>
</form>
<ul class="statuses">
<% statuses.forEach(s => { %>
<li><%= s.createdAt %> - <%= s.text %></li>
<% }); %>
</ul>
</div>
</body>
</html>

View File

@ -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"]

View File

@ -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"
}
}

View File

@ -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'));