app.js 7.2 KB

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