app.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. console.log(Message)
  13. const server = http.createServer(app);
  14. app.use(cors());
  15. app.use(express.json());
  16. const io = require("socket.io")(server, {
  17. cors: {
  18. origin: "http://localhost:3000" //client endpoint and port
  19. }
  20. });
  21. const randomColor = require('randomcolor');
  22. const PORT = process.env.PORT || 5000;
  23. const TOKEN_KEY = process.env.TOKEN_KEY || 'rGH4r@3DKOg06hgj';
  24. const HASH_KEY = 7;
  25. //main test page
  26. app.get('/', (req, res) => {
  27. res.send('here will be login page')
  28. })
  29. const generateToken = (id, userName, isAdmin) => {
  30. const payload = {
  31. id,
  32. userName,
  33. isAdmin
  34. }
  35. return jwt.sign(payload, TOKEN_KEY);
  36. }
  37. const isValidUserName = (userName) => {
  38. const nameRegex = /[^A-Za-z0-9]/ ;
  39. return (!nameRegex.test(userName) && userName.trim().length > 2);
  40. }
  41. const getAllDbUsers = async (socket) => {
  42. const usersDb = await User.find({})
  43. socket.emit('allDbUsers', usersDb)
  44. }
  45. const getOneUser = async (userName) => {
  46. const userInDb = await User.findOne({userName});
  47. return userInDb;
  48. }
  49. app.post('/login', async (req, res) => {
  50. try {
  51. const {userName,password} = req.body;
  52. if (!isValidUserName(userName)){
  53. return res.status(400).json({message: 'Invalid username'})
  54. }
  55. const dbUser = await getOneUser(userName)
  56. if (dbUser?.isBanned){
  57. return res.status(401).json({message: 'Your account has been banned!!!'})
  58. }
  59. const hashPassword = await bcrypt.hash(password, HASH_KEY);
  60. if (!dbUser) {
  61. const user = new User({
  62. userName,
  63. hashPassword,
  64. isAdmin: !await User.count().exec(),
  65. isBanned: false,
  66. isMutted: false
  67. });
  68. await user.save()
  69. return res.json({
  70. token: generateToken(user.id, user.userName, user.isAdmin)
  71. });
  72. }
  73. if (dbUser && !bcrypt.compareSync(password, dbUser.hashPassword)){
  74. return res.status(400).json({message: 'Invalid credantials'})
  75. }
  76. res.json({
  77. token: generateToken(dbUser.id, dbUser.userName, dbUser.isAdmin),
  78. message: 'Login success!!!'
  79. })
  80. } catch (e) {
  81. console.log(e);
  82. res.status(500).json({message: `Error ${e}`});
  83. }
  84. })
  85. io.use( async (socket, next) => {
  86. const token = socket.handshake.auth.token;
  87. const sockets = await io.fetchSockets();
  88. if(!token) {
  89. socket.disconnect();
  90. return;
  91. }
  92. const usersOnline = [];
  93. sockets.map((sock) => {
  94. usersOnline.push(sock.user);
  95. })
  96. try {
  97. const user = jwt.verify(token, TOKEN_KEY);
  98. const userName = user.userName;
  99. const dbUser = await getOneUser(userName);
  100. if(dbUser.isBanned){
  101. socket.disconnect();
  102. return;
  103. }
  104. socket.user = user;
  105. socket.user.color = randomColor();
  106. const exist = sockets.find((current) => current.user.userName == socket.user.userName)
  107. if(exist) { //&& !user.isAdmin - add for two or more admins
  108. console.log(exist.userName, 'exist twice entering...')
  109. exist.disconnect();
  110. }
  111. } catch(e) {
  112. console.log(e);
  113. socket.disconnect();
  114. }
  115. next();
  116. });
  117. io.on("connection", async (socket) => {
  118. const userName = socket.user.userName;
  119. const sockets = await io.fetchSockets();
  120. const dbUser = await getOneUser(userName);
  121. io.emit('usersOnline', sockets.map((sock) => sock.user)); // send array online users
  122. socket.emit('connected', dbUser); //socket.user
  123. if(socket.user.isAdmin){
  124. getAllDbUsers(socket);
  125. }//sent all users from db to admin
  126. const messagesToShow = await Message.find({}).sort({ 'createDate': -1 }).limit(20);
  127. socket.emit('allmessages', messagesToShow.reverse());
  128. socket.on("message", async (data) => {
  129. const dateNow = Date.now(); // for correct working latest post
  130. const post = await Message.findOne({userName}).sort({ 'createDate': -1 })
  131. const oneUser = await getOneUser(userName);
  132. if(oneUser.isMutted){ //(oneUser.isMutted || !post)
  133. return;
  134. }
  135. if(((Date.now() - Date.parse(post?.createDate)) < 1500)){
  136. console.log((Date.now() - Date.parse(post?.createDate)))// can use to show timer near by button
  137. return;
  138. }
  139. // if(!oneUser.isMutted && post){
  140. // if(((Date.now() - Date.parse(post.createDate)) > 150)){//change later 15000
  141. const message = new Message({
  142. text: data.message,
  143. userName: userName,
  144. createDate: Date.now()
  145. });
  146. try {
  147. await message.save();
  148. } catch (error) {
  149. console.log('Message save to db error', error);
  150. }
  151. io.emit('message', message);
  152. // }
  153. // }
  154. });
  155. try {
  156. socket.on("disconnect", async () => {
  157. const sockets = await io.fetchSockets();
  158. io.emit('usersOnline', sockets.map((sock) => sock.user));
  159. console.log(`user :${socket.user.userName} , disconnected to socket`);
  160. });
  161. console.log(`user :${socket.user.userName} , connected to socket`);
  162. socket.on("muteUser",async (data) => {
  163. if(!socket.user.isAdmin){
  164. return;
  165. }
  166. // if(socket.user.isAdmin){
  167. const {user, prevStatus} = data;
  168. const sockets = await io.fetchSockets();
  169. const mute = await User.updateOne({userName : user}, {$set: {isMutted :!prevStatus}});
  170. getAllDbUsers(socket);
  171. const exist = sockets.find( current => current.user.userName == user)
  172. const dbUser = await getOneUser(user);
  173. if(exist){
  174. exist.emit('connected', dbUser);
  175. }
  176. // }
  177. });
  178. socket.on("banUser",async (data) => {
  179. if(!socket.user.isAdmin){
  180. return;
  181. }
  182. // if(socket.user.isAdmin) {
  183. const {user, prevStatus} = data;
  184. const sockets = await io.fetchSockets();
  185. const ban = await User.updateOne({userName : user}, {$set: {isBanned:!prevStatus}});
  186. getAllDbUsers(socket)
  187. const exist = sockets.find( current => current.user.userName == user)
  188. if(exist){
  189. exist.disconnect();
  190. }
  191. // }
  192. });
  193. } catch (e) {
  194. console.log(e);
  195. }
  196. });
  197. //server and database start
  198. const start = async () => {
  199. try {
  200. await mongoose.connect('mongodb://localhost:27017/chat')
  201. .then(() => console.log(`DB started`))
  202. server.listen(PORT, () => {
  203. console.log(`Server started. Port: ${PORT}`);
  204. })
  205. } catch (e) {
  206. console.log(e);
  207. }
  208. }
  209. start();