Compare commits

..

94 commits
test ... master

Author SHA1 Message Date
Yûki Vachot
4ecd7867b0 Update auth.js 2021-06-06 14:48:04 +02:00
Yûki Vachot
438f478541 Update auth.js 2021-06-06 14:47:43 +02:00
Yûki Vachot
92d359b282 Update docker-compose.yml 2021-06-06 14:47:10 +02:00
Yûki Vachot
c9fb831fbb Add Instructions for the professor 2021-06-06 14:43:00 +02:00
Yûki Vachot
837a7391e6 Update server.js 2021-06-06 14:04:56 +02:00
Yûki Vachot
6b9684c6e1 Update server.js 2021-06-06 14:04:32 +02:00
NyxiumYuuki
34a5f703ea Last commit ? 2021-06-06 11:40:31 +02:00
NyxiumYuuki
75060a0997 Add host listening to all addresses including docker allocating on a docker network 2021-06-06 11:40:31 +02:00
NyxiumYuuki
785560b666 Host change to docker service name 2021-06-06 11:40:31 +02:00
NyxiumYuuki
fa14a1c149 Budgets change cause of frontend build js script size 2021-06-06 11:40:31 +02:00
NyxiumYuuki
2a5bf74e0e NODE_ENV change to production 2021-06-06 11:40:31 +02:00
NyxiumYuuki
1b30d725f1 Remove notification service 2021-06-06 11:40:31 +02:00
NyxiumYuuki
c53c80d8a2 Add prod variables 2021-06-06 11:40:31 +02:00
NyxiumYuuki
8d16fd0e73 Add fixtures 2021-06-06 11:40:31 +02:00
vankhaiphan
9d5bba8f20 fix path to icon general room 2021-06-06 10:09:18 +02:00
vankhaiphan
737b284865 fix path to icon general room 2021-06-06 10:07:19 +02:00
vankhaiphan
c6716d9280 fix path to icon general room 2021-06-06 10:02:24 +02:00
NyxiumYuuki
685a00db49 Add & Remove Members from non host errors added 2021-06-02 09:40:41 +02:00
vankhaiphan
ae3c3456c5 add css for message.componenet and private.component - error when insert group icon for general room 2021-06-02 09:23:16 +02:00
NyxiumYuuki
febf812963 Debug room was not changed so we could send messages from last room 2021-06-01 23:03:42 +02:00
NyxiumYuuki
471225f7fa Debug room was not changed so we could send messages from last room 2021-06-01 23:03:36 +02:00
NyxiumYuuki
494565fecd Debug two rooms were sometimes created 2021-06-01 22:59:27 +02:00
NyxiumYuuki
9210ff9210 Date added on server messages 2021-06-01 22:43:12 +02:00
NyxiumYuuki
aa4fc113a1 getConv updated for custom private room + getMembers, newRoom added 2021-06-01 22:38:28 +02:00
NyxiumYuuki
fcf88e3cde New Room dialog added 2021-06-01 22:37:37 +02:00
NyxiumYuuki
5f6535e7c9 Add test register 2021-06-01 22:37:11 +02:00
NyxiumYuuki
4e5197d4bb function now used cause of private variable 2021-06-01 22:36:57 +02:00
NyxiumYuuki
6b0cb128b2 Create components + Material Modules added 2021-06-01 22:36:38 +02:00
NyxiumYuuki
7329ee5fe0 private added + space removed 2021-06-01 22:36:08 +02:00
NyxiumYuuki
6c94581615 changed password added (not verify but should work) 2021-06-01 22:35:37 +02:00
NyxiumYuuki
8213823e9f space removed 2021-06-01 22:35:10 +02:00
NyxiumYuuki
655eeada53 Add roomName for custom private rooms 2021-06-01 22:34:57 +02:00
NyxiumYuuki
577abeb65c Add messages 2021-06-01 22:34:39 +02:00
NyxiumYuuki
22b137931d Dialog of Add, Remove + Member list in chat 2021-06-01 22:34:28 +02:00
NyxiumYuuki
95c08668f7 Add logout button (not working, no AuthGuard) 2021-06-01 22:33:41 +02:00
NyxiumYuuki
fe7b142a5c Wrong spelling corrected 2021-06-01 22:32:49 +02:00
NyxiumYuuki
540539b9fa Indigo Pink Angular Material added 2021-06-01 22:32:17 +02:00
NyxiumYuuki
a126dab147 AuthGuard added (not working) 2021-06-01 22:31:58 +02:00
NyxiumYuuki
12b82d84c1 AuthGuard added 2021-06-01 22:31:39 +02:00
NyxiumYuuki
bfa6cc0855 Dialog Remove Member 2021-06-01 22:31:27 +02:00
NyxiumYuuki
8fe42de825 Dialog Create Room 2021-06-01 22:31:11 +02:00
NyxiumYuuki
916ccddd7d Dialog Add Member 2021-06-01 22:30:56 +02:00
NyxiumYuuki
62a4744e7d Merge remote-tracking branch 'origin/master' 2021-06-01 17:47:34 +02:00
NyxiumYuuki
cdb90cdcfb errors added + getRooms, newRoom, addRoomMember, removeRoomMember 2021-06-01 17:46:48 +02:00
NyxiumYuuki
b97e81d970 Owner field added 2021-06-01 17:44:28 +02:00
vankhaiphan
ee8ac3a18f dropdown change_password and logout 2021-06-01 16:57:26 +02:00
NyxiumYuuki
9e1ce83b81 Merge remote-tracking branch 'origin/master' 2021-06-01 15:58:11 +02:00
NyxiumYuuki
e271c9ea14 Show succesful messa 2021-06-01 15:58:04 +02:00
NyxiumYuuki
bb31981920 Add succesful message 2021-06-01 15:57:48 +02:00
NyxiumYuuki
f36a48748b Change size chat 2021-06-01 15:57:32 +02:00
NyxiumYuuki
67368efd2d Add Navbar modules 2021-06-01 15:56:43 +02:00
NyxiumYuuki
c84a17b47e Add bootstrap.min.js / jquery.min.js / popper.min.js 2021-06-01 15:56:29 +02:00
NyxiumYuuki
aaf51632b4 Tests new navbar with dropdown (not working) 2021-06-01 15:55:56 +02:00
NyxiumYuuki
d20c152c49 Remove former navbar 2021-06-01 15:55:30 +02:00
vankhaiphan
968e2b024a change responsive web + port private room in docker-compose.yml 2021-06-01 15:48:52 +02:00
NyxiumYuuki
36016a1a0b Il manquait la moitié des components :d 2021-05-31 23:11:24 +02:00
NyxiumYuuki
c5406006da updated 2021-05-31 23:09:58 +02:00
NyxiumYuuki
67a37d16ec mongodb privateroom 2021-05-31 08:22:23 +02:00
NyxiumYuuki
64b35b5fe6 docker privateroom 2021-05-31 08:22:05 +02:00
NyxiumYuuki
ed40b33b54 Pretty + server messages 2021-05-31 02:51:28 +02:00
NyxiumYuuki
d103fec09c add send_message with _id 2021-05-31 02:39:55 +02:00
NyxiumYuuki
58c324ff42 Improve libility 2021-05-31 02:39:20 +02:00
NyxiumYuuki
06653deac7 Add joinRoom to get all messages coming from the room + conversationId 2021-05-31 02:39:02 +02:00
NyxiumYuuki
105cbf18f6 Add joinRoom to get all messages coming from the room 2021-05-31 02:38:26 +02:00
NyxiumYuuki
7a19bfbe69 versionKey debug 2021-05-31 00:39:42 +02:00
NyxiumYuuki
2d95b38a85 chat service checked 2021-05-31 00:31:27 +02:00
NyxiumYuuki
c00d9ba51d service-privateroom 2021-05-31 00:30:20 +02:00
NyxiumYuuki
bc6aa6dd28 Delete just for Khai 2021-05-30 23:26:05 +02:00
NyxiumYuuki
0533dae04a container name of privateroom database changed 2021-05-30 23:24:44 +02:00
NyxiumYuuki
18eb60894c change mongodb connection + add require auth 2021-05-30 23:19:14 +02:00
NyxiumYuuki
52583f1f43 add mongodb-privateroom 2021-05-30 23:18:45 +02:00
NyxiumYuuki
374e000f5b add connection 2021-05-30 23:18:19 +02:00
NyxiumYuuki
68f48b0c09 add connection 2021-05-30 23:18:06 +02:00
NyxiumYuuki
ca057706a5 change port and add conversations documents 2021-05-30 23:17:53 +02:00
NyxiumYuuki
f11941590c remove space 2021-05-30 23:17:31 +02:00
NyxiumYuuki
7b351d8b09 add private room 2021-05-30 23:16:50 +02:00
NyxiumYuuki
5d46765145 updated 2021-05-30 23:16:33 +02:00
Yûki Vachot
e06c332bd1 Merge branch 'frontend_test_general' into 'master'
Frontend test general

