Compare commits

..

2 commits
master ... test

Author SHA1 Message Date
wilfried
362a1f236b try frontend... 2021-05-30 10:40:48 +02:00
wilfried
1dcf975c97 rr 2021-05-29 23:04:28 +02:00
80 changed files with 650 additions and 5507 deletions

View file

@ -1,27 +1,5 @@
**Projet Chat**
**Instruction de lancement du Chat**
- `docker compose up`
- Puis se connecter en local sur `http://localhost:4200`
- Identifiants de connexion disponible :
- Username : cloud | Password : computing
- Username : wilfried | Password : test
- Username : yuki | Password : test
- Username : khai | Password : test
- Pour avoir un autre utilisateur connecté, il faut absolument avoir soit un autre navigateur soit un autre onglet en navigateur privé (pour cause d'identifiant de session)
Pour lancer le projet sans image docker, il est obligatoire de lancer plusieurs terminals pour le frontend et pour chaque
serveurs et avoir des images dockers mongodb.
A savoir:
- Terminal Frontend dans le dossier frontend : `ng serve`
- Terminal service-authentication dans le dossier service-authentication : `node server.js`
- Terminal service-message dans le dossier service-message : `node server.js`
- Terminal service-privateroom dans le dossier service-privateroom : `node server.js`
- Puis se connecter en local sur `http://localhost:4200`
**Instruction du professeur**
Le but du projet est de fournir un service de chat rudimentaire :
- Une interface utilisateur en web
- Les utilisateurs peuvent s'enregistrer/se connecter/se déconnecter/changer leur mot de passe

View file

@ -1,22 +0,0 @@
const {sendError, sendMessage} = require ("./message");
const queries = require('./mongodbQueries');
async function changePassword (req,res) {
if (typeof req.body.username === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ username');
if (typeof req.body.password === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ password');
if (typeof req.body.newpassword === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ newpassword');
const change = await queries.changePasswordQuery(req.body.username, req.body.password, req.body.newpassword);
if (change){
return sendMessage(res, 'Le mot de passe a été changé.');
}
else{
return sendError(res, 'Mot de passe actuel incorrect ou erreur interne');
}
}
module.exports = changePassword;

View file

@ -9,7 +9,6 @@ async function checkLogin (req,res) {
const result = await auth.authenticate(req, res);
if (result === 1){
console.log(`${new Date()}] ${req.body.login} connected.`);
return sendMessage(res, true);
}
else{

View file

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

View file

@ -6,6 +6,7 @@ async function getUsers (req,res) {
return sendError(res, 'Vous n\'avez pas envoyé le champ username');
const users = await queries.getUsersQuery(req.body.username);
console.log(users);
if (users){
return sendMessage(res, users);
}

View file

@ -18,15 +18,11 @@ function register(login, password){
return new Promise((resolve, reject) => {
mongoDB.collection(config.mongodbUtilisateurs).updateOne(
{'login': login},
{$setOnInsert: { 'login': login, 'password': password}},
{$set: { 'login': login, 'password': password}},
{upsert:true},function(err,res){
//console.log(res);
if(res !== undefined){
if(typeof res.upsertedId !== 'undefined'){
resolve(res.upsertedId);
}else{
resolve(false);
}
resolve(res.upsertedCount === 1);
}
});
});
@ -46,17 +42,3 @@ function getUsersQuery(username){
}
module.exports.getUsersQuery = getUsersQuery
function changePasswordQuery(login, password, newPassword){
return new Promise((resolve, reject) => {
mongoDB.collection(config.mongodbUtilisateurs).findOneAndUpdate(
{'login': login, 'password': password},
{$set: { 'login': login, 'password': newPassword}}
,function(err,res){
if(res !== undefined){
console.log(res);
resolve(res.lastErrorObject.n === 1);
}
});
});
}
module.exports.changePasswordQuery = changePasswordQuery;

View file

@ -2,19 +2,19 @@ const {sendError, sendMessage} = require ("./message");
const queries = require('./mongodbQueries');
async function register(req,res) {
if (typeof req.body.username === 'undefined')
if (typeof req.body.login === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ login');
if (typeof req.body.password === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ password');
const register = await queries.register(req.body.username, req.body.password);
const register = await queries.register(req.body.login, req.body.password);
if (register){
console.log('Register : '+req.body.username);
return sendMessage(res, 'Successful registration');
console.log('Register : '+req.body.login);
return sendMessage(res, null);
}
else{
return sendError(res, 'Username already taken');
return sendError(res, 'Error registering');
}
}
module.exports = register;

View file

@ -10,7 +10,7 @@ app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
const cors = require('cors');
app.use(cors({origin: 'http://localhost:4200', credentials: true}));
app.use(cors({origin: 'http://127.0.0.1:4200', credentials: true}));
const mongoConnect = require('./mongodbConnect');
@ -18,7 +18,6 @@ mongoConnect.connectToServer(function( err, client ) {
if (err) console.log(err);
const checkLogin = require('./checkLogin');
const register = require('./register');
const changePassword = require('./changePassword');
const getUsers = require('./getUsers');
const queries = require('./mongodbQueries');
const auth = require('./auth');
@ -27,7 +26,6 @@ mongoConnect.connectToServer(function( err, client ) {
queries.register('khai','test');
queries.register('wilfried','test');
queries.register('yuki','test');
queries.register('cloud','computing');
app.post('/verify:token', (req, res) => {
if(typeof req.body !== 'undefined'){
@ -48,11 +46,7 @@ mongoConnect.connectToServer(function( err, client ) {
getUsers(req,res);
});
app.post('/changePassword', (req, res) => {
changePassword(req,res);
});
app.listen(port, '0.0.0.0',() => {
app.listen(port, () => {
console.log (`listening on port ${port}`);
});
});

View file

@ -4,11 +4,9 @@ function getSession (req, callback) {
if(typeof req.headers.cookie !== 'undefined'){
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://service-authentication:3000/verify:token',
url: 'http://127.0.0.1:3000/verify:token',
body: 'sessionid='+req.headers.cookie.replace('SESSIONID=','')
},function (error, response, body) {
//console.log("body ; getSession auth message :",body);
if(typeof body !== 'undefined'){
const bodyJson = JSON.parse(body);
if (bodyJson && bodyJson.status && bodyJson.data) {
if (bodyJson.status === 'ok') {
@ -17,10 +15,6 @@ function getSession (req, callback) {
return callback(bodyJson.data.reason);
}
}
}
else{
return callback('Error');
}
});
}
return callback(undefined);

View file

@ -1,7 +1,6 @@
const config = {
mongodbDatabase: 'chat',
mongodbHost: 'mongodb://mongodb-message:27017/',
// mongodbHost: 'mongodb://127.0.0.1:27020/',
mongodbHost: 'mongodb://127.0.0.1:27020/',
charset: 'utf8',
mongodbLogin: '',
mongodbPassword: '',
@ -9,3 +8,6 @@ const config = {
mongodbMessages: 'messages'
};
module.exports = config;

View file

@ -29,4 +29,9 @@ const schemaMessage = mongoose.Schema({
const messages = mongoose.model(config.mongodbMessages, schemaMessage);
// messages.find({},(err, messages) => {
// if(err) throw err;
// console.log(messages);
// });
module.exports = messages;

View file

@ -11,7 +11,7 @@ const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "http://localhost:4200",
origin: "http://127.0.0.1:4200",
methods: ["GET", "POST"],
credentials: true
}
@ -19,53 +19,31 @@ const io = new Server(server, {
const port = process.env.PORT || 3001;
app.use(bodyParser.json());
app.use(cors({origin: 'http://localhost:4200', credentials: true}));
app.use(cors({origin: 'http://127.0.0.1:4200', credentials: true}));
app.use(cookieParser());
messages.insertMany([
{
username: 'yuki',
date: new Date(),
channel: 'general',
message: 'Ceci est un message de test de la part de Yûki'
},
{
username: 'wilfried',
date: new Date(),
channel: 'general',
message: 'Ceci est un message de test de la part de Wilfried'
},
{
username: 'khai',
date: new Date(),
channel: 'general',
message: 'Ceci est un message de test de la part de Khai'
},
{
username: 'cloud',
date: new Date(),
channel: 'general',
message: 'Ceci est un message à des fins de démonstration'
},
]);
// app.get('/', (req, res) => {
// res.sendFile(__dirname + '/index.html');
// });
io.on('connection',socket => {
let users = {};
auth.getSession(socket.request, function(res){
const getUsername = auth.getUsername(res);
if (getUsername === -1) {
console.log('not authenticated',getUsername);
socket.send('error','not authenticated');
}
else{
console.log(`${new Date()}] ${getUsername} joined the chat.`);
console.log(`${getUsername} joined the chat.`);
socket.broadcast.emit('general',[{
username: 'Server',
date: new Date(),
channel: 'general',
message: `${getUsername} joined the chat.`
}]);
users[socket.id] = getUsername;
messages.find({}, {'_id':0},{sort: {'date':1}},(err, res) => {
if(err) throw err;
if(res.length > 0){
@ -82,7 +60,7 @@ io.on('connection',socket => {
socket.on('general',function(data){
const username = data.username;
const date = data.date;
const date = Date.now();
const channel = 'general';
const message = data.message;
@ -93,7 +71,7 @@ io.on('connection',socket => {
message: message
}
]).then(function(){
//console.log(data, "inserted");
console.log(data, "inserted");
socket.broadcast.emit('general',[data]);
socket.emit('general',[data]);
}).catch(function(error){
@ -103,18 +81,12 @@ io.on('connection',socket => {
});
socket.on("disconnect", function() {
console.log(`${new Date()}] ${getUsername} left the chat.`);
socket.broadcast.emit('general',[{
username: 'Server',
date: new Date(),
channel: 'general',
message: `${getUsername} left the chat.`
}]);
console.log(`${getUsername} left the chat.`);
});
}
});
});
server.listen(port,'0.0.0.0', () => {
console.log (`listening on port ${port}`);
server.listen(port, () => {
console.log(`listening on *:${port}/`);
});

View file

@ -0,0 +1,8 @@
# syntax=docker/dockerfile:1
FROM node:current-slim
ENV NODE_ENV=production
WORKDIR /app-notification
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install --production
COPY . .
CMD [ "node", "server.js" ]

View file

@ -1,6 +1,8 @@
# syntax=docker/dockerfile:1
FROM node:current-slim
ENV NODE_ENV=production
WORKDIR /app-privateroom
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install
RUN npm install --production
COPY . .
CMD node server.js
CMD [ "node", "server.js" ]

View file

@ -1,34 +0,0 @@
const request = require('request');
function getSession (req, callback) {
if(typeof req.headers.cookie !== 'undefined'){
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://service-authentication:3000/verify:token',
body: 'sessionid='+req.headers.cookie.replace('SESSIONID=','')
},function (error, response, body) {
//console.log("body ; getSession auth private :",body);
if(typeof body !== 'undefined'){
const bodyJson = JSON.parse(body);
if (bodyJson && bodyJson.status && bodyJson.data) {
if (bodyJson.status === 'ok') {
return callback(bodyJson.data.token);
} else {
return callback(bodyJson.data.reason);
}
}
}
else{
return callback('Error');
}
});
}
return callback(undefined);
}
module.exports.getSession = getSession;
function getUsername(session) {
if (typeof session === 'undefined' || typeof session.username === 'undefined') return -1;
return session.username;
}
module.exports.getUsername = getUsername;

View file

@ -1,15 +0,0 @@
const config = {
mongodbDatabase: 'chat',
mongodbHost: 'mongodb://mongodb-privateroom:27017',
// mongodbHost: 'mongodb://127.0.0.1:27021/',
charset: 'utf8',
mongodbLogin: '',
mongodbPassword: '',
mongodbPrivatedMessages: 'privatedmessages',
mongodbConversations: 'conversations'
};
module.exports = config;

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,27 +0,0 @@
const mongoose = require("mongoose");
const config = require("../config");
const url = config.mongodbHost+config.mongodbDatabase;
mongoose.connect(url,({useNewUrlParser: true, useUnifiedTopology: true})).then( function(){
console.log('mongodb-conversation connected '+mongoose.connection.readyState);
}).catch(function(err){
console.log('error : '+err);
});
const ConversationSchema = new mongoose.Schema(
{
owner: {
type: String
},
roomName: {
type: String
},
members: {
type: Array
},
},
{ timestamps: true, versionKey: false }
);
module.exports = mongoose.model(config.mongodbConversations, ConversationSchema);

View file

@ -1,30 +0,0 @@
const mongoose = require("mongoose")
const config = require("../config");
const url = config.mongodbHost+config.mongodbDatabase;
mongoose.connect(url,({useNewUrlParser: true, useUnifiedTopology: true})).then( function(){
console.log('mongodb-privated-room connected '+mongoose.connection.readyState);
}).catch(function(err){
console.log('error : '+err);
});
const MessageSchema = new mongoose.Schema(
{
conversationId: {
type: String
},
sender: {
type: String
},
text: {
type: String
},
date:{
type: Date,
},
},
{ timestamps: true, versionKey: false }
);
module.exports = mongoose.model(config.mongodbPrivatedMessages, MessageSchema);

View file

@ -1,25 +0,0 @@
{
"name": "service-privateroom",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"express": "^4.17.1",
"fs": "0.0.1-security",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.12.11",
"socket.io": "^4.1.2"
},
"devDependencies": {
"request": "^2.88.2"
}
}

View file

@ -1,174 +0,0 @@
const router = require("express").Router();
const Conversation = require("../models/Conversation");
const {sendError, sendMessage} = require ("../message");
// new conv
router.post("/newConv", async (req, res) => {
if (typeof req.body.sender === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ sender');
if (typeof req.body.receiver === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ receiver');
const newConversation = new Conversation({
members: [req.body.sender, req.body.receiver], owner: null
});
try{
const savedConversation = await newConversation.save();
sendMessage(res,savedConversation._id);
}catch (err){
sendError(res,err);
}
});
// get conv
router.post("/getConv", async (req, res) => {
if (typeof req.body.sender === 'undefined' && typeof req.body.member === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ sender ou member');
if (typeof req.body.receiver === 'undefined' && typeof req.body.roomName === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ receiver ou roomName');
if (typeof req.body.sender === 'undefined'){
try {
const conversation = await Conversation.find({members: {$in: [req.body.member]}, roomName: req.body.roomName},{_id:1});
if(conversation === []){
sendError(res, 'Not found');
}
else{
sendMessage(res,conversation[0]);
}
}catch (err){
sendError(res,err);
}
}
else{
try {
const conversation = await Conversation.findOne({$or: [{members: {$eq: [req.body.sender,req.body.receiver]}},{members: {$eq: [req.body.receiver,req.body.sender]}}]},{_id:1});
console.log(conversation);
sendMessage(res,conversation);
}catch (err){
sendError(res,err);
}
}
});
// getRooms
router.post("/getRooms", async (req, res) => {
if (typeof req.body.member === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ member');
try {
const conversation = await Conversation.find({members: {$in: [req.body.member]}, roomName: {$exists: true}},{});
console.log(conversation);
sendMessage(res,conversation);
}catch (err){
sendError(res,err);
}
});
// getMembers
router.post("/getMembers", async (req, res) => {
if (typeof req.body.conversationid === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ conversationid');
try {
const conversation = await Conversation.find({_id: req.body.conversationid},{members: 1});
sendMessage(res,conversation);
}catch (err){
sendError(res,err);
}
});
// new Room
router.post("/newRoom", async (req, res) => {
if (typeof req.body.owner === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ owner');
if (typeof req.body.roomName === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ roomName');
await Conversation.updateOne(
{roomName: req.body.roomName},
{$setOnInsert: {members: req.body.owner, owner: req.body.owner, roomName: req.body.roomName}},
{upsert:true},function(err,result){
if(result !== undefined){
if(typeof result.upserted !== 'undefined'){
sendMessage(res,result.upserted[0]._id);
}else{
sendError(res,'Room already exist');
}
}else{
sendError(res,err);
}
});
});
// add Room Member
router.post("/addRoomMember", async (req, res) => {
if (typeof req.body.conversationid === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ conversationId');
if (typeof req.body.owner === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ owner');
if (typeof req.body.member === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ member');
if(req.body.member === req.body.owner){
return sendError(res, 'Impossible de vous ajouter vous même');
}
try{
await Conversation.updateOne(
{_id: req.body.conversationid, owner: req.body.owner},
{$addToSet: {members: req.body.member}},
{useFindAndModify: false},
function(err, result){
if(result !== undefined){
console.log(result);
if(result.nModified === 1){
sendMessage(res,req.body.member+' added');
}
else{
sendError(res,'Seul le propriétaire de la room peut ajouter des membres.');
}
}
else{
sendError(res,err);
}
});
}catch (err){
sendError(res,err);
}
});
// remove Room Member
router.post("/removeRoomMember", async (req, res) => {
if (typeof req.body.conversationid === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ conversationId');
if (typeof req.body.owner === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ owner');
if (typeof req.body.member === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ member');
if(req.body.member === req.body.owner){
return sendError(res, 'Impossible de vous enlever vous même');
}
try{
await Conversation.updateOne(
{_id: req.body.conversationid, owner: req.body.owner},
{$pull: {members: req.body.member}},
{useFindAndModify: false},
function(err, result){
if(result !== undefined){
console.log(result);
if(result.nModified === 1){
sendMessage(res,req.body.member+' removed');
}
else{
sendError(res,'Seul le propriétaire de la room peut retirer des membres.');
}
}
else{
sendError(res,err);
}
});
}catch (err){
sendError(res,err);
}
});
module.exports = router;

View file

@ -1,143 +0,0 @@
const express = require('express');
const app = express();
const port = process.env.PORT || 3002;
const http = require('http');
const { Server } = require("socket.io");
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "http://localhost:4200",
methods: ["GET", "POST"],
credentials: true
}
});
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
const cookieParser = require('cookie-parser');
app.use(cookieParser());
const cors = require('cors');
app.use(cors({origin: 'http://localhost:4200', credentials: true}));
const auth = require("./auth");
const Message = require("./models/Message");
const conversationRoute = require("./routes/conversations");
app.use("/conversations", conversationRoute);
const Conversation = require("./models/Conversation");
Conversation.updateOne(
{roomName: 'Demonstration Room'},
{$setOnInsert: {members: ['cloud','yuki','wilfried','khai'], owner: 'cloud', roomName: 'Demonstration Room'}},
{upsert:true},function(err,result){
if(result !== undefined){
if(typeof result.upserted !== 'undefined'){
Message.insertMany([
{
conversationId: result.upserted[0]._id,
sender: 'yuki',
text: 'Message à des fins de démonstration pour private room de Yûki',
date: new Date()
},
{
conversationId: result.upserted[0]._id,
sender: 'wilfried',
text: 'Message à des fins de démonstration pour private room de Wilfried',
date: new Date()
},
{
conversationId: result.upserted[0]._id,
sender: 'khai',
text: 'Message à des fins de démonstration pour private room de Khai',
date: new Date()
},
{
conversationId: result.upserted[0]._id,
sender: 'cloud',
text: 'Message à des fins de démonstration pour private room de Cloud',
date: new Date()
},
]);
}else{
console.log('Room already exist');
}
}else{
console.log(err);
}
});
io.on('connection',socket => {
auth.getSession(socket.request, function(res){
const getUsername = auth.getUsername(res);
if (getUsername === -1) {
console.log('not authenticated',getUsername);
socket.send('error','not authenticated');
}
else{
socket.on('joinroom', function (data){
console.log(`${new Date()}] ${getUsername} joined the chat.`);
const conversationId = data.room;
socket.broadcast.emit(conversationId,[{
username: 'Server',
date: new Date(),
channel: conversationId,
message: `${getUsername} joined the chat.`
}]);
Message.find({conversationId: {$eq: conversationId}}, {'_id':0, 'username': '$sender', 'date':'$date', 'channel':'$conversationId', 'message':'$text'},{sort: {'date':1}},(err, res) => {
if(err) throw err;
if(res.length > 0){
socket.emit(conversationId,res);
}
socket.emit(conversationId,[{
username: 'Server',
date: new Date(),
channel: conversationId,
message: `${getUsername} joined the chat.`
}]);
});
});
socket.on('privateroom',function(data){
console.log(`${getUsername} joined the chat.`);
const sender = data.sender;
const conversationId = data.room;
const date = data.date;
const message = data.message;
Message.insertMany([{
conversationId: conversationId,
sender: sender,
text: message,
date: date
}
]).then(function(){
console.log(data, "inserted");
const newData = {
username: data.sender,
date: data.date,
channel: conversationId,
message: data.message
}
socket.broadcast.emit(conversationId,[newData]);
socket.emit(conversationId,[newData]);
}).catch(function(error){
console.log("error",error);
});
});
socket.on("disconnect", function() {
console.log(`${new Date()}] ${getUsername} left the chat.`);
});
}
});
});
server.listen(port, '0.0.0.0',() => {
console.log (`listening on port ${port}`);
});

View file

@ -13,11 +13,9 @@ services:
depends_on:
- service-authentication
- service-message
- service-privateroom
links:
- service-authentication
- service-message
- service-privateroom
service-authentication:
container_name: service-authentication
@ -34,7 +32,7 @@ services:
links:
- mongodb-authentication
environment:
NODE_ENV: production
NODE_ENV: development
service-message:
container_name: service-message
@ -44,31 +42,13 @@ services:
- backend/service-message
- backend/service-message/node_modules
ports:
- 3001:3001
- 3001:3000
depends_on:
- mongodb-message
links:
- mongodb-message
- service-authentication
environment:
NODE_ENV: production
service-privateroom:
container_name: service-privateroom
build: ./backend/service-privateroom
command: node server.js
volumes:
- backend/service-privateroom
- backend/service-privateroom/node_modules
ports:
- 3002:3002
depends_on:
- mongodb-privateroom
links:
- mongodb-privateroom
- service-authentication
environment:
NODE_ENV: production
NODE_ENV: development
mongodb-authentication:
image: mongo
@ -85,11 +65,3 @@ services:
- ./backend/service-message/database:/data/db-message
ports:
- 27020:27017
mongodb-privateroom:
image: mongo
container_name: mongodb-privateroom
volumes:
- ./backend/service-privateroom/database:/data/db-privateroom
ports:
- 27021:27017

View file

@ -34,23 +34,18 @@
"src/assets"
],
"styles": [
"node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"node_modules/bootstrap/scss/bootstrap.scss",
"src/styles.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/popper.js/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "2mb"
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,8 @@
"@angular/router": "~12.0.1",
"@ng-bootstrap/ng-bootstrap": "^8.0.0",
"@types/socket.io-client": "^3.0.0",
"angular-bootstrap-md": "^11.1.0",
"bootstrap": "^4.6.0",
"jquery": "^3.6.0",
"jquery.js": "0.0.2-security",
"jquery.min.js": "^3.5.1",
"popper": "^1.0.1",
"popper.js": "^1.16.1",
"rxjs": "^7.1.0",
"socket.io-client": "^4.1.2",
"tslib": "^2.1.0",
@ -40,7 +35,6 @@
"@angular/cli": "~12.0.1",
"@angular/compiler-cli": "~12.0.1",
"@types/jasmine": "~3.6.0",
"@types/jquery": "^3.5.5",
"@types/node": "^12.11.1",
"jasmine-core": "~3.7.0",
"karma": "~6.3.0",

View file

@ -1,13 +0,0 @@
<h1 mat-dialog-title>Ajouter un membre</h1>
<mat-divider></mat-divider>
<br>
<div mat-dialog-content>
<p>Saisissez un nouveau nom d'utilisateur à ajouter à la room</p>
<input matInput [(ngModel)]="memberName" class="w-100">
</div>
<br>
<div class="alert alert-danger w-100" *ngIf="errorMessage!==''"><span class="font-weight-bold">Erreur : </span>{{errorMessage}}</div>
<div mat-dialog-actions class="float-right">
<button mat-raised-button color="accent" class="mb-2" (click)="onNoClick()">Fermer</button>
<button mat-raised-button color="primary" class="mb-2" (click)="onAddMember()" cdkFocusInitial>Ajouter le membre</button>
</div>

View file

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

View file

@ -1,45 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../services/message/message.service";
import {environment} from "../../environments/environment";
export interface AddMemberDialogData {
owner: string;
conversationid: string
}
@Component({
selector: 'app-add-member-dialog',
templateUrl: './add-member-dialog.component.html',
styleUrls: ['./add-member-dialog.component.scss']
})
export class AddMemberDialogComponent{
memberName = '';
errorMessage = '';
constructor(
public dialogRef: MatDialogRef<AddMemberDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: AddMemberDialogData,
@Inject(MessageService) private messageService: MessageService) { }
onNoClick(): void {
this.dialogRef.close();
}
onAddMember(){
this.messageService.sendMessage(environment.urlCPR, "conversations/addRoomMember", {owner: this.data.owner, conversationid: this.data.conversationid, member: this.memberName}).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
this.errorMessage = data.data.reason;
}
else{
this.dialogRef.close({
data: data.data
});
}
});
}
}

View file

@ -1,36 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {LoginComponent} from "./login/login.component";
import {ChatComponent} from "./chat/chat.component";
import {AuthGuard} from "./auth.guard";
import {ChangePasswordComponent} from "./change-password/change-password.component";
import {GeneralComponent} from "./general/general.component";
const routes: Routes = [
// {
// path: 'login',
// component: LoginComponent,
// },
// {
// path: '',
// canActivateChild: [AuthGuard],
// children: [
// { path: 'chat', component: ChatComponent},
// { path: 'changePassword', component: ChangePasswordComponent}
// ]
// }
{
path: '',
path: 'login',
component: LoginComponent,
},
{ path: 'chat',
canActivateChild: [AuthGuard],
component: ChatComponent
},
{ path: 'changePassword', component: ChangePasswordComponent}
{
path: 'general',
component: GeneralComponent,
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
exports: [RouterModule]
})
export class AppRoutingModule { }

View file

@ -1,2 +1 @@
<app-navbar></app-navbar>
<router-outlet></router-outlet>

View file

@ -1,22 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {Title} from '@angular/platform-browser';
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
constructor(private titleService: Title, private router: Router) {
}
ngOnInit(): void {
this.setTitle('Chat Polytech');
}
public setTitle(newTitle: string): void {
this.titleService.setTitle(newTitle);
}
export class AppComponent {
title = 'frontend';
}

View file

@ -5,60 +5,23 @@ import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { GeneralComponent } from './general/general.component';
import {CommonModule, DatePipe} from "@angular/common";
import { PrivateComponent } from './private/private.component';
import { ChatComponent } from './chat/chat.component';
import { MessageComponent } from './message/message.component';
import { RegisterComponent } from './register/register.component';
import { ChangePasswordComponent } from './change-password/change-password.component';
import { NavbarComponent } from './navbar/navbar.component';
import {NavbarModule, WavesModule, ButtonsModule, IconsModule} from 'angular-bootstrap-md';
import { AddMemberDialogComponent } from './add-member-dialog/add-member-dialog.component';
import { RemoveMemberDialogComponent } from './remove-member-dialog/remove-member-dialog.component';
import {MatDividerModule} from "@angular/material/divider";
import {MatFormFieldModule} from "@angular/material/form-field";
import {MatDialogModule} from "@angular/material/dialog";
import {MatButtonModule} from "@angular/material/button";
import {MatSortModule} from "@angular/material/sort";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {CreateRoomDialogComponent} from "./create-room-dialog/create-room-dialog.component";
@NgModule({
declarations: [
AppComponent,
LoginComponent,
PrivateComponent,
ChatComponent,
MessageComponent,
RegisterComponent,
ChangePasswordComponent,
NavbarComponent,
CreateRoomDialogComponent,
AddMemberDialogComponent,
RemoveMemberDialogComponent
GeneralComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
CommonModule,
ReactiveFormsModule,
AppRoutingModule,
NavbarModule,
WavesModule,
ButtonsModule,
IconsModule,
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule,
BrowserAnimationsModule,
MatSortModule,
MatButtonModule,
MatDialogModule,
MatFormFieldModule,
MatDividerModule
],
providers: [DatePipe],
bootstrap: [AppComponent]

View file

@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuard', () => {
let guard: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
guard = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

View file

@ -1,24 +0,0 @@
import { Injectable } from '@angular/core';
import {ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, CanActivateChild, Router} from '@angular/router';
import { Observable } from 'rxjs';
import {AuthService} from './services/auth/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivateChild {
constructor(private authService: AuthService, private router: Router) {
}
canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if(!this.authService.getLogged()){
this.router.navigate(['login']);
return false;
}
return true;
}
}

View file

@ -1,24 +0,0 @@
<div class="container">
<div class="modal-header">
<h4 class="modal-title">Changer de mot de passe :</h4>
</div>
<form>
<div class="modal-body">
<div class="row">
<div class="col-md-10">
<div class="form-group mb-0">
<input class="form-control" type="password" required="" [(ngModel)]="oldPassword" autocomplete="password-change" id="oldpassword-change" name="oldpassword-name-change" placeholder="old password">
<input class="form-control" type="password" required="" [(ngModel)]="newPassword" autocomplete="password2-change" id="newpassword-change" name="newpassword-name-change" placeholder="new password">
<input class="form-control" type="password" required="" [(ngModel)]="confirmPassword" autocomplete="password2-change" id="confirmpassword-change" name="confirmpassword-name-change" placeholder="confirm password">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input class="btn btn-sm btn-primary" name="button-register" (click)="changePassword()" type="submit" value="Changer">
</div>
</form>
<br>
<div class="alert alert-danger" *ngIf="errorMessage!==''">{{errorMessage}}</div>
<div class="alert-success" *ngIf="succesMessage!==''">{{succesMessage}}</div>
</div>

View file

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

View file

@ -1,41 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {MessageService} from "../services/message/message.service";
import {environment} from "../../environments/environment";
@Component({
selector: 'app-change-password',
templateUrl: './change-password.component.html',
styleUrls: ['./change-password.component.scss']
})
export class ChangePasswordComponent implements OnInit {
username = sessionStorage.getItem('login');
oldPassword = '';
newPassword = '';
confirmPassword = '';
errorMessage = '';
succesMessage = '';
constructor(private messageService: MessageService) { }
ngOnInit(): void {
}
changePassword(): void {
console.log(this.username);
if(this.newPassword !== this.confirmPassword){
this.errorMessage = 'Les mots de passe ne sont pas identiques.';
}
else {
this.messageService.sendMessage(environment.urlCL,"changePassword",{username: this.username, password: this.oldPassword, newpassword: this.confirmPassword}).subscribe(data => {
if (data.status !== 'ok') {
this.succesMessage = '';
this.errorMessage = data.data.reason;
} else {
this.errorMessage = '';
this.succesMessage = data.data;
}
});
}
}
}

View file

@ -1 +0,0 @@
<app-private></app-private>

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChatComponent } from './chat.component';
describe('ChatComponent', () => {
let component: ChatComponent;
let fixture: ComponentFixture<ChatComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChatComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChatComponent);
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-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss']
})
export class ChatComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View file

@ -1,13 +0,0 @@
<h1 mat-dialog-title>New room</h1>
<mat-divider></mat-divider>
<br>
<div mat-dialog-content>
<p>Saisissez un nouveau nom de room</p>
<input matInput [(ngModel)]="newRoomName" class="w-100">
</div>
<br>
<div class="alert alert-danger w-100" *ngIf="errorMessage!==''"><span class="font-weight-bold">Erreur : </span>{{errorMessage}}</div>
<div mat-dialog-actions class="float-right">
<button mat-raised-button color="accent" class="mb-2" (click)="onNoClick()">Fermer</button>
<button mat-raised-button color="primary" class="mb-2" (click)="onCreateRoom()" cdkFocusInitial>Créer la room</button>
</div>

View file

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

View file

@ -1,42 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MessageService} from "../services/message/message.service";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {environment} from "../../environments/environment";
export interface CreateRoomDialogData {
owner: string;
}
@Component({
selector: 'app-create-room-dialog',
templateUrl: './create-room-dialog.component.html',
styleUrls: ['./create-room-dialog.component.scss']
})
export class CreateRoomDialogComponent{
newRoomName = '';
errorMessage = '';
constructor(
public dialogRef: MatDialogRef<CreateRoomDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: CreateRoomDialogData,
@Inject(MessageService) private messageService: MessageService) { }
onNoClick(): void {
this.dialogRef.close();
}
onCreateRoom(){
this.messageService.sendMessage(environment.urlCPR, "conversations/newRoom", {owner: this.data.owner, roomName: this.newRoomName}).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
this.errorMessage = data.data.reason;
}
else{
this.dialogRef.close({
data: data.data
});
}
});
}
}

View file

@ -0,0 +1,52 @@
<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">{{username}}</p>
</div>
</div>
</div>
<div class="col-md-8">
<div class="chat-header">
<p class="username">General Chat</p>
</div>
<div class="chat-body">
<ul #ulMessages id="messages">
</ul>
</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)]="msg"/>
</div>
</div>
<div class="col-md-2 text-center align-self-center">
<button class="btn btn-primary btn-bm px-3 " (click)="sendButtonClick()">Envoyer</button>
</div>
</div>
</div>
</div>
</div>
</div>

View file

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

View file

@ -0,0 +1,61 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {ChatInfo, ChatService} from "../services/chat/chat.service";
import {environment} from "../../environments/environment";
import {DatePipe} from "@angular/common";
import {MessageService} from "../services/message/message.service";
@Component({
selector: 'app-general',
templateUrl: './general.component.html',
styleUrls: ['./general.component.scss']
})
export class GeneralComponent implements OnInit {
public username = sessionStorage.getItem('login');
private room = 'general';
public msg = '';
// @ts-ignore
@ViewChild('ulMessages') ulMsg: ElementRef;
constructor(private chatservice: ChatService, private pipe: DatePipe, private messageservice: MessageService) {}
ngOnInit() {
console.log('General working');
this.messageservice.sendMessage(environment.urlCL,'getUsers', {username: this.username}).subscribe(
data => {
if (data.status !== 'ok'){
console.log(data.data.reason);
}
else{
console.log(data.data);
}
}
);
this.chatservice.setUrl(environment.urlCG);
this.chatservice.setRoom(this.room);
this.chatservice.onNewMessage(this.room).subscribe((infos: ChatInfo[]) => {
for(let data of infos){
if(data !== undefined && data.date !== undefined){
if(data.username === 'Server'){
this.ulMsg.nativeElement.insertAdjacentHTML('beforeend', '<li><span class="text-danger">'+data.message+'</span></li>');
}
else{
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>');
}
}
}
window.scrollTo(0, document.body.scrollHeight);
});
}
sendButtonClick(){
console.log('Button working');
if(this.msg && this.username){
this.chatservice.sendMessage(this.username, this.room, this.msg);
console.log(this.username, this.room, this.msg);
this.msg = '';
}
}
}

View file

@ -2,22 +2,28 @@
<div class="modal-header">
<h4 class="modal-title">Veuillez-vous authentifier :</h4>
</div>
<form>
<div class="modal-body">
<div class="row">
<div class="col-md-10">
<div class="form-group mb-0">
<input class="form-control" type="text" required="" [(ngModel)]="login" autocomplete="login" id="login" name="login" placeholder="login">
<input class="form-control" type="password" required="" [(ngModel)]="password" autocomplete="password" id="password" name="password" placeholder="password">
<input type="text"
placeholder="Entrez votre login"
class="form-control"
[(ngModel)]="login">
<input type="text"
placeholder="Entrez votre password"
class="form-control"
[(ngModel)]="password">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input class="btn btn-sm btn-primary" name="button-connexion" (click)="showCredentials()" type="submit" value="Se connecter">
<button class="btn btn-sm btn-primary" (click) = "showCredentials()">Connexion Privée</button>
<button class="btn btn-sm btn-primary" (click) = "showCredentials()">Connexion Générale</button>
</div>
</form>
<br>
<div class="alert alert-danger" *ngIf="errorMessage!==''">{{errorMessage}}</div>
<p class="alert alert-danger" role="alert" *ngIf="errorMessage !== ''">{{errorMessage}}</p>
</div>
<app-register></app-register>

View file

@ -20,16 +20,16 @@ export class LoginComponent implements OnInit {
}
showCredentials(): void {
// console.log('Login :', this.login);
// console.log('Password :', this.password);
console.log('Login :', this.login);
console.log('Password :', this.password);
this.auth.sendAuthentication(this.login, this.password).subscribe(data => {
this.auth.finalizeAuthentication(data);
if (this.auth.getLogged()) {
if (this.auth.islog === true) {
sessionStorage.setItem('login', this.login);
this.router.navigateByUrl('/chat');
this.router.navigateByUrl('/general');
} else {
this.errorMessage = data.data.reason;
//console.log(this.errorMessage);
console.log(this.errorMessage);
}
});

View file

@ -1,28 +0,0 @@
<div class="chat-container">
<div class="chat-header bg-primary">
<p class="username" *ngIf="room !== 'general'">{{room}}</p>
<p class="username" *ngIf="room === 'general'">General</p>
<p class="username" *ngIf="room === ''">PLEASE CHOOSE A ROOM</p>
<div class="pull-right">
<input *ngIf="room !== '' && room !== 'general' && typeRoom === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="addMember()" type="submit" value="+">
<input *ngIf="room !== '' && room !== 'general' && typeRoom === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="removeMember()" type="submit" value="-">
<input *ngIf="room !== '' && room !== 'general' && typeRoom === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="listMembers()" type="submit" value="Members">
</div>
</div>
<div #scrollContainer class="chat-body" >
<ul #ulMessages id="messages">
</ul>
</div>
<div class="chat-footer">
<div class="row col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
<div class="col-md-10">
<div class="form-group mb-0">
<input type="text" placeholder="Entrez votre message" (keydown.enter)="sendButtonClick()" class="form-control" [(ngModel)]="msg"/>
</div>
</div>
<div class="col-md-2 text-center align-self-center">
<button class="btn btn-primary btn-bm px-3" (click)="sendButtonClick()" id="button-send">Envoyer</button>
</div>
</div>
</div>
</div>

View file

@ -1,6 +0,0 @@
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #007bff; }
.chat-container .chat-header {
height: 60px;
}

View file

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

View file

@ -1,224 +0,0 @@
import {Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core';
import {ChatInfo, ChatService} from "../services/chat/chat.service";
import {DatePipe} from "@angular/common";
import {environment} from "../../environments/environment";
import {MessageService} from "../services/message/message.service";
import {MatDialog} from "@angular/material/dialog";
import {AddMemberDialogComponent} from "../add-member-dialog/add-member-dialog.component";
import {RemoveMemberDialogComponent} from "../remove-member-dialog/remove-member-dialog.component";
@Component({
selector: 'app-message',
templateUrl: './message.component.html',
styleUrls: ['./message.component.scss']
})
export class MessageComponent implements OnInit, OnChanges {
public username = sessionStorage.getItem('login');
public msg = '';
public roomId = '';
// @ts-ignore
@Input() room: string;
// @ts-ignore
@Input() typeRoom: boolean;
// @ts-ignore
@ViewChild('ulMessages') ulMsg: ElementRef;
// @ts-ignore
@ViewChild('scrollContainer') scrollContainer: ElementRef;
constructor(private chatservice: ChatService, private pipe: DatePipe, private messageservice: MessageService, public dialog: MatDialog) {
}
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges){
//console.log('ngOnChange :'+this.room);
this.chatservice.leaveRoom();
// @ts-ignore
document.getElementById('messages').innerHTML = '';
if(this.room === 'General' || this.room === 'general'){
this.room = 'general';
this.chatservice.setUrl(environment.urlCG);
this.chatservice.setRoom(this.room);
this.chatServiceOnNewMessage(this.room);
}
else if(this.room !== ''){
let dataMessage;
if(this.typeRoom){
dataMessage = {
member: this.username,
roomName: this.room,
}
}
else{
dataMessage = {
sender: this.username,
receiver: this.room,
}
}
this.chatservice.setUrl(environment.urlCPR);
this.messageservice.sendMessage(environment.urlCPR,"conversations/getConv",dataMessage).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
} else {
if(data.data === null){
this.messageservice.sendMessage(environment.urlCPR, "conversations/newConv", {
sender: this.username,
receiver: this.room,
}).subscribe(data2 => {
if (data2.status !== 'ok') {
console.log(data2.data.reason);
} else {
//console.log(data.data);
this.roomId = data2.data._id;
this.chatservice.setRoom(this.roomId)
this.chatServiceOnNewMessage(this.roomId);
}
});
}
else{
if(typeof data.data !== 'undefined' && typeof data.data._id !== 'undefined'){
//console.log(data.data);
this.roomId = data.data._id;
this.chatservice.setRoom(this.roomId);
this.chatServiceOnNewMessage(this.roomId);
}
}
}
});
}
}
chatServiceOnNewMessage(room: string){
this.chatservice.onNewMessage(room).subscribe((infos: ChatInfo[]) => {
for(let data of infos){
if(data !== undefined && data.date !== undefined){
if(data.username === 'Server'){
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-danger">'+data.message+'</span></li>');
}
else{
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.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
});
}
sendButtonClick(){
//console.log('Button working');
if(this.msg && this.username && this.room){
if(this.room === 'general'){
//console.log("sendButton general");
this.chatservice.sendMessage(this.username, this.room, this.msg);
//console.log(this.username, this.room, this.msg);
}
else{
//console.log("sendButton private");
this.chatservice.sendMessage(this.username, this.roomId, this.msg);
//console.log(this.username, this.roomId, this.msg);
}
this.msg = '';
}
}
addMember(){
let dataMessage;
if(this.typeRoom){
dataMessage = {
member: this.username,
roomName: this.room,
}
}
else{
dataMessage = {
sender: this.username,
receiver: this.room,
}
}
this.messageservice.sendMessage(environment.urlCPR, "conversations/getConv", dataMessage).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
} else {
this.roomId = data.data._id;
const dialogRef = this.dialog.open(AddMemberDialogComponent, {
width: '50%',
data: {owner: this.username, conversationid: this.roomId}
});
dialogRef.afterClosed().subscribe(data2 => {
console.log(data2);
this.listMembers();
});
}
});
}
removeMember(){
let dataMessage;
if(this.typeRoom){
dataMessage = {
member: this.username,
roomName: this.room,
}
}
else{
dataMessage = {
sender: this.username,
receiver: this.room,
}
}
this.messageservice.sendMessage(environment.urlCPR, "conversations/getConv", dataMessage).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
} else {
this.roomId = data.data._id;
const dialogRef = this.dialog.open(RemoveMemberDialogComponent, {
width: '50%',
data: {owner: this.username, conversationid: this.roomId}
});
dialogRef.afterClosed().subscribe(data2 => {
console.log(data2);
this.listMembers();
});
}
});
}
listMembers(){
let dataMessage;
if(this.typeRoom){
dataMessage = {
member: this.username,
roomName: this.room,
}
}
else{
dataMessage = {
sender: this.username,
receiver: this.room,
}
}
this.messageservice.sendMessage(environment.urlCPR, "conversations/getConv", dataMessage).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
} else {
this.roomId = data.data._id;
this.messageservice.sendMessage(environment.urlCPR, "conversations/getMembers", {conversationid: this.roomId}).subscribe(data2 => {
if (data2.status !== 'ok') {
console.log(data2.data.reason);
} else {
if(typeof data2.data[0] !== 'undefined'){
this.ulMsg.nativeElement.insertAdjacentHTML('beforeend', '<li><span class="text-danger">Membres: '+data2.data[0].members+'</span></li>');
}
}
});
}
});
}
}

View file

@ -1,15 +0,0 @@
<nav class="navbar navbar-expand-lg navbar-light bg-primary">
<a class="navbar-brand" href="/chat">Chat Polytech</a>
<ul class="navbar-nav ml-auto" *ngIf="true;">
<!-- Dropdown -->
<li class="nav-item dropdown" dropdown>
<a role="button" data-toggle="dropdown" type="button" class="nav-link dropdown-toggle ">Profile</a>
<div class="dropdown-menu dropdown-menu-right dropdown dropdown-primary" role="menu">
<a class="dropdown-item waves-light" href="changePassword">Change password</a>
<!-- <div class="divider dropdown-divider"></div>-->
<a class="dropdown-item waves-light" href="#" (click)="logout()">Log out</a>
</div>
</li>
</ul>
</nav>

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,24 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {AuthService} from "../services/auth/auth.service";
import {Router} from "@angular/router";
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
constructor(public authservice: AuthService, private router: Router) { }
ngOnInit(): void {
}
logout(){
//console.log('connecté ? '+this.authservice.getLogged());
console.log('test');
this.authservice.setLogged(false);
this.router.navigate(['/']);
}
}

View file

@ -1,24 +0,0 @@
<div class="container col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
<div class="row">
<div class="col-xl-4 col-lg-4 col-md-4 col-sm-3 col-3">
<br>
<div class="btn-group">
<input *ngIf="privateRoomActivate === false" class="btn btn-sm btn-primary" name="button-change-private" (click)="changeListPrivate()" type="submit" value="Private Room">
<input *ngIf="privateRoomActivate === false" class="btn btn-sm btn-primary" name="button-change-private" (click)="changeListGeneral()" type="submit" value="Actualiser">
<input *ngIf="privateRoomActivate === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="changeListGeneral()" type="submit" value="Home Room">
<input *ngIf="privateRoomActivate === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="newRoom()" type="submit" value="New Room">
<input *ngIf="privateRoomActivate === true" class="btn btn-sm btn-primary" name="button-change-private" (click)="changeListPrivate()" type="submit" value="Actualiser">
</div>
<div #userList class="user-list-card" id="userList" (click)="selectRoom($event)">
<div class="user-card">
<img src="../../assets/image/general.png" height="25" width="25" />
<p class="username">General</p>
</div>
</div>
</div>
<div class="col-xl-8 col-lg-8 col-md-8 col-sm-9 col-9">
<br>
<app-message [room]="roomSelected" [typeRoom]="privateRoomActivate"></app-message>
</div>
</div>
</div>

View file

@ -1,9 +0,0 @@
.btn-group{
height: 60px;
padding-bottom: 10px;
display: flex;
flex-direction: row;
}
.user-list-card{
height: calc(100% - 80px);
}

View file

@ -1,91 +0,0 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {environment} from "../../environments/environment";
import {ChatService} from "../services/chat/chat.service";
import {MessageService} from "../services/message/message.service";
import {CreateRoomDialogComponent} from "../create-room-dialog/create-room-dialog.component";
import {MatDialog} from "@angular/material/dialog";
@Component({
selector: 'app-private',
templateUrl: './private.component.html',
styleUrls: ['./private.component.scss']
})
export class PrivateComponent implements OnInit {
public username = sessionStorage.getItem('login');
public roomSelected = 'general';
public privateRoomActivate = false;
// @ts-ignore
@ViewChild('userList') userList: ElementRef;
constructor(private chatservice: ChatService, private messageservice: MessageService, public dialog: MatDialog) {}
ngOnInit(): void {
this.changeListGeneral();
}
selectRoom(event: Event): void {
if((event.target as Element).className !== 'user-list-card'){
const room = (event.target as Element).textContent;
//console.log(room);
if(room !== '' && room !== null) {
this.roomSelected = room;
}
}
}
changeListPrivate(): void{
this.roomSelected = '';
this.privateRoomActivate = true;
// @ts-ignore
document.getElementById('userList').innerHTML = '';
this.messageservice.sendMessage(environment.urlCPR,'conversations/getRooms', {member: this.username}).subscribe(
data => {
if (data.status !== 'ok'){
console.log(data.data.reason);
}
else{
console.log(data.data);
for(let user of data.data){
if(user !== undefined && user.roomName !== undefined){
this.userList.nativeElement.insertAdjacentHTML('beforeend', '<div class="user-card" [id]="'+user.roomName+'"><img src="../../assets/image/room.png" height="25" width="25"/><p class="username">'+user.roomName+'</p></div>');
}
}
}
}
);
}
changeListGeneral(): void{
this.roomSelected = 'general';
this.privateRoomActivate = false;
// @ts-ignore
document.getElementById('userList').innerHTML = '<div class="user-card"><img src="../../assets/image/general.png" height="25" width="25"/><p class="username">General</p></div>';
this.messageservice.sendMessage(environment.urlCL,'getUsers', {username: this.username}).subscribe(
data => {
if (data.status !== 'ok'){
console.log(data.data.reason);
}
else{
for(let user of data.data){
if(user !== undefined && user.login !== undefined){
this.userList.nativeElement.insertAdjacentHTML('beforeend', '<div class="user-card" [id]="'+user.login+'"><img src="../../assets/image/user.png" height="25" width="25"/><p class="username">'+user.login+'</p></div>');
}
}
}
}
);
}
newRoom(): void{
const dialogRef = this.dialog.open(CreateRoomDialogComponent, {
width: '50%',
data: {owner: this.username}
});
dialogRef.afterClosed().subscribe(data => {
console.log(data);
this.changeListPrivate();
});
}
}

View file

@ -1,24 +0,0 @@
<div class="container">
<div class="modal-header">
<h4 class="modal-title">Vous pouvez aussi vous enregistrer ici</h4>
</div>
<form>
<div class="modal-body">
<div class="row">
<div class="col-md-10">
<div class="form-group mb-0">
<input class="form-control" type="text" required="" [(ngModel)]="login2" autocomplete="login-register" id="login-register" name="login-name-register" placeholder="login">
<input class="form-control" type="password" required="" [(ngModel)]="password2" autocomplete="password-register" id="password-register" name="password-name-register" placeholder="password">
<input class="form-control" type="password" required="" [(ngModel)]="password4" autocomplete="password2-register" id="password2-register" name="password2-name-register" placeholder="confirmation password">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input class="btn btn-sm btn-primary" name="button-register" (click)="register()" type="submit" value="S'enregistrer">
</div>
</form>
<br>
<div class="alert alert-danger" *ngIf="errorMessage!==''">{{errorMessage}}</div>
<div class="alert-success" *ngIf="succesMessage!==''">{{succesMessage}}</div>
</div>

View file

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

View file

@ -1,42 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {MessageService} from "../services/message/message.service";
import {environment} from "../../environments/environment";
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit {
login2 = '';
password2 = '';
password4 = '';
errorMessage = '';
succesMessage = '';
constructor(private messageService: MessageService) { }
ngOnInit(): void {
}
register(): void {
if(this.password4 !== this.password2){
console.log("error");
this.errorMessage = 'Les mots de passe ne sont pas identiques.';
}
else {
this.messageService.sendMessage(environment.urlCL,"register",{username: this.login2, password: this.password2}).subscribe(data => {
if (data.status !== 'ok') {
this.succesMessage = '';
this.errorMessage = data.data.reason;
} else {
//console.log(data.data);
this.errorMessage = '';
this.succesMessage = data.data;
}
});
}
}
}

View file

@ -1,13 +0,0 @@
<h1 mat-dialog-title>Retirer un membre</h1>
<mat-divider></mat-divider>
<br>
<div mat-dialog-content>
<p>Saisissez un nouveau nom d'utilisateur à retirer à la room</p>
<input matInput [(ngModel)]="memberName" class="w-100">
</div>
<br>
<div class="alert alert-danger w-100" *ngIf="errorMessage!==''"><span class="font-weight-bold">Erreur : </span>{{errorMessage}}</div>
<div mat-dialog-actions class="float-right">
<button mat-raised-button color="accent" class="mb-2" (click)="onNoClick()">Fermer</button>
<button mat-raised-button color="primary" class="mb-2" (click)="onDeleteMember()" cdkFocusInitial>Retirer le membre</button>
</div>

View file

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

View file

@ -1,40 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../services/message/message.service";
import {environment} from "../../environments/environment";
import {AddMemberDialogData} from "../add-member-dialog/add-member-dialog.component";
@Component({
selector: 'app-remove-member-dialog',
templateUrl: './remove-member-dialog.component.html',
styleUrls: ['./remove-member-dialog.component.scss']
})
export class RemoveMemberDialogComponent {
memberName = '';
errorMessage = '';
constructor(
public dialogRef: MatDialogRef<RemoveMemberDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: AddMemberDialogData,
@Inject(MessageService) private messageService: MessageService) { }
onNoClick(): void {
this.dialogRef.close();
}
onDeleteMember(){
this.messageService.sendMessage(environment.urlCPR, "conversations/removeRoomMember", {owner: this.data.owner, conversationid: this.data.conversationid, member: this.memberName}).subscribe(data => {
if (data.status !== 'ok') {
console.log(data.data.reason);
this.errorMessage = data.data.reason;
}
else{
this.dialogRef.close({
data: data.data
});
}
});
}
}

View file

@ -10,10 +10,11 @@ import {environment} from "../../../environments/environment";
export class AuthService {
// @ts-ignore
private islog: boolean;
islog: boolean;
// @ts-ignore
public currentUser;
constructor(private messageService: MessageService) {
}
constructor(private messageService: MessageService) { }
getLogged(): boolean {
return this.islog;

View file

@ -9,6 +9,7 @@ export interface ChatInfo {
message: string
}
@Injectable({
providedIn: 'root'
})
@ -30,7 +31,6 @@ export class ChatService {
setRoom(room: string){
this.room = room;
this.joinRoom(this.room);
}
setSocket(){
@ -39,42 +39,17 @@ export class ChatService {
});
}
sendMessage(sender: string | null, room: string, message: string) {
if(room === 'general' || room === 'General'){
sendMessage(username: string | null, room: string, message: string) {
// @ts-ignore
this.socket.emit(room, {
username: sender,
username: username,
date: new Date(),
room: room,
message: message
});
}
else{
//console.log('sendMessage private: ',sender,room,message);
// @ts-ignore
this.socket.emit('privateroom', {
sender: sender,
room: room,
date: new Date(),
message: message
});
}
}
joinRoom(room: string): void{
//@ts-ignore
this.socket.emit('joinroom', {
room: room
});
}
leaveRoom(): void {
// @ts-ignore
this.socket?.disconnect();
}
onNewMessage(room: string): Observable<ChatInfo[]> {
//console.log('onNewMessage: ',room);
return new Observable(observer => {
// @ts-ignore
this.socket.on(room, (data: ChatInfo[]) => {

View file

@ -25,3 +25,4 @@ export class MessageService {
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,6 +1,3 @@
export const environment = {
production: true,
urlCL: 'http://localhost:3000',
urlCG: 'http://localhost:3001',
urlCPR: 'http://localhost:3002'
production: true
};

View file

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

View file

@ -3,10 +3,9 @@ body {
}
.container-fluid {
padding-left: 5vh;
padding-right: 5vh;
padding-top: 1vh;
padding: 50px 200px;
overflow: hidden;
background-color: #87CEEB;
}
.user-list-card {
@ -14,8 +13,7 @@ body {
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
height: calc(100vh - 100px);
padding: 0;
overflow-y: auto;
padding: 10px;
.user-card {
display: flex;
@ -31,7 +29,6 @@ body {
font-weight: 500;
margin-bottom: 0;
display: flex;
margin-left: 5px;
justify-content: center;
align-items: center;
}
@ -50,9 +47,13 @@ body {
position: relative;
overflow: hidden;
.chat-header {
}
.chat-header {
height: 70px;
background-color: steelblue;
border-radius: 10px;
background-color: #E5E5E5;
display: flex;
justify-content: flex-start;
align-items: center;
@ -61,37 +62,29 @@ body {
font-size: 20px;
font-weight: 500;
margin-bottom: 0;
margin-left: 20px;
display: flex;
margin-left: 5px;
justify-content: center;
align-items: center;
}
}
}
.chat-body {
.chat-body {
background-color: white;
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
height: 76vh;
border-radius: 10px;
height: calc(89.5vh - 89.5px);
overflow-y: auto;
}
}
.chat-footer {
position: absolute;
.chat-footer {
border-radius: 10px;
bottom: 0;
left: 0;
right: 0;
background-color: #EDEDED;
padding: 10px 20px;
width: auto;
#button {
size: auto;
}
}
}
.modal-footer{
.modal-footer {
display: block;
}