-
Notifications
You must be signed in to change notification settings - Fork 275
add solution #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
add solution #115
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| name: Test | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [ master ] | ||
|
|
||
| jobs: | ||
| build: | ||
|
|
||
| runs-on: ubuntu-latest | ||
|
|
||
| strategy: | ||
| matrix: | ||
| node-version: [20.x] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v2 | ||
| - name: Use Node.js ${{ matrix.node-version }} | ||
| uses: actions/setup-node@v1 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| - run: npm install | ||
| - run: npm test |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| PORT=3000 | ||
| DB_HOST=localhost | ||
| DB_USER=postgres | ||
| DB_PASSWORD=0011 | ||
| DB_DATABASE=postgres | ||
| DB_PORT=5555 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { sequelize } from './src/utils/db.js'; | ||
| import './src/models/index.js'; | ||
|
|
||
| sequelize.sync({ alter: true }).then(() => { | ||
| // eslint-disable-next-line no-console | ||
| console.log('Database synced'); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import { ApiError } from '../exeptions/api.error.js'; | ||
| import { userService } from '../services/user.service.js'; | ||
|
|
||
| const login = async (req, res) => { | ||
| const { userName } = req.body; | ||
|
|
||
| try { | ||
| const activeUser = await userService.getUser(userName); | ||
|
|
||
| res.cookie('activeUser', activeUser, { | ||
| httpOnly: true, | ||
| secure: false, | ||
| sameSite: 'lax', | ||
| maxAge: 30 * 24 * 60 * 60 * 1000, | ||
| }); | ||
|
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issue: You are storing the entire user object directly as a cookie value. Cookies can only store strings, so you should use |
||
|
|
||
| // localStorage.setItem('activeUser', JSON.stringify(activeUser)); | ||
|
|
||
| res.send(activeUser); | ||
| } catch (e) { | ||
| throw ApiError.badRequest(e); | ||
|
Comment on lines
+20
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issue: The |
||
| } | ||
|
Comment on lines
+20
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issue: The catch block does not receive the error object. Update the catch block to |
||
| }; | ||
|
|
||
| const getUser = async (req, res) => { | ||
| const activeUserCookie = req.cookies.activeUser; | ||
| let activeUser; | ||
|
|
||
| try { | ||
| activeUser = JSON.parse(activeUserCookie); | ||
| } catch (err) { | ||
| throw ApiError.unauthorized(err); | ||
| } | ||
|
|
||
| const user = await userService.getUser(activeUser.name); | ||
|
|
||
| res.send(user); | ||
| }; | ||
|
|
||
| export const authController = { | ||
| login, | ||
| getUser, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { messageService } from '../services/message.service.js'; | ||
| import { emitter } from '../events/eventEmitter.js'; | ||
| import { userService } from '../services/user.service.js'; | ||
|
|
||
| const getMessages = async (req, res) => { | ||
| const { roomId } = req.params; | ||
|
|
||
| const messages = await messageService.getMessages(roomId); | ||
|
|
||
| // emitter.once('message', (message) => { | ||
| // res.status(200).send(messages); | ||
| // }); | ||
| res.status(200).send(messages); | ||
| }; | ||
|
|
||
| const sendMessage = async (req, res) => { | ||
| const { content, name } = req.body; | ||
| const { roomId } = req.params; | ||
| const activeUser = req.cookies.activeUser; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical issue: req.cookies.activeUser will be a string, not an object. If you need to access properties like 'activeUser.name', you must parse the cookie value (e.g., using JSON.parse) if it was stringified when set. Otherwise, this will not work as intended. |
||
| const id = activeUser.id; | ||
|
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical issue:
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error: You are treating |
||
| // const { id } = await userService.getUser(activeUser.name); | ||
|
|
||
| console.log(activeUser.id); | ||
| console.log('strange'); | ||
|
|
||
| const message = { | ||
| content, | ||
| userId: id, | ||
| roomId, | ||
| createdAt: new Date(), | ||
| name, | ||
| }; | ||
|
|
||
| await messageService.sendMessage(message); | ||
|
|
||
| emitter.emit('message', message); | ||
|
|
||
| res.status(201).send(); | ||
| }; | ||
|
|
||
| export const messageController = { | ||
| getMessages, | ||
| sendMessage, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import { ApiError } from '../exeptions/api.error.js'; | ||
| import { roomService } from '../services/rooms.service.js'; | ||
| import { userService } from '../services/user.service.js'; | ||
|
|
||
| const getAll = async (req, res) => { | ||
| const rooms = await roomService.getAll(); | ||
|
|
||
| res.send(rooms); | ||
| }; | ||
|
|
||
| const create = async (req, res) => { | ||
| const { roomName } = req.body; | ||
|
|
||
| console.log('Room name: ', roomName); | ||
|
|
||
| const newRoom = await roomService.create(roomName); | ||
|
|
||
| res.send(newRoom); | ||
| }; | ||
|
|
||
| const rename = async (req, res) => { | ||
| const { id } = req.params; | ||
| const { newRoomName } = req.body; | ||
|
|
||
| console.log('roomId: ', id); | ||
| console.log('newRoomName: ', newRoomName); | ||
|
|
||
| const updatedRoom = await roomService.rename(id, newRoomName); | ||
|
|
||
| res.send(updatedRoom); | ||
| }; | ||
|
|
||
| const join = async (req, res) => { | ||
| const { roomId } = req.params; | ||
| const activeUser = req.cookies.activeUser; | ||
| const user = await userService.getUser(activeUser.name); | ||
|
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical issue: req.cookies.activeUser will be a string, not an object. Attempting to access 'activeUser.name' will result in 'undefined'. You should parse the cookie value (e.g., using JSON.parse) if you are storing an object as a cookie, or store only the username as the cookie value.
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical issue:
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error: You are treating |
||
|
|
||
| try { | ||
| await roomService.join(roomId, user); | ||
| res | ||
| .status(200) | ||
| .json({ message: `User joined room ${roomId} successfully.` }); | ||
| } catch (error) { | ||
| console.error('Error joining room:', error); | ||
| } | ||
|
Comment on lines
+43
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issue: In the |
||
| }; | ||
|
|
||
| const remove = async (req, res) => { | ||
| const { id } = req.params; | ||
|
|
||
| await roomService.remove(id); | ||
|
|
||
| res.status(201).send(); | ||
| }; | ||
|
|
||
| const getJoined = async (req, res) => { | ||
| const { id } = req.params; | ||
|
|
||
| // if (id instanceof undefined) { | ||
| // throw ApiError.badRequest('Id is undefined'); | ||
| // } | ||
|
|
||
| const roomIds = (await roomService.getJoined(id)) || []; | ||
|
|
||
| res.send(roomIds); | ||
| }; | ||
|
|
||
| export const roomController = { | ||
| getAll, | ||
| create, | ||
| rename, | ||
| join, | ||
| remove, | ||
| getJoined, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import { EventEmitter } from 'events'; | ||
|
|
||
| export const emitter = new EventEmitter(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { emitter } from './eventEmitter.js'; | ||
| import { wss } from '../index.js'; | ||
|
|
||
| emitter.on('message', (message) => { | ||
| for (const client of wss.clients) { | ||
| client.send(JSON.stringify(message)); | ||
| } | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| export class ApiError extends Error { | ||
| constructor({ message, status, errors }) { | ||
| super(message); | ||
|
|
||
| this.status = status; | ||
| this.errors = errors; | ||
| } | ||
|
|
||
| static badRequest(message, errors) { | ||
| return new ApiError({ | ||
| message, | ||
| errors, | ||
| status: 400, | ||
| }); | ||
| } | ||
|
|
||
| static unauthorized(errors) { | ||
| return new ApiError({ | ||
| message: 'unauthorized user', | ||
| errors, | ||
| status: 401, | ||
| }); | ||
| } | ||
|
|
||
| static notFound(errors) { | ||
| return new ApiError({ | ||
| message: 'not found', | ||
| errors, | ||
| status: 404, | ||
| }); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import express from 'express'; | ||
| import cookieParser from 'cookie-parser'; | ||
| import cors from 'cors'; | ||
| import { authRouter } from './routes/auth.route.js'; | ||
| import { errorMiddleware } from './middlewares/errorMiddleware.js'; | ||
| import { roomRouter } from './routes/room.route.js'; | ||
| import { WebSocketServer } from 'ws'; | ||
| import { messageRouter } from './routes/message.route.js'; | ||
| import './events/messageListener.js'; | ||
|
|
||
| const PORT = process.env.PORT || 3000; | ||
|
|
||
| const app = express(); | ||
|
|
||
| app.use( | ||
| cors({ | ||
| origin: 'http://localhost:5173', | ||
| credentials: true, | ||
| }), | ||
| ); | ||
| app.use(express.json()); | ||
| app.use(cookieParser()); | ||
|
|
||
| app.use(authRouter); | ||
| app.use(roomRouter); | ||
| app.use(messageRouter); | ||
|
|
||
| app.get('/', (req, res) => { | ||
| res.send('Hello'); | ||
| }); | ||
|
|
||
| app.use(errorMiddleware); | ||
|
|
||
| const server = app.listen(PORT, () => { | ||
| // eslint-disable-next-line no-console | ||
| console.log('Server is running...'); | ||
| }); | ||
|
|
||
| export const wss = new WebSocketServer({ server }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| export const authMiddleware = (req, res, next) => { | ||
| const activeUser = req.cookies.activeUser; | ||
| // const activeUser = localStorage.getItem('activeUser'); | ||
|
|
||
| console.log('Active user: ', activeUser); | ||
|
|
||
| if (activeUser === undefined) { | ||
| console.log('error'); | ||
|
|
||
| res.status(401).json({ message: 'Unauthorized' }); | ||
| return; | ||
| } | ||
|
|
||
| next(); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { ApiError } from '../exeptions/api.error.js'; | ||
|
|
||
| export const errorMiddleware = (error, req, res, next) => { | ||
| if (error instanceof ApiError) { | ||
| return res.status(error.status).send({ | ||
| message: error.message, | ||
| errors: error.errors, | ||
| }); | ||
| } | ||
|
|
||
| if (error) { | ||
| return res.status(500).send({ | ||
| message: 'Server error', | ||
| }); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { User } from './user.js'; | ||
| import { Room } from './room.js'; | ||
| import { Message } from './message.js'; | ||
|
|
||
| User.hasMany(Message); | ||
| Message.belongsTo(User); | ||
|
|
||
| Room.hasMany(Message); | ||
| Message.belongsTo(Room); | ||
|
|
||
| User.belongsToMany(Room, { through: 'UserRooms', as: 'rooms' }); | ||
| Room.belongsToMany(User, { through: 'UserRooms', as: 'users' }); | ||
|
|
||
| export { User, Room, Message }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { sequelize } from '../utils/db.js'; | ||
|
|
||
| export const Message = sequelize.define('Message', { | ||
| content: { | ||
| type: DataTypes.TEXT, | ||
| allowNull: false, | ||
| }, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { sequelize } from '../utils/db.js'; | ||
|
|
||
| export const Room = sequelize.define('Room', { | ||
| roomName: { | ||
| type: DataTypes.STRING, | ||
| allowNull: false, | ||
| }, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { sequelize } from '../utils/db.js'; | ||
|
|
||
| export const User = sequelize.define('User', { | ||
| name: { | ||
| type: DataTypes.STRING, | ||
| allowNull: false, | ||
| unique: true, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue: You are storing the
activeUserobject directly in the cookie. Cookies can only store strings. Please useJSON.stringify(activeUser)when setting the cookie to ensure proper serialization.