See merge request groupe100idee/chatless!5
2021-05-30 22:30:09 +02:00
NyxiumYuuki
50d06cc817 change username 2021-05-30 22:35:12 +02:00
NyxiumYuuki
35f47457c2 add private room 2021-05-30 22:35:04 +02:00
NyxiumYuuki
ae0da17533 data already in data 2021-05-30 22:34:55 +02:00
vankhaiphan
0625a3929f add socker.io fore service-private 2021-05-30 22:34:41 +02:00
vankhaiphan
6818e0bb47 change port mongodbHost for service-privateroom 2021-05-30 20:56:42 +02:00
vankhaiphan
36e6596c78 private room but socketio not ready 2021-05-30 20:55:00 +02:00
NyxiumYuuki
0348ca1ecc Updated Component 2021-05-30 18:29:15 +02:00
NyxiumYuuki
aa2f6e0ecc Updated routes 2021-05-30 18:29:02 +02:00
NyxiumYuuki
6f7e465b86 Errormessage added + type and required added 2021-05-30 18:28:48 +02:00
NyxiumYuuki
4b8337c4f6 Errormessage added + type and required added 2021-05-30 18:27:32 +02:00
NyxiumYuuki
0034b66391 General renamed to message component 2021-05-30 18:25:55 +02:00
Yûki Vachot
c652958324 Merge branch 'frontend_test_general' into 'master'
Frontend test general

See merge request groupe100idee/chatless!4
2021-05-30 18:24:25 +02:00
NyxiumYuuki
5027493910 Add leaveRoom (socket disconnect) 2021-05-30 18:12:18 +02:00
NyxiumYuuki
def91588a3 Debug chat display 2021-05-30 18:11:44 +02:00
NyxiumYuuki
8547ebf403 add left chat 2021-05-30 11:25:10 +02:00
NyxiumYuuki
c14c46a444 change type input 2021-05-30 11:24:52 +02:00
80 changed files with 5507 additions and 650 deletions

View file

@ -1,5 +1,27 @@
**Projet Chat** **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 : Le but du projet est de fournir un service de chat rudimentaire :
- Une interface utilisateur en web - Une interface utilisateur en web
- Les utilisateurs peuvent s'enregistrer/se connecter/se déconnecter/changer leur mot de passe - Les utilisateurs peuvent s'enregistrer/se connecter/se déconnecter/changer leur mot de passe

View file

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

View file

@ -1,7 +1,8 @@
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://127.0.0.1:27017/', mongodbHost: 'mongodb://mongodb-authentication:27017/',
// mongodbHost: 'mongodb://127.0.0.1:27017/',
charset: 'utf8', charset: 'utf8',
mongodbLogin: '', mongodbLogin: '',
mongodbPassword: '', mongodbPassword: '',

