-
Notifications
You must be signed in to change notification settings - Fork 275
Solution #137
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?
Solution #137
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,71 @@ | ||
| import { EventEmitter } from 'events'; | ||
| import { messageService } from '../services/message.service.js'; | ||
| import { User } from '../models/user.model.js'; | ||
|
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. Import path is incorrect — there is no |
||
|
|
||
| export const messageEmitter = new EventEmitter(); | ||
|
|
||
| const create = async (req, res) => { | ||
| const { roomId } = req.params; | ||
| const { text, userId } = req.body; | ||
|
|
||
| if (!roomId || !userId || !text || typeof text !== 'string') { | ||
| return res.status(400).json({ message: 'Missing or invalid parameters' }); | ||
| } | ||
|
|
||
| try { | ||
| const newMessage = await messageService.createMessageInRoom( | ||
| text, | ||
| userId, | ||
| roomId, | ||
| ); | ||
|
Comment on lines
+16
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. You call the service to create a message — make sure you handle the exact shape the service returns. If the service returns a mapped object ( |
||
|
|
||
| const user = await User.findByPk(userId); | ||
|
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. This |
||
|
|
||
| if (!user) { | ||
| return res.status(404).json({ message: 'User not found' }); | ||
| } | ||
|
Comment on lines
+15
to
+26
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. You call |
||
|
|
||
| const formattedMessage = { | ||
| author: user.name, | ||
| time: newMessage.createdAt, | ||
| text: newMessage.text, | ||
|
Comment on lines
+28
to
+31
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. You're building |
||
| }; | ||
|
Comment on lines
+28
to
+32
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.
|
||
|
|
||
| messageEmitter.emit('message', formattedMessage); | ||
|
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. When emitting the message you must include 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. You emit |
||
|
|
||
| res.status(201).json(formattedMessage); | ||
|
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. The response |
||
| } catch (err) { | ||
| // eslint-disable-next-line no-console | ||
| console.error('Error creating message:', err); | ||
| res.status(500).json({ message: 'Internal server error' }); | ||
| } | ||
| }; | ||
|
|
||
| const getMessages = async (req, res) => { | ||
| const { roomId } = req.params; | ||
|
|
||
| if (!roomId) { | ||
| return res.status(400).json({ message: 'Missing roomId' }); | ||
| } | ||
|
|
||
| try { | ||
| const messages = await messageService.getAllMessagesInRoom(roomId); | ||
|
|
||
| const formattedMessages = messages.map((m) => ({ | ||
| author: m.User?.name || 'Unknown', | ||
| time: m.createdAt, | ||
| text: m.text, | ||
|
Comment on lines
+54
to
+57
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. In |
||
| })); | ||
|
Comment on lines
+52
to
+58
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.
|
||
|
|
||
| res.status(200).json(formattedMessages); | ||
| } catch (err) { | ||
| // eslint-disable-next-line no-console | ||
| console.error('Error getting messages:', err); | ||
| res.status(500).json({ message: 'Internal server error' }); | ||
| } | ||
| }; | ||
|
|
||
| export const messageController = { | ||
| create, | ||
| getMessages, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { roomsService } from '../services/rooms.service.js'; | ||
|
|
||
| const getAllRooms = async (req, res) => { | ||
| const rooms = await roomsService.getAllRooms(); | ||
|
|
||
| res.status(200).send(rooms); | ||
|
Comment on lines
+3
to
+6
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. Wrap service calls in try/catch to handle unexpected errors (DB failures, etc.) and return 500 on server errors. Right now
Comment on lines
+4
to
+6
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.
|
||
| }; | ||
|
|
||
| const createRoom = async (req, res) => { | ||
| const { title, userId, description } = req.body; | ||
|
|
||
| if (!title || !userId) { | ||
| return res.sendStatus(404); | ||
|
Comment on lines
+12
to
+13
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. For missing required parameters you should return 400 (Bad Request), not 404. Change this to
Comment on lines
+12
to
+13
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. Returning 404 for missing |
||
| } | ||
|
|
||
| await roomsService.createRoom(title, userId, description); | ||
|
|
||
| res.sendStatus(201); | ||
|
Comment on lines
+16
to
+18
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. Validate the
Comment on lines
+16
to
+18
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. Call to |
||
| }; | ||
|
|
||
| const updateRoom = async (req, res) => { | ||
| const { roomId } = req.params; | ||
| const { title, description } = req.body; | ||
|
|
||
| if ((!title && !description) || !roomId) { | ||
| return res.sendStatus(404); | ||
|
Comment on lines
+25
to
+26
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. Same issue:
Comment on lines
+25
to
+26
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. Validation here uses 404 for missing |
||
| } | ||
|
|
||
| await roomsService.updateRoom(roomId, title, description); | ||
|
|
||
| res.sendStatus(204); | ||
|
Comment on lines
+29
to
+31
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.
|
||
| }; | ||
|
|
||
| const deleteRoom = async (req, res) => { | ||
| const { roomId } = req.params; | ||
|
|
||
| if (!roomId) { | ||
| return res.sendStatus(400); | ||
| } | ||
|
|
||
| await roomsService.deleteRoom(roomId); | ||
|
|
||
| res.sendStatus(204); | ||
|
Comment on lines
+41
to
+43
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. In |
||
| }; | ||
|
|
||
| export const roomController = { | ||
| getAllRooms, | ||
| createRoom, | ||
| updateRoom, | ||
| deleteRoom, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { User } from '../models/user.js'; | ||
| import { userService } from '../services/user.service.js'; | ||
|
|
||
| const create = async (req, res) => { | ||
| try { | ||
| const { name } = req.body; | ||
|
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. You destructure 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. Trim incoming |
||
|
|
||
| if (!name) { | ||
| return res.status(400).json({ message: 'Name is required' }); | ||
|
Comment on lines
+8
to
+9
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. The presence check |
||
| } | ||
|
|
||
| const isNameExist = await User.findOne({ where: { name } }); | ||
|
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. You check |
||
|
|
||
| if (isNameExist) { | ||
| return res.status(409).json({ message: 'User already exists' }); | ||
| } | ||
|
|
||
| await userService.createUser(name); | ||
|
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. You're proactively checking for an existing user which is good, but there's still a race condition between this check and |
||
|
|
||
| return res.status(201).json({ message: 'User was created!' }); | ||
| } catch { | ||
|
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. The catch block has no error parameter and returns 500 for all failures. Change to 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. The |
||
| return res.status(500).json({ message: 'Internal server error' }); | ||
| } | ||
| }; | ||
|
|
||
| export const userController = { | ||
| create, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import 'dotenv/config'; | ||
|
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. Importing dotenv here is fine to load environment variables. Ensure you have a .env in development and that CI/production provide these env vars; otherwise Sequelize will be constructed with undefined values. |
||
| import { Sequelize } from 'sequelize'; | ||
|
|
||
| export const client = new Sequelize({ | ||
|
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. Sequelize constructor uses several environment variables. Consider validating these values (or providing sensible defaults) before constructing Sequelize so the app fails fast with a clear error when DB config is missing. |
||
| host: process.env.DB_HOST, | ||
|
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. If your database uses a non-default port, include |
||
| username: process.env.DB_USERNAME, | ||
| password: process.env.DB_PASS, | ||
| database: process.env.DB_DATABASE, | ||
| dialect: 'postgres', | ||
|
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. For production (e.g. Heroku, managed Postgres) you may need to pass |
||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,83 @@ | ||
| 'use strict'; | ||
| import 'dotenv/config'; | ||
| import express from 'express'; | ||
| import { WebSocketServer } from 'ws'; | ||
| import cors from 'cors'; | ||
| import { userRoute } from './routes/user.route.js'; | ||
| import { roomsRoute } from './routes/rooms.route.js'; | ||
| import { messageRoute } from './routes/message.route.js'; | ||
| import { messageEmitter } from './controllers/message.controller.js'; | ||
| import { messageService } from './services/message.service.js'; | ||
|
|
||
| const PORT = process.env.PORT || 5000; | ||
| const app = express(); | ||
|
|
||
| app.use(cors()); | ||
| app.use(express.json()); | ||
|
|
||
| app.use('/user', userRoute); | ||
| app.use('/rooms', roomsRoute); | ||
| app.use(messageRoute); | ||
|
|
||
| const server = app.listen(PORT); | ||
|
|
||
| const wss = new WebSocketServer({ server }); | ||
| const rooms = {}; | ||
|
|
||
| wss.on('connection', (ws) => { | ||
| ws.on('message', async (rawMessage) => { | ||
| let parsed; | ||
|
|
||
| try { | ||
| parsed = JSON.parse(rawMessage); | ||
| } catch { | ||
| return; | ||
| } | ||
|
|
||
| const { roomId } = parsed; | ||
|
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. You only parse JSON and check |
||
|
|
||
| if (!roomId || typeof roomId !== 'number') { | ||
|
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. The code rejects |
||
| return; | ||
| } | ||
|
Comment on lines
+39
to
+41
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. The WS join validation requires |
||
|
|
||
| if (!rooms[roomId]) { | ||
| rooms[roomId] = []; | ||
|
Comment on lines
+43
to
+44
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. You create the room array if missing but never validate |
||
| } | ||
|
|
||
| if (!rooms[roomId].includes(ws)) { | ||
| rooms[roomId].push(ws); | ||
| } | ||
|
|
||
| const messages = await messageService.getAllMessagesInRoom(roomId); | ||
|
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. When a client joins you push the socket then fetch and send previous messages — good. Ensure 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.
|
||
|
|
||
| messages.forEach((msg) => { | ||
| ws.send(JSON.stringify(msg)); | ||
|
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. Sending Sequelize model instances with |
||
| }); | ||
| }); | ||
|
|
||
| ws.on('close', () => { | ||
| for (const roomId in rooms) { | ||
| rooms[roomId] = rooms[roomId].filter((client) => client !== ws); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| messageEmitter.on('message', async (message) => { | ||
| const { roomId } = message; | ||
|
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. The emitter handler expects |
||
|
|
||
| if (!roomId || !rooms[roomId]) { | ||
| return; | ||
|
Comment on lines
+66
to
+69
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. This handler expects incoming emitted |
||
| } | ||
|
|
||
| const formatted = { | ||
| author: message.author || message.User?.name || 'Unknown', | ||
| time: message.time || message.createdAt, | ||
|
Comment on lines
+72
to
+74
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. The code mixes shapes when formatting outgoing WS messages: it uses
Comment on lines
+72
to
+74
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. Accessing |
||
| text: message.text, | ||
| }; | ||
|
Comment on lines
+72
to
+76
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. The |
||
|
|
||
| rooms[roomId].forEach((client) => { | ||
| if (client.readyState === 1) { | ||
| client.send(JSON.stringify(formatted)); | ||
| } | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { client } from '../db.js'; | ||
| import { User } from './user.js'; | ||
| import { Room } from './room.js'; | ||
|
|
||
| export const Message = client.define( | ||
| 'message', | ||
| { | ||
| id: { | ||
| type: DataTypes.UUID, | ||
| defaultValue: DataTypes.UUIDV4, | ||
| allowNull: false, | ||
| primaryKey: true, | ||
| }, | ||
| text: { | ||
| type: DataTypes.STRING, | ||
|
Comment on lines
+15
to
+16
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. Use
Comment on lines
+15
to
+16
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. Use a longer text type for message bodies. |
||
| allowNull: false, | ||
|
Comment on lines
+15
to
+17
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. The |
||
| }, | ||
| createdAt: { | ||
| type: DataTypes.DATE, | ||
| defaultValue: DataTypes.NOW, | ||
| allowNull: false, | ||
| }, | ||
|
Comment on lines
+19
to
+23
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. You define
Comment on lines
+19
to
+23
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.
|
||
| }, | ||
|
Comment on lines
+19
to
+24
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. Define |
||
| { | ||
| updatedAt: false, | ||
| tableName: 'messages', | ||
| }, | ||
| ); | ||
|
|
||
| Message.belongsTo(User, { foreignKey: 'userId' }); | ||
| User.hasMany(Message, { foreignKey: 'userId' }); | ||
|
|
||
| Message.belongsTo(Room, { foreignKey: 'roomId' }); | ||
| Room.hasMany(Message, { foreignKey: 'roomId' }); | ||
|
Comment on lines
+31
to
+35
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.
Comment on lines
+31
to
+35
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. Associations are correct, but they rely on implicitly-created FK columns. After adding explicit |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { client } from '../db.js'; | ||
| import { User } from './user.js'; | ||
|
|
||
| export const Room = client.define('room', { | ||
| id: { | ||
| type: DataTypes.UUID, | ||
| defaultValue: DataTypes.UUIDV4, | ||
| allowNull: false, | ||
| primaryKey: true, | ||
| }, | ||
| title: { | ||
| type: DataTypes.STRING, | ||
| allowNull: false, | ||
| }, | ||
| description: { | ||
| type: DataTypes.STRING, | ||
| allowNull: false, | ||
|
Comment on lines
+16
to
+18
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.
Comment on lines
+16
to
+18
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. The model sets
Comment on lines
+16
to
+18
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.
|
||
| }, | ||
| }); | ||
|
|
||
| Room.belongsTo(User); | ||
| User.hasMany(Room); | ||
|
Comment on lines
+22
to
+23
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. This model and its
Comment on lines
+22
to
+23
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. Association uses default FK options. To guarantee every room is associated with a user (matching the controller/service which requires
Comment on lines
+22
to
+23
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. Associations are declared but there is no explicit
Comment on lines
+22
to
+23
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. When adding the explicit |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { DataTypes } from 'sequelize'; | ||
| import { client } from '../db.js'; | ||
|
|
||
| export const User = client.define('user', { | ||
| id: { | ||
| type: DataTypes.UUID, | ||
| defaultValue: DataTypes.UUIDV4, | ||
| allowNull: false, | ||
| primaryKey: true, | ||
| }, | ||
| name: { | ||
| type: DataTypes.STRING, | ||
| unique: true, | ||
| allowNull: false, | ||
| }, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import express from 'express'; | ||
| import { messageController } from '../controllers/message.controller.js'; | ||
|
|
||
| export const messageRoute = new express.Router(); | ||
|
|
||
| messageRoute.get('/rooms/:roomId/messages', messageController.getMessages); | ||
| messageRoute.post('/rooms/:roomId/messages', messageController.create); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import express from 'express'; | ||
| import { roomController } from '../controllers/rooms.controller.js'; | ||
|
|
||
| export const roomsRoute = new express.Router(); | ||
|
|
||
| roomsRoute.get('/', roomController.getAllRooms); | ||
| roomsRoute.post('/', roomController.createRoom); | ||
|
Comment on lines
+6
to
+7
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. The file registers GET, POST, PATCH and DELETE routes which cover list, create, rename/update and delete room operations. However there is no explicit HTTP "join room" endpoint here. If joining is intentionally handled via WebSocket (src/index.js), please document that for clients or add an HTTP join handler for clients that expect to join via REST. |
||
| roomsRoute.patch('/:roomId', roomController.updateRoom); | ||
| roomsRoute.delete('/:roomId', roomController.deleteRoom); | ||
|
Comment on lines
+8
to
+9
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. Consider adding validation for |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import express from 'express'; | ||
| import { userController } from '../controllers/user.controller.js'; | ||
|
|
||
| export const userRoute = new express.Router(); | ||
|
|
||
| userRoute.post('/', userController.create); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { Message } from '../models/message.js'; | ||
|
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. The service imports only |
||
| import { User } from '../models/user.js'; | ||
|
|
||
| const getAllMessagesInRoom = async (roomId) => { | ||
| if (!roomId) { | ||
| throw new Error('roomId is required'); | ||
| } | ||
|
|
||
| const messages = await Message.findAll({ | ||
| where: { roomId }, | ||
| include: [{ model: User, attributes: ['name'] }], | ||
| order: [['createdAt', 'ASC']], | ||
| }); | ||
|
|
||
| return messages.map((msg) => ({ | ||
| author: msg.user?.name || 'Unknown', | ||
|
Comment on lines
+15
to
+16
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. When including |
||
| time: msg.createdAt, | ||
| text: msg.text, | ||
| roomId: msg.roomId, | ||
| })); | ||
| }; | ||
|
|
||
| const createMessageInRoom = async (text, userId, roomId) => { | ||
| if (!text || !userId || !roomId) { | ||
| throw new Error('Missing required fields'); | ||
| } | ||
|
|
||
| const newMessage = await Message.create({ text, userId, roomId }); | ||
|
|
||
| const messageWithUser = await Message.findByPk(newMessage.id, { | ||
| include: [{ model: User, attributes: ['name'] }], | ||
| }); | ||
|
Comment on lines
+30
to
+32
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. After |
||
|
|
||
| return { | ||
| author: messageWithUser.user?.name || 'Unknown', | ||
|
Comment on lines
+34
to
+35
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. Same issue as above: |
||
| time: messageWithUser.createdAt, | ||
| text: messageWithUser.text, | ||
| roomId: messageWithUser.roomId, | ||
| }; | ||
|
Comment on lines
+34
to
+39
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. This service returns a normalized plain object ( |
||
| }; | ||
|
|
||
| export const messageService = { | ||
| getAllMessagesInRoom, | ||
| createMessageInRoom, | ||
|
Comment on lines
+42
to
+44
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. Consider normalizing the returned value from both functions to a consistent plain payload (not Sequelize instances). Controllers and WebSocket code assume they can serialize |
||
| }; | ||
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.
Import path is incorrect; there is no
../models/user.model.jsfile. Import the actual User model (e.g.../models/user.js) soUser.findByPk/Sequelize won't fail at runtime.