Merge branch 'frontend_test_general' into 'master'

Frontend test general

See merge request groupe100idee/chatless!1
This commit is contained in:
Yûki Vachot 2021-05-29 01:32:39 +02:00
commit 30e7faffbc
29 changed files with 283 additions and 559 deletions

View file

@ -21,8 +21,8 @@ module.exports.setSessionCookie = setSessionCookie;
// de session. Si ce dernier n'existe pas, on renvoie // de session. Si ce dernier n'existe pas, on renvoie
// l'ID -1. // l'ID -1.
function getUserId(session) { function getUserId(session) {
if (typeof session.userId === 'undefined') return -1; if (typeof session.username === 'undefined') return -1;
return session.userId; return session.username;
} }
module.exports.getUserId = getUserId; module.exports.getUserId = getUserId;

View file

@ -1,7 +1,7 @@
const config = { const config = {
// paramètres de connexion à la base de données // paramètres de connexion à la base de données
mongodbDatabase: 'chat', mongodbDatabase: 'chat',
mongodbHost: 'mongodb://mongodb-authentication:27017/', mongodbHost: 'mongodb://127.0.0.1:27017/',
charset: 'utf8', charset: 'utf8',
mongodbLogin: '', mongodbLogin: '',
mongodbPassword: '', mongodbPassword: '',

View file

@ -20,6 +20,7 @@ mongoConnect.connectToServer(function( err, client ) {
const register = require('./register'); const register = require('./register');
const queries = require('./mongodbQueries'); const queries = require('./mongodbQueries');
queries.register('Server','admin');
queries.register('khai','test'); queries.register('khai','test');
queries.register('wilfried','test'); queries.register('wilfried','test');
queries.register('yuki','test'); queries.register('yuki','test');

View file

@ -1,11 +1,12 @@
const sessionJWT = require ('jsonwebtoken'); const sessionJWT = require ('jsonwebtoken');
const fs = require ('fs'); const fs = require ('fs');
// renvoie un nouveau token JWT // renvoie un nouveau token JWT
function createSessionJWT (userId) { function createSessionJWT (username) {
// ci-dessous, on met en place le cookie de session JWT : // ci-dessous, on met en place le cookie de session JWT :
// 1/ on recupere notre clef privee // 1/ on recupere notre clef privee
const RSA_PRIVATE_KEY = fs.readFileSync('./keys/jwtRS256.key'); const RSA_PRIVATE_KEY = fs.readFileSync('../keys/jwtRS256.key');
// 2/ on signe un token JWT. Le payload est l'identifiant de // 2/ on signe un token JWT. Le payload est l'identifiant de
// l'utilisateur ainsi qu'une date d'expiration à mi-parcours : // l'utilisateur ainsi qu'une date d'expiration à mi-parcours :
@ -18,7 +19,7 @@ function createSessionJWT (userId) {
// session. // session.
const jwtToken = sessionJWT.sign( const jwtToken = sessionJWT.sign(
{ {
userId: userId, username: username,
midExp: Math.floor(Date.now() / 1000) + 1800 // validité: 30mn midExp: Math.floor(Date.now() / 1000) + 1800 // validité: 30mn
}, },
RSA_PRIVATE_KEY, RSA_PRIVATE_KEY,
@ -40,14 +41,15 @@ function createSessionCookie(req, res, payload) {
// midExp, alors le cookie est encore valide et on peut le renvoyer. Sinon, // midExp, alors le cookie est encore valide et on peut le renvoyer. Sinon,
// on doit recalculer un nouveau cookie. // on doit recalculer un nouveau cookie.
let jwtToken = ''; let jwtToken = '';
if ((typeof payload.userId !== 'undefined') && if ((typeof payload.username !== 'undefined') &&
(typeof payload.midExp !== 'undefined') && (typeof payload.midExp !== 'undefined') &&
(Math.floor(Date.now() / 1000) <= payload.midExp)) { (Math.floor(Date.now() / 1000) <= payload.midExp)) {
jwtToken = req.cookies.SESSIONID; jwtToken = req.headers.cookie;
} }
else { else {
// on crée un nouveau cookie // on crée
jwtToken = createSessionJWT(payload.userId); // un nouveau cookie
jwtToken = createSessionJWT(payload.username);
} }
// on renvoie le cookie au client // on renvoie le cookie au client
@ -63,14 +65,13 @@ module.exports.createSessionCookie = createSessionCookie;
function decodeSessionCookie(req) { function decodeSessionCookie(req) {
// si l'on n'a pas de cookie de session, on renvoie une session avec vide, // si l'on n'a pas de cookie de session, on renvoie une session avec vide,
// avec juste un userId à -1 // avec juste un userId à -1
console.log(req.cookies);
if (typeof req.cookies.SESSIONID === 'undefined') {
return { userId: -1 };
}
const sessionid = req.cookies.SESSIONID;
if (typeof req.headers.cookie === 'undefined') {
return { username: -1 };
}
const sessionid = req.headers.cookie.replace('SESSIONID=','');
// on lit la clef publique // on lit la clef publique
const RSA_PUBLIC_KEY = fs.readFileSync('./keys/jwtRS256.key.pub'); const RSA_PUBLIC_KEY = fs.readFileSync('../keys/jwtRS256.key.pub');
// on récupère les données du cookie // on récupère les données du cookie
try { try {
@ -81,7 +82,7 @@ function decodeSessionCookie(req) {
return token; return token;
} }
catch (err) { catch (err) {
return {userId: -1}; return {username: err};
} }
} }
module.exports.decodeSessionCookie = decodeSessionCookie; module.exports.decodeSessionCookie = decodeSessionCookie;

View file

@ -1,6 +1,6 @@
const config = { const config = {
mongodbDatabase: 'chat', mongodbDatabase: 'chat',
mongodbHost: 'mongodb://mongodb-message:27020/', mongodbHost: 'mongodb://127.0.0.1:27020/',
charset: 'utf8', charset: 'utf8',
mongodbLogin: '', mongodbLogin: '',
mongodbPassword: '', mongodbPassword: '',

View file

@ -1,13 +0,0 @@
// renvoie un message au format JSON. On a besoin de passer en paramètre
// res, la réponse que l'on envoie au client (Angular). Le paramètre
// data est un objet JavaScript. Globalement, cette fonction est
// équivalente au "echo json_encode(data);" que vous utilisiez en PHP
function sendMessage (res, data) {
res.json ({ status: 'ok', data: data });
}
function sendError (res, reason) {
res.json ({ status: 'error', data: {reason: reason }});
}
module.exports = { sendMessage, sendError };

View file

@ -1,6 +1,6 @@
const config = require('./config'); const config = require('./config');
const mongoose = require( 'mongoose' ); const mongoose = require( 'mongoose' );
const url = config.mongodbHost; const url = config.mongodbHost+config.mongodbDatabase;
mongoose.connect(url,({useNewUrlParser: true, useUnifiedTopology: true})).then( function(){ mongoose.connect(url,({useNewUrlParser: true, useUnifiedTopology: true})).then( function(){
console.log('mongodb-message connected '+mongoose.connection.readyState); console.log('mongodb-message connected '+mongoose.connection.readyState);
@ -8,7 +8,6 @@ mongoose.connect(url,({useNewUrlParser: true, useUnifiedTopology: true})).then(
console.log('error : '+err); console.log('error : '+err);
}); });
const schemaMessage = mongoose.Schema({ const schemaMessage = mongoose.Schema({
username:{ username:{
type: String, type: String,
@ -26,7 +25,7 @@ const schemaMessage = mongoose.Schema({
type: String, type: String,
required: true required: true
} }
}); },{ versionKey: false });
const messages = mongoose.model(config.mongodbMessages, schemaMessage); const messages = mongoose.model(config.mongodbMessages, schemaMessage);

View file

@ -5,50 +5,59 @@ const cors = require ('cors');
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
const auth = require ('./auth'); const auth = require ('./auth');
const bodyParser = require ('body-parser'); const bodyParser = require ('body-parser');
const {sendError, sendMessage} = require ('./message');
const messages = require('./mongodb-message'); const messages = require('./mongodb-message');
const app = express(); const app = express();
const server = http.createServer(app); const server = http.createServer(app);
const io = new Server(server); const io = new Server(server, {
const port = process.env.PORT || 3000; cors: {
origin: "http://127.0.0.1:4200",
methods: ["GET", "POST"],
credentials: true
}
});
const port = process.env.PORT || 3001;
app.use(bodyParser.json()); app.use(bodyParser.json());
app.use(cors({origin: 'http://127.0.0.1:4200', credentials: true})); app.use(cors({origin: 'http://127.0.0.1:4200', credentials: true}));
app.use(cookieParser()); app.use(cookieParser());
io.use(function(socket, next){
const session = auth.getSession(socket.request);
const getUsername = auth.getUsername(session);
if (getUsername === -1) {
//sendError(res, 'not authenticated');
}
auth.setSessionCookie(socket.request, socket.request.res || {}, next);
});
app.get('/', (req, res) => { app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html'); res.sendFile(__dirname + '/index.html');
}); });
io.on('connection',socket => { io.on('connection',socket => {
let users = {}
let users = {};
const session = auth.getSession(socket.request); const session = auth.getSession(socket.request);
const getUsername = auth.getUsername(session); const getUsername = auth.getUsername(session);
if (getUsername === -1) {
socket.emit('error','not authenticated');
}
console.log(`${getUsername} joined the chat.`); console.log(`${getUsername} joined the chat.`);
socket.broadcast.emit('general',`${getUsername} joined the chat.`); socket.broadcast.emit('general',[{
username: 'Server',
date: new Date(),
channel: 'general',
message: `${getUsername} joined the chat.`
}]);
users[socket.id] = getUsername; users[socket.id] = getUsername;
messages.find({},(err, res) => { messages.find({}, {'_id':0},{sort: {'date':1}},(err, res) => {
if(err) throw err; if(err) throw err;
if(res.length > 0){ if(res.length > 0){
const savedChat = res; //console.log(res, res.length);
socket.emit('general',savedChat); socket.emit('general',res);
} }
socket.emit('general',[{
username: 'Server',
date: new Date(),
channel: 'general',
message: `${getUsername} joined the chat.`
}]);
}); });
socket.on('general',function(data){ socket.on('general',function(data){
socket.broadcast.emit('general',data);
const username = data.username; const username = data.username;
const date = Date.now(); const date = Date.now();
const channel = 'general'; const channel = 'general';
@ -62,22 +71,20 @@ io.on('connection',socket => {
} }
]).then(function(){ ]).then(function(){
console.log(data, "inserted"); console.log(data, "inserted");
socket.broadcast.emit('general',[data]);
socket.emit('general',[data]);
}).catch(function(error){ }).catch(function(error){
console.log("error",error); console.log("error",error);
}); });
}); });
socket.on('typing',(user)=>{
socket.broadcast.emit('notifyTyping',user)
})
socket.on("disconnect", function() { socket.on("disconnect", function() {
console.log(`${socket.id} left the chat.`); console.log(`${getUsername} left the chat.`);
}); });
}); });
server.listen(port, () => { server.listen(port, () => {
console.log('listening on *:3000'); console.log(`listening on *:${port}/`);
}); });

View file

@ -1,11 +1,12 @@
const sessionJWT = require ('jsonwebtoken'); const sessionJWT = require ('jsonwebtoken');
const fs = require ('fs'); const fs = require ('fs');
// renvoie un nouveau token JWT // renvoie un nouveau token JWT
function createSessionJWT (userId) { function createSessionJWT (username) {
// ci-dessous, on met en place le cookie de session JWT : // ci-dessous, on met en place le cookie de session JWT :
// 1/ on recupere notre clef privee // 1/ on recupere notre clef privee
const RSA_PRIVATE_KEY = fs.readFileSync('./keys/jwtRS256.key'); const RSA_PRIVATE_KEY = fs.readFileSync('../keys/jwtRS256.key');
// 2/ on signe un token JWT. Le payload est l'identifiant de // 2/ on signe un token JWT. Le payload est l'identifiant de
// l'utilisateur ainsi qu'une date d'expiration à mi-parcours : // l'utilisateur ainsi qu'une date d'expiration à mi-parcours :
@ -18,7 +19,7 @@ function createSessionJWT (userId) {
// session. // session.
const jwtToken = sessionJWT.sign( const jwtToken = sessionJWT.sign(
{ {
userId: userId, username: username,
midExp: Math.floor(Date.now() / 1000) + 1800 // validité: 30mn midExp: Math.floor(Date.now() / 1000) + 1800 // validité: 30mn
}, },
RSA_PRIVATE_KEY, RSA_PRIVATE_KEY,
@ -40,14 +41,15 @@ function createSessionCookie(req, res, payload) {
// midExp, alors le cookie est encore valide et on peut le renvoyer. Sinon, // midExp, alors le cookie est encore valide et on peut le renvoyer. Sinon,
// on doit recalculer un nouveau cookie. // on doit recalculer un nouveau cookie.
let jwtToken = ''; let jwtToken = '';
if ((typeof payload.userId !== 'undefined') && if ((typeof payload.username !== 'undefined') &&
(typeof payload.midExp !== 'undefined') && (typeof payload.midExp !== 'undefined') &&
(Math.floor(Date.now() / 1000) <= payload.midExp)) { (Math.floor(Date.now() / 1000) <= payload.midExp)) {
jwtToken = req.cookies.SESSIONID; jwtToken = req.headers.cookie;
} }
else { else {
// on crée un nouveau cookie // on crée
jwtToken = createSessionJWT(payload.userId); // un nouveau cookie
jwtToken = createSessionJWT(payload.username);
} }
// on renvoie le cookie au client // on renvoie le cookie au client
@ -63,13 +65,13 @@ module.exports.createSessionCookie = createSessionCookie;
function decodeSessionCookie(req) { function decodeSessionCookie(req) {
// si l'on n'a pas de cookie de session, on renvoie une session avec vide, // si l'on n'a pas de cookie de session, on renvoie une session avec vide,
// avec juste un userId à -1 // avec juste un userId à -1
if (typeof req.cookies.SESSIONID === 'undefined') {
return { userId: -1 };
}
const sessionid = req.cookies.SESSIONID;
if (typeof req.headers.cookie === 'undefined') {
return { username: -1 };
}
const sessionid = req.headers.cookie.replace('SESSIONID=','');
// on lit la clef publique // on lit la clef publique
const RSA_PUBLIC_KEY = fs.readFileSync('./keys/jwtRS256.key.pub'); const RSA_PUBLIC_KEY = fs.readFileSync('../keys/jwtRS256.key.pub');
// on récupère les données du cookie // on récupère les données du cookie
try { try {
@ -80,7 +82,7 @@ function decodeSessionCookie(req) {
return token; return token;
} }
catch (err) { catch (err) {
return {userId: -1}; return {username: err};
} }
} }
module.exports.decodeSessionCookie = decodeSessionCookie; module.exports.decodeSessionCookie = decodeSessionCookie;

View file

@ -12,6 +12,23 @@
"requires": { "requires": {
"@angular-devkit/core": "12.0.1", "@angular-devkit/core": "12.0.1",
"rxjs": "6.6.7" "rxjs": "6.6.7"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
} }
}, },
"@angular-devkit/build-angular": { "@angular-devkit/build-angular": {
@ -87,6 +104,23 @@
"webpack-dev-server": "3.11.2", "webpack-dev-server": "3.11.2",
"webpack-merge": "5.7.3", "webpack-merge": "5.7.3",
"webpack-subresource-integrity": "1.5.2" "webpack-subresource-integrity": "1.5.2"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
} }
}, },
"@angular-devkit/build-optimizer": { "@angular-devkit/build-optimizer": {
@ -108,6 +142,23 @@
"requires": { "requires": {
"@angular-devkit/architect": "0.1200.1", "@angular-devkit/architect": "0.1200.1",
"rxjs": "6.6.7" "rxjs": "6.6.7"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
} }
}, },
"@angular-devkit/core": { "@angular-devkit/core": {
@ -122,6 +173,23 @@
"magic-string": "0.25.7", "magic-string": "0.25.7",
"rxjs": "6.6.7", "rxjs": "6.6.7",
"source-map": "0.7.3" "source-map": "0.7.3"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
} }
}, },
"@angular-devkit/schematics": { "@angular-devkit/schematics": {
@ -133,6 +201,23 @@
"@angular-devkit/core": "12.0.1", "@angular-devkit/core": "12.0.1",
"ora": "5.4.0", "ora": "5.4.0",
"rxjs": "6.6.7" "rxjs": "6.6.7"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
} }
}, },
"@angular/animations": { "@angular/animations": {
@ -5620,6 +5705,15 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true "dev": true
}, },
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"supports-color": { "supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -5628,6 +5722,12 @@
"requires": { "requires": {
"has-flag": "^4.0.0" "has-flag": "^4.0.0"
} }
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
} }
} }
}, },
@ -9896,17 +9996,17 @@
} }
}, },
"rxjs": { "rxjs": {
"version": "6.6.7", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.1.0.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "integrity": "sha512-gCFO5iHIbRPwznl6hAYuwNFld8W4S2shtSJIqG27ReWXo9IWrCyEICxUA+6vJHwSR/OakoenC4QsDxq50tzYmw==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "~2.1.0"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.14.1", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
} }
} }
}, },

View file

@ -25,7 +25,8 @@
"@types/socket.io-client": "^3.0.0", "@types/socket.io-client": "^3.0.0",
"bootstrap": "^4.6.0", "bootstrap": "^4.6.0",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"rxjs": "~6.6.0", "rxjs": "^7.1.0",
"socket.io-client": "^4.1.2",
"tslib": "^2.1.0", "tslib": "^2.1.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },

View file

@ -1,8 +1,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import {AppComponent} from "./app.component";
import {LoginComponent} from "./login/login.component"; import {LoginComponent} from "./login/login.component";
import {PrivateComponent} from "./private/private.component"; import {GeneralComponent} from "./general/general.component";
const routes: Routes = [ const routes: Routes = [
{ {
@ -10,8 +9,8 @@ const routes: Routes = [
component: LoginComponent, component: LoginComponent,
}, },
{ {
path: 'private', path: 'general',
component: PrivateComponent, component: GeneralComponent,
} }
]; ];

View file

@ -2,24 +2,18 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import {HttpClientModule} from "@angular/common/http"; import {HttpClientModule} from "@angular/common/http";
import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { GeneralComponent } from './general/general.component'; import { GeneralComponent } from './general/general.component';
import { PrivateComponent } from './private/private.component'; import {CommonModule, DatePipe} from "@angular/common";
import { NavbarComponent } from './navbar/navbar.component';
import {CommonModule} from "@angular/common";
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
LoginComponent, LoginComponent,
GeneralComponent, GeneralComponent
PrivateComponent,
NavbarComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -27,9 +21,9 @@ import {CommonModule} from "@angular/common";
FormsModule, FormsModule,
CommonModule, CommonModule,
ReactiveFormsModule, ReactiveFormsModule,
AppRoutingModule AppRoutingModule,
], ],
providers: [], providers: [DatePipe],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View file