View file

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

View file

@ -18,11 +18,15 @@ function register(login, password){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
mongoDB.collection(config.mongodbUtilisateurs).updateOne( mongoDB.collection(config.mongodbUtilisateurs).updateOne(
{'login': login}, {'login': login},
{$set: { 'login': login, 'password': password}}, {$setOnInsert: { 'login': login, 'password': password}},
{upsert:true},function(err,res){ {upsert:true},function(err,res){
//console.log(res); //console.log(res);
if(res !== undefined){ if(res !== undefined){
resolve(res.upsertedCount === 1); if(typeof res.upsertedId !== 'undefined'){
resolve(res.upsertedId);
}else{
resolve(false);
}
} }
}); });
}); });
@ -42,3 +46,17 @@ function getUsersQuery(username){
} }
module.exports.getUsersQuery = getUsersQuery 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'); const queries = require('./mongodbQueries');
async function register(req,res) { async function register(req,res) {
if (typeof req.body.login === 'undefined') if (typeof req.body.username === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ login'); return sendError(res, 'Vous n\'avez pas envoyé le champ login');
if (typeof req.body.password === 'undefined') if (typeof req.body.password === 'undefined')
return sendError(res, 'Vous n\'avez pas envoyé le champ password'); return sendError(res, 'Vous n\'avez pas envoyé le champ password');
const register = await queries.register(req.body.login, req.body.password); const register = await queries.register(req.body.username, req.body.password);
if (register){ if (register){
console.log('Register : '+req.body.login); console.log('Register : '+req.body.username);
return sendMessage(res, null); return sendMessage(res, 'Successful registration');
} }
else{ else{
return sendError(res, 'Error registering'); return sendError(res, 'Username already taken');
} }
} }
module.exports = register; module.exports = register;

View file

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

View file

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

View file

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

View file

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

View file

