Skip to content

Commit

Permalink
Message Send with Attachment Successfully
Browse files Browse the repository at this point in the history
  • Loading branch information
pronazmul committed Jun 18, 2021
1 parent 93ef9ba commit 2acfdd1
Show file tree
Hide file tree
Showing 11 changed files with 1,524 additions and 308 deletions.
10 changes: 10 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const mongoose = require("mongoose");
const dotenv = require("dotenv");
const path = require("path");
const cookieParser = require("cookie-parser");
const http = require("http");
const moment = require("moment");

// Internal Dependencies:
const {
Expand All @@ -15,8 +17,16 @@ const userRouter = require("./router/userRouter");
const inboxRouter = require("./router/inboxRouter");

const app = express();
const server = http.createServer(app);
dotenv.config();

// socket creation
const io = require("socket.io")(server);
global.io = io;

// Moment Set as application local:
app.locals.moment = moment;

// Database Connection
mongoose
.connect(process.env.DB_CONNECTION_URL, {
Expand Down
67 changes: 66 additions & 1 deletion controller/inboxController.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,72 @@ const getMessages = async (req, res, next) => {

// Send Message:
const sendMessage = async (req, res, next) => {
res.status(200).json({ msg: "File Uploaded Successfully!" });
if (req.body.message || (req.files && req.files.length > 0)) {
try {
// save message text/attachment in database
let attachments = null;

if (req.files && req.files.length > 0) {
attachments = [];

req.files.forEach((file) => {
attachments.push(file.filename);
});
}

const newMessage = new Message({
text: req.body.message,
attachment: attachments,
sender: {
id: req.user.userid,
name: req.user.username,
avatar: req.user.avatar || null,
},
receiver: {
id: req.body.receiverId,
name: req.body.receiverName,
avatar: req.body.avatar || null,
},
conversation_id: req.body.conversationId,
});

const result = await newMessage.save();

This comment has been minimized.

Copy link
@pronazmul

pronazmul Jun 21, 2021

Author Owner

#Emit Socket Event

// emit socket event
global.io.emit("new_message", {
message: {
conversation_id: req.body.conversationId,
sender: {
id: req.user.userid,
name: req.user.username,
avatar: req.user.avatar || null,
},
message: req.body.message,
attachment: attachments,
date_time: result.date_time,
},
});

res.status(200).json({
message: "Successful!",
data: result,
});
} catch (err) {
res.status(500).json({
errors: {
common: {
msg: err.message,
},
},
});
}
} else {
res.status(500).json({
errors: {
common: "message text or attachment is required!",
},
});
}
};

// Module Export:
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"express-validator": "^6.11.1",
"http-errors": "^1.8.0",
"jsonwebtoken": "^8.5.1",
"moment": "^2.29.1",
"mongoose": "^5.12.13",
"multer": "^1.4.2"
"multer": "^1.4.2",
"socket.io": "^4.1.2"
}
}
7 changes: 7 additions & 0 deletions public/js/socket.io.min.js

Large diffs are not rendered by default.

163 changes: 0 additions & 163 deletions test.ejs
Original file line number Diff line number Diff line change
@@ -1,163 +0,0 @@

<div id="chat-container">
<div id="search-container">
<input type="text" placeholder="Search" />
</div>

<div class="new-message-container" onclick="openModal()">
<a href="#">+</a>
</div>

<div id="chat-title">
<span id="conversation-partner"></span>
<img src="./images/trash.png" alt="Delete Conversation" />
</div>

<!-- placeholder div if no messages are in messages area -->
<div id="chat-message-list">
<div class="nothing">select a conversation</div>
</div>

<!-- send message form -->
<form id="chat-form" method="post" enctype="multipart/form-data">
<label for="attachment"><img src="./images/attachment.png" alt="Add Attachment" /></label>
<input type="file" multiple name="attachment" class="hide" id="attachment" />
<input type="text" name="message" placeholder="Type a message" autocomplete="off" />
</form>

</div>
<%- include('./partials/add-conversation-modal.ejs'); %>

<!-- import socket io client from cdn -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.min.js"></script>

<script>
const form = document.querySelector('#chat-form');
const messageContainer = document.querySelector('#chat-message-list');
const chatTitleContainer = document.querySelector('#conversation-partner');
const loggedinUserId = '<%= loggedInUser.userid %>';
const loggedinUserName = '<%= loggedInUser.username %>';
let participant = null; // selected conversation participant object
let current_conversation_id; // selected conversation id
// socket initialization
const socket = io('<%= process.env.APP_URL %>');
// handle new/live incoming message from socket
socket.on("new_message", data => {
// only respond if current conversation is open in any client
if(data.message.conversation_id == current_conversation_id) {
// message class
const messageClass = data.message.sender.id === loggedinUserId ? 'you-message' : 'other-message';
const senderAvatar = data.message.sender.avatar ? `<img src="./uploads/avatars/${data.message.sender.avatar}" alt="${data.message.sender.name}" />` : `<img src="./images/nophoto.png" alt="${data.message.sender.name}" />`;
// message attachments
let attachments = '<div class="attachments">';
if(data.message.attachment && data.message.attachment.length > 0) {
data.message.attachment.forEach(attachment => {
attachments += `<img src="./uploads/attachments/${attachment}" /> `;
});
}
attachments += '</div>';
let messageHTML;
// do not show avatar for loggedin user
if(data.message.sender.id == loggedinUserId) {
messageHTML = `<div class="message-row ${messageClass}"><div class="message-content">
<div class="message-text">${data.message.message}</div>
${attachments}
<div class="message-time">${moment(data.message.date_time).fromNow()}</div>
</div></div>`;
} else {
messageHTML = `<div class="message-row ${messageClass}"><div class="message-content">
${senderAvatar}
<div class="message-text">${data.message.message}</div>
${attachments}
<div class="message-time">${moment(data.message.date_time).fromNow()}</div>
</div></div>`;
}
// append the inoming message to message area as last item
document.querySelector('#chat-message-list > .message-row:first-child').insertAdjacentHTML('beforeBegin', messageHTML);
}
});
// get messages of a conversation
async function getMessages(conversation_id, current_conversation_name){
// messages failure toast
const messagesFailureToast = Toastify({
text: "Error loading messages!",
duration: 1000,
});
let response = await fetch(`/inbox/messages/${conversation_id}`);
const result= await response.json();
if(!result.errors && result.data) {
form.style.visibility = 'visible';
const {data, user, conversation_id} = result;
participant = data.participant;
current_conversation_id = conversation_id;
if(data.messages) {
let allMessages = '';
if(data.messages.length > 0) {
data.messages.forEach((message) => {
let senderAvatar = message.sender.avatar ? `./uploads/avatars/${message.sender.avatar}` : './images/nophoto.png';
const messageClass = message.sender.id === loggedinUserId ? 'you-message' : 'other-message';
const showAvatar = message.sender.id === loggedinUserId ? '' : `<img src="${senderAvatar}" alt="${message.sender.name}" />`;
// message attachments
let attachments = '<div class="attachments">';
if(message.attachment && message.attachment.length > 0) {
message.attachment.forEach(attachment => {
attachments += `<img src="./uploads/attachments/${attachment}" /> `;
});
}
attachments += '</div>';
// final message html
let messageHTML = `<div class="message-row ${messageClass}"><div class="message-content">
${showAvatar}
<div class="message-text">${message.text}</div>
${attachments}
<div class="message-time">${moment(message.date_time).fromNow()}</div>
</div></div>`;
allMessages += messageHTML;
messageContainer.innerHTML = allMessages;
});
} else if(data.messages.length === 0) {
messageContainer.innerHTML = '<div class="message-row"></div>';
}
chatTitleContainer.textContent = current_conversation_name;
}
} else {
messagesFailureToast.showToast();
}
}
// message sending
form.onsubmit = async function (event) {
event.preventDefault();
const sendMessageFailureToast = Toastify({
text: "Error sending message",
duration: 1000,
});
// prepare the form data
const formData = new FormData(form);
formData.append('receiverId', participant.id);
formData.append('receiverName', participant.name);
formData.append('avatar', participant.avatar || '');
formData.append('conversationId', current_conversation_id);
// send the request to server
let response = await fetch("/inbox/message", {
method: "POST",
body: formData,
});
// get response
let result = await response.json();
if (!result.errors) {
form.reset(); // reset the form
} else {
sendMessageFailureToast.showToast();
}
}
</script>
</body>
</html>
62 changes: 0 additions & 62 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,62 +0,0 @@
// external imports
const multer = require("multer");
const path = require("path");
const createError = require("http-errors");

function uploader(
subfolder_path,
allowed_file_types,
max_file_size,
max_number_of_files,
error_msg
) {
// File upload folder
const UPLOADS_FOLDER = `${__dirname}/../public/uploads/${subfolder_path}/`;

// define the storage
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOADS_FOLDER);
},
filename: (req, file, cb) => {
const fileExt = path.extname(file.originalname);
const fileName =
file.originalname
.replace(fileExt, "")
.toLowerCase()
.split(" ")
.join("-") +
"-" +
Date.now();

cb(null, fileName + fileExt);
},
});

// preapre the final multer upload object
const upload = multer({
storage: storage,
limits: {
fileSize: max_file_size,
},
fileFilter: (req, file, cb) => {
if (req.files.length > max_number_of_files) {
cb(
createError(
`Maximum ${max_number_of_files} files are allowed to upload!`
)
);
} else {
if (allowed_file_types.includes(file.mimetype)) {
cb(null, true);
} else {
cb(createError(error_msg));
}
}
},
});

return upload;
}

module.exports = uploader;
1 change: 0 additions & 1 deletion utilities/multipleUploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const multipleUploader = (
cb(null, UPLOADS_FOLDER);
},
filename: (req, file, cb) => {
console.log(req.files);
const fileExt = path.extname(file.originalname);
const fileName =
file.originalname
Expand Down
Loading

0 comments on commit 2acfdd1

Please sign in to comment.