@ -1,52 +1,25 @@
<div class="container-fluid" > <!DOCTYPE html>
<div class="row"> <html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
<div class="col-md-4"> #form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
<div class="user-list-card"> #messages { list-style-type: none; margin: 0; padding: 0; }
<div class="user-card" #messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
> </style>
<!----> </head>
<body>
<img src="../../assets/image/user.png" height="25" width="25"/> <ul #ulMessages id="messages">
<p class="username"></p> </ul>
<form id="form" action="">
</div> <input id="input" autocomplete="off" name="message" [(ngModel)]="msg"/><button (click)="sendButtonClick()">Send</button>
</div> </form>
</body>
</div> </html>
<div class="col-md-8">
<div class="chat-container">
<ng-container *ngIf="selectedUser">
<div class="chat-header">
<p class="username">{{selectedUser?.name}}</p>
</div>
<div class="chat-body">
<div *ngFor="let item of messageArray">
<span><strong>{{item.user}} : </strong> {{item.message}}</span>
</div>
</div>
<div class="chat-footer">
<div class="row">
<div class="col-md-10">
<div class="form-group mb-0">
<input type="text" placeholder="Entrez votre message" class="form-control"
[(ngModel)]="messageText"/>
</div>
</div>
<div class="col-md-2 text-center align-self-center">
<button class="btn btn-primary btn-bm px-3 " (click)="sendMessage()">Envoyer</button>
</div>
</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>

View file

@ -1,8 +1,7 @@
import { Component, OnInit } from '@angular/core'; import {Component, ElementRef, Inject, Input, OnInit, ViewChild} from '@angular/core';
import {ChatService} from "../services/chat/chat.service"; import {ChatInfo, ChatService} from "../services/chat/chat.service";
import {AuthService} from "../services/auth/auth.service"; import {environment} from "../../environments/environment";
import {MessageService} from "../services/message/message.service"; import {DatePipe} from "@angular/common";
import {MatTableDataSource} from "@angular/material/table";
@Component({ @Component({
selector: 'app-general', selector: 'app-general',
@ -10,123 +9,42 @@ import {MatTableDataSource} from "@angular/material/table";
styleUrls: ['./general.component.scss'] styleUrls: ['./general.component.scss']
}) })
export class GeneralComponent implements OnInit { export class GeneralComponent implements OnInit {
dataSource = new MatTableDataSource<userList>();
// @ts-ignore private username = sessionStorage.getItem('login');
public user:String; private room = 'general';
// @ts-ignore public msg = '';
public room:String;
// @ts-ignore
public messageText: string;
messageArray:Array<{user:String,message:String}> = [];
private storageArray = [];
// @ts-ignore // @ts-ignore
public showScreen: boolean; @ViewChild('ulMessages') ulMsg: ElementRef;
// @ts-ignore
public password: string;
// @ts-ignore
public selectedUser;
constructor(private chatservice: ChatService, private pipe: DatePipe) {}
constructor(private Auth: AuthService, ngOnInit() {
private chatService: ChatService, console.log('General working');
private MS: MessageService this.chatservice.setUrl(environment.urlCG);
) { this.chatservice.setRoom(this.room);
this.chatservice.onNewMessage(this.room).subscribe((infos: ChatInfo[]) => {
for(let data of infos){
this.chatService.newUserJoined() if(data !== undefined && data.date !== undefined){
.subscribe(data=> this.messageArray.push(data)); if(data.username === 'Server'){
this.ulMsg.nativeElement.insertAdjacentHTML('beforeend', '<li><span class="text-danger">'+data.message+'</span></li>');
}
this.chatService.userLeftRoom() else{
.subscribe(data=>this.messageArray.push(data)); this.ulMsg.nativeElement.insertAdjacentHTML('beforeend','<li><span class="text-primary">['+this.pipe.transform(data.date, 'dd/MM/yyyy HH:MM:ss')+'] </span><span class="text-success">'+data.username+' </span>:<span class="text-secondary"> '+data.message+'</span></li>');
}
this.chatService.getMessage() }
.subscribe(data=>this.messageArray.push(data)); }
} window.scrollTo(0, document.body.scrollHeight);
ngOnInit(): void {
this.MS.sendMessage('Cours/CoursGet', {}).subscribe( send => {
console.log(send.data);
this.dataSource.data = send.data as userList[];
}); });
// this.chatService.getMessage()
// .subscribe((data: {user: string, message: string}) => {
// this.messageArray.push(data);
// if (this.room) {
// setTimeout( () => {
// this.storageArray = this.chatService.getStorage();
// //@ts-ignore
// const storeIndex = this.storageArray.findIndex((storage) => storage.room === this.room);
// //@ts-ignore
// this.messageArray = this.storageArray[storeIndex].chats;
// }, 500);
// }
// });
} }
// selectUserHandler(password: string): void { sendButtonClick(){
// //this.selectedUser = this.userList.find(user => user.password === password); console.log('Button working');
// this.room = this.selectedUser.room[this.currentUser.id]; if(this.msg && this.username){
// this.messageArray = []; this.chatservice.sendMessage(this.username, this.room, this.msg);
// console.log(this.username, this.room, this.msg);
// this.storageArray = this.chatService.getStorage(); this.msg = '';
// // @ts-ignore }
// const storeIndex = this.storageArray.findIndex((storage) => storage.room === this.room);
//
// if (storeIndex > -1) {
// // @ts-ignore
// this.messageArray = this.storageArray[storeIndex].chats;
// }
//
// // @ts-ignore
// this.join(this.currentUser.name, this.room);
// }
join(username: string, room: string): void {
this.chatService.joinRoom({user: username, room: room});
} }
sendMessage()
{
this.chatService.sendMessage({user:this.user, room:this.room, message:this.messageText});
// this.storageArray = this.chatService.getStorage();
// // @ts-ignore
// const storeIndex = this.storageArray.findIndex((storage) => storage.room === this.room);
//
// if (storeIndex > -1) {
// // @ts-ignore
// this.storageArray[storeIndex].chats.push({
// user: this.currentUser.name,
// message: this.messageText
// })
// } else {
// const updateStorage = {
// room: this.room,
// chats: [{
// user: this.currentUser.name,
// message: this.messageText
// }]
// };
// // @ts-ignore
// this.storageArray.push(updateStorage);
// }
// this.chatService.setStorage(this.storageArray);
// this.messageText = '';
}
leave(){
this.chatService.leaveRoom({login:this.dataSource.data, room:this.room});
}
}
export interface userList {
login: string;
} }