@ -11,7 +11,7 @@ const app = express();
const server = http.createServer(app); const server = http.createServer(app);
const io = new Server(server, { const io = new Server(server, {
cors: { cors: {
origin: "http://127.0.0.1:4200", origin: "http://localhost:4200",
methods: ["GET", "POST"], methods: ["GET", "POST"],
credentials: true credentials: true
} }
@ -19,31 +19,53 @@ const io = new Server(server, {
const port = process.env.PORT || 3001; 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://localhost:4200', credentials: true}));
app.use(cookieParser()); app.use(cookieParser());
// app.get('/', (req, res) => {
// res.sendFile(__dirname + '/index.html'); 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'
},
]);
io.on('connection',socket => { io.on('connection',socket => {
let users = {};
auth.getSession(socket.request, function(res){ auth.getSession(socket.request, function(res){
const getUsername = auth.getUsername(res); const getUsername = auth.getUsername(res);
if (getUsername === -1) { if (getUsername === -1) {
console.log('not authenticated',getUsername);
socket.send('error','not authenticated'); socket.send('error','not authenticated');
} }
else{ else{
console.log(`${getUsername} joined the chat.`); console.log(`${new Date()}] ${getUsername} joined the chat.`);
socket.broadcast.emit('general',[{ socket.broadcast.emit('general',[{
username: 'Server', username: 'Server',
date: new Date(), date: new Date(),
channel: 'general', channel: 'general',
message: `${getUsername} joined the chat.` message: `${getUsername} joined the chat.`
}]); }]);
users[socket.id] = getUsername;
messages.find({}, {'_id':0},{sort: {'date':1}},(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){
@ -60,7 +82,7 @@ io.on('connection',socket => {
socket.on('general',function(data){ socket.on('general',function(data){
const username = data.username; const username = data.username;
const date = Date.now(); const date = data.date;
const channel = 'general'; const channel = 'general';
const message = data.message; const message = data.message;
@ -71,7 +93,7 @@ io.on('connection',socket => {
message: message message: message
} }
]).then(function(){ ]).then(function(){
console.log(data, "inserted"); //console.log(data, "inserted");
socket.broadcast.emit('general',[data]); socket.broadcast.emit('general',[data]);
socket.emit('general',[data]); socket.emit('general',[data]);
}).catch(function(error){ }).catch(function(error){
@ -81,12 +103,18 @@ io.on('connection',socket => {
}); });
socket.on("disconnect", function() { socket.on("disconnect", function() {
console.log(`${getUsername} left the chat.`); console.log(`${new Date()}] ${getUsername} left the chat.`);
socket.broadcast.emit('general',[{
username: 'Server',
date: new Date(),
channel: 'general',
message: `${getUsername} left the chat.`
}]);
}); });
} }
}); });
}); });
server.listen(port, () => { server.listen(port,'0.0.0.0', () => {
console.log(`listening on *:${port}/`); console.log (`listening on port ${port}`);
}); });

View file

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

View file

@ -0,0 +1,34 @@
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

@ -0,0 +1,15 @@
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

@ -0,0 +1,13 @@
// 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

@ -0,0 +1,27 @@
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

@ -0,0 +1,30 @@
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

@ -0,0 +1,25 @@
{
"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

@ -0,0 +1,174 @@
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

@ -0,0 +1,143 @@
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,9 +13,11 @@ services:
depends_on: depends_on:
- service-authentication - service-authentication
- service-message - service-message
- service-privateroom
links: links:
- service-authentication - service-authentication
- service-message - service-message
- service-privateroom
service-authentication: service-authentication:
container_name: service-authentication container_name: service-authentication
@ -32,7 +34,7 @@ services:
links: links:
- mongodb-authentication - mongodb-authentication
environment: environment:
NODE_ENV: development NODE_ENV: production
service-message: service-message:
container_name: service-message container_name: service-message
@ -42,13 +44,31 @@ services:
- backend/service-message - backend/service-message
- backend/service-message/node_modules - backend/service-message/node_modules
ports: ports:
- 3001:3000 - 3001:3001
depends_on: depends_on:
- mongodb-message - mongodb-message
links: links:
- mongodb-message - mongodb-message
- service-authentication
environment: environment:
NODE_ENV: development 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
mongodb-authentication: mongodb-authentication:
image: mongo image: mongo
@ -65,3 +85,11 @@ services:
- ./backend/service-message/database:/data/db-message - ./backend/service-message/database:/data/db-message
ports: ports:
- 27020:27017 - 27020:27017
mongodb-privateroom:
image: mongo
container_name: mongodb-privateroom
volumes:
- ./backend/service-privateroom/database:/data/db-privateroom
ports:
- 27021:27017

View file

@ -34,18 +34,23 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"node_modules/bootstrap/scss/bootstrap.scss", "node_modules/bootstrap/scss/bootstrap.scss",
"src/styles.scss" "src/styles.scss"
], ],
"scripts": [] "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"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kb", "maximumWarning": "1mb",
"maximumError": "1mb" "maximumError": "2mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",

File diff suppressed because it is too large Load diff

View file

@ -23,8 +23,13 @@
"@angular/router": "~12.0.1", "@angular/router": "~12.0.1",
"@ng-bootstrap/ng-bootstrap": "^8.0.0", "@ng-bootstrap/ng-bootstrap": "^8.0.0",
"@types/socket.io-client": "^3.0.0", "@types/socket.io-client": "^3.0.0",
"angular-bootstrap-md": "^11.1.0",
"bootstrap": "^4.6.0", "bootstrap": "^4.6.0",
"jquery": "^3.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", "rxjs": "^7.1.0",
"socket.io-client": "^4.1.2", "socket.io-client": "^4.1.2",
"tslib": "^2.1.0", "tslib": "^2.1.0",
@ -35,6 +40,7 @@
"@angular/cli": "~12.0.1", "@angular/cli": "~12.0.1",
"@angular/compiler-cli": "~12.0.1", "@angular/compiler-cli": "~12.0.1",
"@types/jasmine": "~3.6.0", "@types/jasmine": "~3.6.0",
"@types/jquery": "^3.5.5",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
"jasmine-core": "~3.7.0", "jasmine-core": "~3.7.0",
"karma": "~6.3.0", "karma": "~6.3.0",

View file

@ -0,0 +1,13 @@
<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

@ -0,0 +1,25 @@
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

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

View file

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

View file

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

View file

@ -5,23 +5,60 @@ 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 {CommonModule, DatePipe} from "@angular/common"; 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({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
LoginComponent, LoginComponent,
GeneralComponent PrivateComponent,
ChatComponent,
MessageComponent,
RegisterComponent,
ChangePasswordComponent,
NavbarComponent,
CreateRoomDialogComponent,
AddMemberDialogComponent,
RemoveMemberDialogComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
AppRoutingModule,
HttpClientModule, HttpClientModule,
FormsModule, FormsModule,
CommonModule, CommonModule,
ReactiveFormsModule, ReactiveFormsModule,
AppRoutingModule, AppRoutingModule,
NavbarModule,
WavesModule,
ButtonsModule,
IconsModule,
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule,
BrowserAnimationsModule,
MatSortModule,
MatButtonModule,
MatDialogModule,
MatFormFieldModule,
MatDividerModule
], ],
providers: [DatePipe], providers: [DatePipe],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View file

@ -0,0 +1,16 @@
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

@ -0,0 +1,24 @@
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

@ -0,0 +1,24 @@
<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

@ -0,0 +1,25 @@
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

@ -0,0 +1,41 @@
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

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

View file

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

View file

@ -0,0 +1,15 @@
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

@ -0,0 +1,13 @@
<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

@ -0,0 +1,25 @@
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

@ -0,0 +1,42 @@
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

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

View file

@ -20,16 +20,16 @@ export class LoginComponent implements OnInit {
} }
showCredentials(): void { showCredentials(): void {
console.log('Login :', this.login); // console.log('Login :', this.login);
console.log('Password :', this.password); // console.log('Password :', this.password);
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.getLogged()) {
sessionStorage.setItem('login', this.login); sessionStorage.setItem('login', this.login);
this.router.navigateByUrl('/general'); this.router.navigateByUrl('/chat');
} else { } else {
this.errorMessage = data.data.reason; this.errorMessage = data.data.reason;
console.log(this.errorMessage); //console.log(this.errorMessage);
} }
}); });

View file

@ -0,0 +1,28 @@
<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

@ -0,0 +1,6 @@
#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

@ -0,0 +1,25 @@
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

@ -0,0 +1,224 @@
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

@ -0,0 +1,15 @@
<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

@ -0,0 +1,25 @@
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

@ -0,0 +1,24 @@
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

@ -0,0 +1,24 @@
<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

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

View file

@ -0,0 +1,25 @@
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

@ -0,0 +1,91 @@
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

@ -0,0 +1,24 @@
<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

@ -0,0 +1,25 @@
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

@ -0,0 +1,42 @@
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

@ -0,0 +1,13 @@
<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

@ -0,0 +1,25 @@
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

@ -0,0 +1,40 @@
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,11 +10,10 @@ import {environment} from "../../../environments/environment";
export class AuthService { export class AuthService {
// @ts-ignore // @ts-ignore
islog: boolean; private islog: boolean;
// @ts-ignore
public currentUser;
constructor(private messageService: MessageService) { } constructor(private messageService: MessageService) {
}
getLogged(): boolean { getLogged(): boolean {
return this.islog; return this.islog;

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

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

View file

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

View file

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