Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
/node_modules
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,6 @@ Your assignment will be evaluated based on the following factors:
You have 3-4 days from the date you received this assignment to complete and submit it.

Good luck with the assignment! If you have any questions during the development process, feel free to reach out for clarification. Happy coding!

Postman Collection-:
https://documenter.getpostman.com/view/25012702/2s9YJdX3Gx
8 changes: 8 additions & 0 deletions connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const mongoose = require('mongoose');
require('dotenv').config();

const connectDB = (url) => {
return mongoose.connect(url);
};

module.exports = connectDB;
107 changes: 107 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const express = require('express');
const app = express();
const userRoutes = require('./routes/userRoutes')
const User = require('./models/User');
const Message = require('./models/Message')
const rooms = ['general', 'tech', 'finance', 'crypto'];
const cors = require('cors');
const connectDB = require('./connection');
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(cors());

app.use('/users', userRoutes)

const server = require('http').createServer(app);
const PORT = 5001;
const io = require('socket.io')(server, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST']
}
})


async function getLastMessagesFromRoom(room){
let roomMessages = await Message.aggregate([
{$match: {to: room}},
{$group: {_id: '$date', messagesByDate: {$push: '$$ROOT'}}}
])
return roomMessages;
}

function sortRoomMessagesByDate(messages){
return messages.sort(function(a, b){
let date1 = a._id.split('/');
let date2 = b._id.split('/');

date1 = date1[2] + date1[0] + date1[1]
date2 = date2[2] + date2[0] + date2[1];

return date1 < date2 ? -1 : 1
})
}

// socket connection

io.on('connection', (socket)=> {

socket.on('new-user', async ()=> {
const members = await User.find();
io.emit('new-user', members)
})

socket.on('join-room', async(newRoom, previousRoom)=> {
socket.join(newRoom);
socket.leave(previousRoom);
let roomMessages = await getLastMessagesFromRoom(newRoom);
roomMessages = sortRoomMessagesByDate(roomMessages);
socket.emit('room-messages', roomMessages)
})

socket.on('message-room', async(room, content, sender, time, date) => {
const newMessage = await Message.create({content, from: sender, time, date, to: room});
let roomMessages = await getLastMessagesFromRoom(room);
roomMessages = sortRoomMessagesByDate(roomMessages);
// sending message to room
io.to(room).emit('room-messages', roomMessages);
socket.broadcast.emit('notifications', room)
})

app.delete('/logout', async(req, res)=> {
try {
const {_id, newMessages} = req.body;
const user = await User.findById(_id);
user.status = "offline";
user.newMessages = newMessages;
await user.save();
const members = await User.find();
socket.broadcast.emit('new-user', members);
res.status(200).send();
} catch (e) {
console.log(e);
res.status(400).send()
}
})

})


app.get('/rooms', (req, res)=> {
res.json(rooms)
})


const start = async () => {
try {
await connectDB(process.env.MONGO_URL);
server.listen(PORT, () =>
console.log(`Server is listening on port ${PORT}...`)
);
} catch (error) {
console.log(error);
}
};

start();

14 changes: 14 additions & 0 deletions models/Message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const mongoose = require('mongoose');

const MessageSchema = new mongoose.Schema({
content: String,
from: Object,
socketid: String,
time: String,
date: String,
to: String
})

const Message = mongoose.model('Message', MessageSchema);

module.exports = Message
73 changes: 73 additions & 0 deletions models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const mongoose = require('mongoose');
const {isEmail} = require('validator');
const bcrypt = require('bcrypt');

const UserSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Can't be blank"]
},
email: {
type: String,
lowercase: true,
unique: true,
required: [true, "Can't be blank"],
index: true,
validate: [isEmail, "invalid email"]
},
password: {
type: String,
required: [true, "Can't be blank"]
},
picture: {
type: String,
},
newMessages: {
type: Object,
default: {}
},
status: {
type: String,
default: 'online'
}
}, {minimize: false});

UserSchema.pre('save', function(next){
const user = this;
if(!user.isModified('password')) return next();

bcrypt.genSalt(10, function(err, salt){
if(err) return next(err);

bcrypt.hash(user.password, salt, function(err, hash){
if(err) return next(err);

user.password = hash
next();
})

})

})


UserSchema.methods.toJSON = function(){
const user = this;
const userObject = user.toObject();
delete userObject.password;
return userObject;
}

UserSchema.statics.findByCredentials = async function(email, password) {
const user = await User.findOne({email});
if(!user) throw new Error('invalid email or password');

const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch) throw new Error('invalid email or password')
return user
}


const User = mongoose.model('User', UserSchema);

module.exports = User
12 changes: 12 additions & 0 deletions node_modules/.bin/mime

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions node_modules/.bin/mime.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions node_modules/.bin/mime.ps1

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions node_modules/.bin/nodemon

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions node_modules/.bin/nodemon.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions node_modules/.bin/nodemon.ps1

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions node_modules/.bin/nodetouch

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions node_modules/.bin/nodetouch.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions node_modules/.bin/nodetouch.ps1

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading