app.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. const express = require('express');
  2. const app = express()
  3. const cors = require("cors");
  4. const http = require('http'); //create new http
  5. const mongoose = require('mongoose');
  6. const socket = require("socket.io");
  7. const User = require('./db/models/User');
  8. const Message = require('./db/models/Message');
  9. const jwt = require('jsonwebtoken');
  10. const bcrypt = require('bcrypt');
  11. require('dotenv').config(); // add dotnv for config
  12. const Uuid = require('uuid'); //lib for unic id generate
  13. const fileupload = require('express-fileupload');
  14. const fs = require('fs');
  15. const ORIGIN_URL = process.env.REACT_APP_BASE_URL
  16. const server = http.createServer(app);
  17. app.use(cors());
  18. app.use(express.json());
  19. app.use(fileupload())
  20. app.use(express.static('avatars')); //folder for static files
  21. const io = require("socket.io")(server, {
  22. cors: ORIGIN_URL
  23. });
  24. const PORT = process.env.PORT || 5000;
  25. const TOKEN_KEY = process.env.TOKEN_KEY || 'rGH4r@3DKOg06hgj';
  26. const HASH_KEY = 7;
  27. const STATIC_PATH = process.env. STATIC_PATH || 'avatars';
  28. const generateToken = (id, userName, isAdmin) => {
  29. const payload = {
  30. id,
  31. userName,
  32. isAdmin
  33. }
  34. return jwt.sign(payload, TOKEN_KEY);
  35. }
  36. const isValidUserName = (userName) => {
  37. const nameRegex = /[^A-Za-z0-9]/ ;
  38. return (!nameRegex.test(userName) && userName.trim().length > 2);
  39. }
  40. const getAllDbUsers = async (socket) => {
  41. const usersDb = await User.find({})
  42. socket.emit('allDbUsers', usersDb)
  43. }
  44. const getOneUser = async (userName) => {
  45. const userInDb = await User.findOne({userName});
  46. return userInDb;
  47. }
  48. app.post('/login', async (req, res) => {
  49. try {
  50. const {userName,password} = req.body;
  51. if (!isValidUserName(userName)){
  52. return res.status(400).json({message: 'Invalid username'})
  53. }
  54. const dbUser = await getOneUser(userName)
  55. if (dbUser?.isBanned){
  56. return res.status(401).json({message: 'Your account has been banned!!!'})
  57. }
  58. const hashPassword = await bcrypt.hash(password, HASH_KEY);
  59. if (!dbUser) {
  60. const user = new User({
  61. userName,
  62. hashPassword,
  63. isAdmin: !await User.count().exec(),
  64. isBanned: false,
  65. isMutted: false,
  66. avatar: '',
  67. messages: []
  68. });
  69. await user.save()
  70. return res.json({
  71. token: generateToken(user.id, user.userName, user.isAdmin)
  72. });
  73. }
  74. if (dbUser && !bcrypt.compareSync(password, dbUser.hashPassword)){
  75. return res.status(400).json({message: 'Invalid credantials'})
  76. }
  77. res.json({
  78. token: generateToken(dbUser.id, dbUser.userName, dbUser.isAdmin),
  79. })
  80. } catch (e) {
  81. console.log(e);
  82. res.status(500).json({message: `Error ${e}`});
  83. }
  84. })
  85. app.post('/avatar', async (req, res) => {
  86. if (!req.files || Object.keys(req.files).length === 0) {
  87. return res.status(400).json('No files were uploaded.');
  88. }
  89. try {
  90. const file = req.files.file;
  91. const user = jwt.verify(req.body.token, TOKEN_KEY);
  92. const avatarFileName = Uuid.v4() + '.jpeg';
  93. file.mv(STATIC_PATH + '\/' + avatarFileName)
  94. const userFromDb = await getOneUser(user.userName);
  95. if(userFromDb.avatar){
  96. const oldAvatar = userFromDb.avatar;
  97. fs.unlinkSync(STATIC_PATH + '\/' + oldAvatar)
  98. }
  99. await User.findOneAndUpdate({userName: user.userName},{ $set: {'avatar': avatarFileName}}, {
  100. new: true
  101. });
  102. return res.json({ message:'Avatar was uploud succesfully...', avatarUrl: avatarFileName})
  103. } catch (error) {
  104. res.status(500).json({message: `Error uppload file to serverp: ${error}`});
  105. }
  106. })
  107. app.post('/files', async (req, res) => {
  108. if (!req.files || Object.keys(req.files).length === 0) {
  109. return res.status(400).json('No files were uploaded.');
  110. }
  111. const user = jwt.verify(req.body.token, TOKEN_KEY);
  112. const oneUser = await getOneUser(user.userName);
  113. if(oneUser.isMutted){
  114. return;
  115. }
  116. const files = req.files.files;
  117. if (files.length) {
  118. for (let i = 0; i < files.length; i++) {
  119. let file = files[i]
  120. file.mv(STATIC_PATH + '\/' + file.name)
  121. const message = new Message({
  122. text: file.name,
  123. userName: user.userName,
  124. createDate: Date.now(),
  125. user: oneUser.id, //add link to other collection by id
  126. file: file.name,
  127. fileType: file.mimetype
  128. });
  129. try {
  130. await message.save();
  131. if(!oneUser.messages){
  132. await oneUser.update({ $set: {'messages': []}});
  133. }
  134. await oneUser.messages.push(message)
  135. await oneUser.save()
  136. }
  137. catch (error) {
  138. console.log('Message save to db error', error);
  139. }
  140. const newMessages = await message.populate( {path:'user'})
  141. io.emit('newmessage', newMessages);
  142. }}
  143. else {
  144. if (files.name == 'blob') {
  145. files.name = Uuid.v4() + '.jpeg'
  146. }
  147. files.mv(STATIC_PATH + '\/' + files.name); //for one file
  148. const message = new Message({
  149. text: files.name,
  150. userName: user.userName,
  151. createDate: Date.now(),
  152. user: oneUser.id, //add link to other collection by id
  153. file: files.name,
  154. fileType: files.mimetype
  155. });
  156. try {
  157. await message.save();
  158. if(!oneUser.messages){
  159. await oneUser.update({ $set: {'messages': []}});
  160. }
  161. await oneUser.messages.push(message)
  162. await oneUser.save()
  163. }
  164. catch (error) {
  165. console.log('Message save to db error', error);
  166. }
  167. const newMessages = await message.populate( {path:'user'})
  168. io.emit('newmessage', newMessages);
  169. }
  170. return res.json({ message:'File was uploud succesfully...'})
  171. })
  172. io.use( async (socket, next) => {
  173. const token = socket.handshake.auth.token;
  174. const sockets = await io.fetchSockets();
  175. if(!token) {
  176. console.log('socket disconnect')
  177. socket.disconnect();
  178. return;
  179. }
  180. const usersOnline = [];
  181. sockets.map(sock => usersOnline.push(sock.user))
  182. try {
  183. const user = jwt.verify(token, TOKEN_KEY);
  184. const userName = user.userName;
  185. const dbUser = await getOneUser(userName);
  186. if(dbUser && dbUser.isBanned){
  187. socket.disconnect();
  188. return;
  189. }
  190. socket.user = user;
  191. const exist = sockets.find(current => current.user.userName == socket.user.userName)
  192. // console.log('exist ' , exist)
  193. if(exist) { //&& !user.isAdmin - add for two or more admins
  194. console.log(exist.user.userName, 'exist twice entering...')
  195. exist.disconnect();
  196. }
  197. } catch(e) {
  198. console.log(e);
  199. socket.disconnect();
  200. }
  201. next();
  202. });
  203. io.on("connection", async (socket) => {
  204. //need to use this ID to socket privat messges
  205. const users = [];
  206. for (let [id, socket] of io.of("/").sockets) {
  207. users.push({
  208. userID: id,
  209. username: socket.user.userName
  210. });
  211. }
  212. socket.emit("usersID", users);
  213. const userName = socket.user.userName;
  214. const sockets = await io.fetchSockets();
  215. const dbUser = await getOneUser(userName);
  216. const usersOnline = sockets.map(sock => sock.user)
  217. const onUser = []
  218. const usersOnlineID = usersOnline.map(users => Object.values(users)[0])
  219. const userSet = new Set(usersOnlineID)
  220. for (let id of userSet) {
  221. const userFromDb = await User.findById(id)
  222. onUser.push(userFromDb)
  223. }
  224. console.log(users)
  225. io.emit('usersOnline', onUser); // send array online users
  226. socket.emit('connected', dbUser); //socket.user
  227. if(socket.user.isAdmin){
  228. getAllDbUsers(socket);
  229. }//sent all users from db to admin
  230. const messagesToShow = await Message.find({}).sort({ 'createDate': -1 }).limit(20).populate( {path:'user'});
  231. socket.emit('allmessages', messagesToShow.reverse());
  232. socket.on("message", async (data) => {
  233. const dateNow = Date.now(); // for correct working latest post
  234. const post = await Message.findOne({userName}).sort({ 'createDate': -1 })
  235. const oneUser = await getOneUser(userName);
  236. if(oneUser.isMutted){ //(oneUser.isMutted || !post)
  237. return;
  238. }
  239. if(((Date.now() - Date.parse(post?.createDate)) < 1500)){
  240. console.log((Date.now() - Date.parse(post?.createDate)))// can use to show timer near by button
  241. return;
  242. }
  243. // if(!oneUser.isMutted && post){
  244. // if(((Date.now() - Date.parse(post.createDate)) > 150)){//change later 15000
  245. const message = new Message({
  246. text: data.message,
  247. userName: userName,
  248. createDate: Date.now(),
  249. user: oneUser.id, //add link to other collection by id
  250. });
  251. try {
  252. await message.save();
  253. if(!oneUser.messages){
  254. await oneUser.update({ $set: {'messages': []}});
  255. }
  256. await oneUser.messages.push(message)
  257. await oneUser.save()
  258. } catch (error) {
  259. console.log('Message save to db error', error);
  260. }
  261. const newMessages = await message.populate( {path:'user'})
  262. io.emit('newmessage', newMessages);
  263. // }
  264. // }
  265. });
  266. try {
  267. socket.on("disconnect", async () => {
  268. const exist = sockets.find(current => current.user.userName == socket.user.userName)
  269. const usersOnline = sockets.map(sock => sock.user)
  270. const filteredUsersOnline = usersOnline.filter(user => exist.user.id !== user.id)
  271. io.emit('usersOnline', filteredUsersOnline);
  272. // const sockets = await io.fetchSockets();
  273. // io.emit('usersOnline', sockets.map(sock => sock.user));
  274. console.log(`user :${socket.user.userName} , disconnected to socket`);
  275. });
  276. console.log(`user :${socket.user.userName} , connected to socket`);
  277. socket.on("muteUser",async (data) => {
  278. if(!socket.user.isAdmin){
  279. return;
  280. }
  281. // if(socket.user.isAdmin){
  282. const {user, prevStatus} = data;
  283. const sockets = await io.fetchSockets();
  284. const mute = await User.updateOne({userName : user}, {$set: {isMutted :!prevStatus}});
  285. getAllDbUsers(socket);
  286. const exist = sockets.find( current => current.user.userName == user)
  287. const dbUser = await getOneUser(user);
  288. if(exist){
  289. exist.emit('connected', dbUser);
  290. }
  291. // }
  292. });
  293. socket.on("private message", ({ user, message, to }) => {
  294. console.log(to, user._id, message)
  295. socket.to(to).emit("private message", {
  296. user,
  297. message,
  298. from: user.id,
  299. });
  300. });
  301. socket.on("banUser",async (data) => {
  302. if(!socket.user.isAdmin){
  303. return;
  304. }
  305. // if(socket.user.isAdmin) {
  306. const {user, prevStatus} = data;
  307. const sockets = await io.fetchSockets();
  308. const ban = await User.updateOne({userName : user}, {$set: {isBanned:!prevStatus}});
  309. getAllDbUsers(socket)
  310. const exist = sockets.find( current => current.user.userName == user)
  311. if(exist){
  312. exist.emit('ban', "dbUser")
  313. exist.disconnect();
  314. }
  315. // }
  316. });
  317. socket.on('userWriting', async () => {
  318. let isTyping = true;
  319. io.emit('writing', {userName, isTyping})
  320. })
  321. socket.on('editmessage', async (data) => {
  322. console.log(data.messageNewText)
  323. const user = jwt.verify(data.token, TOKEN_KEY)
  324. if(!user){
  325. return
  326. }
  327. try {
  328. await Message.findByIdAndUpdate(data.messageId, {text:data.messageNewText})
  329. const messagesToShow = await Message.find({}).sort({ 'createDate': -1 }).limit(20).populate( {path:'user'});
  330. io.emit('allmessages', messagesToShow.reverse())
  331. } catch (error) {
  332. console.log(error)
  333. }
  334. })
  335. socket.on('deleteMessage', async (data) => {
  336. const user = jwt.verify(data.token, TOKEN_KEY)
  337. console.log(data.messageId)
  338. if(!user){
  339. return
  340. }
  341. try {
  342. await Message.findByIdAndDelete(data.messageId)
  343. const messagesToShow = await Message.find({}).sort({ 'createDate': -1 }).limit(20).populate( {path:'user'});
  344. io.emit('allmessages', messagesToShow.reverse())
  345. } catch (error) {
  346. console.log(error)
  347. }
  348. })
  349. } catch (e) {
  350. console.log(e);
  351. }
  352. });
  353. //server and database start
  354. const start = async () => {
  355. try {
  356. await mongoose.connect('mongodb://localhost:27017/chat')
  357. .then(() => console.log(`DB started`))
  358. // await mongoose
  359. // .connect('mongodb+srv://serg1557733:1557733@cluster0.p9ltitx.mongodb.net/?retryWrites=true&w=majority')
  360. // .then(() => console.log(`DB started`))
  361. server.listen(PORT, () => {
  362. console.log(`Server started. Port: ${PORT}`);
  363. })
  364. } catch (e) {
  365. console.log(e);
  366. }
  367. }
  368. start();