View file

@ -1,5 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {AuthService} from "../services/auth/auth.service"; import {AuthService} from "../services/auth/auth.service";
@ -10,7 +9,6 @@ import {AuthService} from "../services/auth/auth.service";
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit {
login = ''; login = '';
password = ''; password = '';
errorMessage = ''; errorMessage = '';
@ -27,7 +25,8 @@ export class LoginComponent implements OnInit {
this.auth.sendAuthentication(this.login, this.password).subscribe(data => { this.auth.sendAuthentication(this.login, this.password).subscribe(data => {
this.auth.finalizeAuthentication(data); this.auth.finalizeAuthentication(data);
if (this.auth.islog === true) { if (this.auth.islog === true) {
this.router.navigateByUrl('/private'); sessionStorage.setItem('login', this.login);
this.router.navigateByUrl('/general');
} else { } else {
this.errorMessage = data.data.reason; this.errorMessage = data.data.reason;
console.log(this.errorMessage); console.log(this.errorMessage);

View file

@ -1 +0,0 @@
<p>navbar works!</p>

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarComponent } from './navbar.component';
describe('NavbarComponent', () => {
let component: NavbarComponent;
let fixture: ComponentFixture<NavbarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavbarComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(NavbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,15 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View file

@ -1,55 +0,0 @@
<div class="container-fluid" >
<div class="row">
<div class="col-md-4">
<div class="user-list-card">
<div class="user-card"
>
<!---->
<img src="../../assets/image/user.png" height="25" width="25"/>
<p class="username"></p>
</div>
</div>
</div>
<div class="col-md-8">
<div class="chat-container">
<ng-container *ngIf="selectedUser">
<div class="chat-header">
<p class="username">{{selectedUser?.name}}</p>
</div>
<div class="chat-body">
<div *ngFor="let item of messageArray"
>
<!---->
<p class="message-container">{{item?.message}}</p>
</div>
</div>
<div class="chat-footer">
<div class="row">
<div class="col-md-10">
<div class="form-group mb-0">
<input type="text" placeholder="Entrez votre message" class="form-control"
[(ngModel)]="messageText" (keyup)="$event.keyCode === 13 && sendMessage()"/>
</div>
</div>
<div class="col-md-2 text-center align-self-center">
<button class="btn btn-primary btn-bm px-3 " (click)="sendMessage()">Envoyer</button>
</div>
</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PrivateComponent } from './private.component';
describe('PrivateComponent', () => {
let component: PrivateComponent;
let fixture: ComponentFixture<PrivateComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PrivateComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PrivateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,123 +0,0 @@
import {NgModule, Component, OnInit, Input} from '@angular/core';
import {ChatService} from "../services/chat/chat.service";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {AuthService} from "../services/auth/auth.service";
import {MessageService} from "../services/message/message.service";
import {MatTableDataSource} from "@angular/material/table";
@Component({
selector: 'app-private',
templateUrl: './private.component.html',
styleUrls: ['./private.component.scss']
})
export class PrivateComponent implements OnInit {
dataSource = new MatTableDataSource<userList>();
// @ts-ignore
public roomId: string;
// @ts-ignore
public messageText: string;
public messageArray: {user: string, message: string}[] = [];
private storageArray = [];
// @ts-ignore
public showScreen: boolean;
// @ts-ignore
public password: string;
// @ts-ignore
public currentUser;
// @ts-ignore
public selectedUser;
constructor(
private Auth: AuthService,
private chatService: ChatService,
private MS: MessageService
) {
}
ngOnInit(): void {
this.MS.sendMessage('Cours/CoursGet', {}).subscribe( send => {
console.log(send.data);
this.dataSource.data = send.data as userList[];
});
// this.chatService.getMessage()
// .subscribe((data: {user: string, message: string}) => {
// this.messageArray.push(data);
// if (this.roomId) {
// setTimeout( () => {
// this.storageArray = this.chatService.getStorage();
// //@ts-ignore
// const storeIndex = this.storageArray.findIndex((storage) => storage.roomId === this.roomId);
// //@ts-ignore
// this.messageArray = this.storageArray[storeIndex].chats;
// }, 500);
// }
// });
}
// selectUserHandler(login: string): void {
// this.login = login;
// this.selectedUser = this.userList.find(user => user.password === password);
// this.roomId = this.selectedUser.roomId[this.currentUser.id];
// this.messageArray = [];
//
// // this.storageArray = this.chatService.getStorage();
// // // @ts-ignore
// // const storeIndex = this.storageArray.findIndex((storage) => storage.roomId === this.roomId);
// //
// // if (storeIndex > -1) {
// // // @ts-ignore
// // this.messageArray = this.storageArray[storeIndex].chats;
// // }
//
// this.join(this.login);
// }
join(username: string, roomId: string): void {
this.chatService.joinRoom({user: username});
}
sendMessage(): void {
this.chatService.sendMessage({
user: this.currentUser.name,
message: this.messageText
});
// this.storageArray = this.chatService.getStorage();
// // @ts-ignore
// const storeIndex = this.storageArray.findIndex((storage) => storage.roomId === this.roomId);
//
// if (storeIndex > -1) {
// // @ts-ignore
// this.storageArray[storeIndex].chats.push({
// user: this.currentUser.name,
// message: this.messageText
// })
// } else {
// const updateStorage = {
// roomId: this.roomId,
// chats: [{
// user: this.currentUser.name,
// message: this.messageText
// }]
// };
// // @ts-ignore
// this.storageArray.push(updateStorage);
// }
// this.chatService.setStorage(this.storageArray);
this.messageText = '';
}
}
export interface userList {
login: string;
}

View file

@ -1,75 +1,61 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { io, Socket } from "socket.io-client"; import { Observable } from 'rxjs';
import {Observable} from "rxjs"; import { io, Socket } from 'socket.io-client';
export interface ChatInfo {
username: string,
date: Date,
room: string,
message: string
}
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class ChatService { export class ChatService {
private socket: Socket; private socket: Socket | undefined;
private url = 'http://localhost:3000'; private url: string;
private room: string;
constructor() { constructor() {
this.socket = io(this.url); this.url = '';
this.room = '';
} }
// @ts-ignore setUrl(url: string){
joinRoom(data): void { this.url = url;
this.socket.emit('join', data); this.setSocket();
} }
// @ts-ignore setRoom(room: string){
sendMessage(data): void{ this.room = room;
this.socket.emit('message', data);
} }
getMessage(): Observable<any> { setSocket(){
return new Observable<{user: string, message: string}>(observer => { this.socket = io(this.url, {
this.socket.on('new message', (data) => { withCredentials: true
observer.next(data);
});
return () => {
this.socket.disconnect();
}
}); });
} }
newUserJoined() sendMessage(username: string | null, room: string, message: string) {
{ // @ts-ignore
let observable = new Observable<{user:String, message:String}>(observer=>{ this.socket.emit(room, {
this.socket.on('new user joined', (data)=>{ username: username,
date: new Date(),
room: room,
message: message
});
}
onNewMessage(room: string): Observable<ChatInfo[]> {
return new Observable(observer => {
// @ts-ignore
this.socket.on(room, (data: ChatInfo[]) => {
console.log(data);
observer.next(data); observer.next(data);
}); });
return () => {this.socket.disconnect();}
}); });
return observable;
} }
// @ts-ignore
leaveRoom(data){
this.socket.emit('leave',data);
}
userLeftRoom(){
let observable = new Observable<{user:String, message:String}>(observer=>{
this.socket.on('left room', (data)=>{
observer.next(data);
});
return () => {this.socket.disconnect();}
});
return observable;
}
getStorage() {
const storage = localStorage.getItem('chats');
return storage ? JSON.parse(storage) : [];
}
setStorage(data: any) {
localStorage.setItem('chats', JSON.stringify(data));
}
} }

View file

@ -4,7 +4,8 @@
export const environment = { export const environment = {
production: false, production: false,
urlCL: 'http://127.0.0.1:3000' urlCL: 'http://127.0.0.1:3000',
urlCG: 'http://127.0.0.1:3001'
}; };
/* /*