generated from lucien/api-template
add: added replies to messages
This commit is contained in:
parent
05dd75fa74
commit
b10a472ed7
10 changed files with 607 additions and 306 deletions
|
@ -4,17 +4,18 @@ const {
|
||||||
getChannels,
|
getChannels,
|
||||||
getChannel,
|
getChannel,
|
||||||
addChannel,
|
addChannel,
|
||||||
getMessages,
|
|
||||||
getMessage,
|
getMessage,
|
||||||
|
getMessages,
|
||||||
addMessage,
|
addMessage,
|
||||||
deleteMessage,
|
deleteMessage,
|
||||||
addMention,
|
addMention,
|
||||||
getMentions,
|
getMentions,
|
||||||
getUserByUsername,
|
getUserByUsername,
|
||||||
deleMentions,
|
|
||||||
deleteChannelMentions,
|
|
||||||
deleteChannelMessages,
|
deleteChannelMessages,
|
||||||
deleteChannel
|
deleteChannel,
|
||||||
|
setHasReplies,
|
||||||
|
addReply,
|
||||||
|
getMessageReplies
|
||||||
} = require('../libs/mysql');
|
} = require('../libs/mysql');
|
||||||
const rateLimit = require("express-rate-limit");
|
const rateLimit = require("express-rate-limit");
|
||||||
const slowDown = require("express-slow-down");
|
const slowDown = require("express-slow-down");
|
||||||
|
@ -70,7 +71,6 @@ router.post('/:name/purge', async (req, res) => {
|
||||||
return res.status(401).send({ error: 'Unauthorized' });
|
return res.status(401).send({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteChannelMentions(connection, channel[0].id);
|
|
||||||
await deleteChannelMessages(connection, channel[0].id);
|
await deleteChannelMessages(connection, channel[0].id);
|
||||||
connection.end();
|
connection.end();
|
||||||
|
|
||||||
|
@ -111,6 +111,23 @@ router.post('/:name/delete', async (req, res) => {
|
||||||
res.send({ message: 'Channel deleted' });
|
res.send({ message: 'Channel deleted' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getReplies(message, connection) {
|
||||||
|
const replies = await getMessageReplies(connection, message.id);
|
||||||
|
for (const reply of replies) {
|
||||||
|
if (reply.has_replies) {
|
||||||
|
const subReplies = await getReplies(reply, connection);
|
||||||
|
reply.replies = subReplies;
|
||||||
|
}
|
||||||
|
if (reply.content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, reply.id);
|
||||||
|
reply.mentions = mentions;
|
||||||
|
} else {
|
||||||
|
reply.mentions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replies;
|
||||||
|
}
|
||||||
|
|
||||||
router.get('/:name/messages', async (req, res) => {
|
router.get('/:name/messages', async (req, res) => {
|
||||||
const name = req.params.name;
|
const name = req.params.name;
|
||||||
const connection = await getConnection();
|
const connection = await getConnection();
|
||||||
|
@ -128,6 +145,14 @@ router.get('/:name/messages', async (req, res) => {
|
||||||
} else {
|
} else {
|
||||||
message.mentions = [];
|
message.mentions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.has_replies) {
|
||||||
|
const replies = await getReplies(message, connection);
|
||||||
|
message.replies = replies;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message.replies = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
|
@ -175,46 +200,6 @@ router.post('/:name/messages/send', speedLimiter, limiter, checkAuth, async (req
|
||||||
res.send({ message: 'Message sent' });
|
res.send({ message: 'Message sent' });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/:name/messages/delete', checkAuth, async (req, res) => {
|
|
||||||
const { message_id } = req.body;
|
|
||||||
const name = req.params.name;
|
|
||||||
const user = req.user;
|
|
||||||
|
|
||||||
if (!message_id) {
|
|
||||||
return res.status(400).send({ error: 'Missing message_id' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = await getConnection();
|
|
||||||
|
|
||||||
const message = await getMessage(connection, message_id);
|
|
||||||
if (!message[0]) {
|
|
||||||
connection.end();
|
|
||||||
return res.status(400).send({ error: 'No message found' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const channel = await getChannel(connection, name);
|
|
||||||
if (!channel[0]) {
|
|
||||||
connection.end();
|
|
||||||
return res.status(400).send({ error: 'No channel found' });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.id !== channel[0].owner_id && user.id !== message[0].user_id && user.admin !== 1) {
|
|
||||||
connection.end();
|
|
||||||
return res.status(401).send({ error: 'Unauthorized' });
|
|
||||||
}
|
|
||||||
|
|
||||||
await deleteMessage(connection, message_id);
|
|
||||||
connection.end();
|
|
||||||
|
|
||||||
req.sockets.emit({
|
|
||||||
type: 'delete_message',
|
|
||||||
channel_id: channel[0].id,
|
|
||||||
user_id: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
res.send({ message: 'Message deleted' });
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/add', speedLimiter, limiter, checkAuth, async (req, res) => {
|
router.post('/add', speedLimiter, limiter, checkAuth, async (req, res) => {
|
||||||
const { name, description } = req.body;
|
const { name, description } = req.body;
|
||||||
const user = req.user;
|
const user = req.user;
|
||||||
|
|
|
@ -14,6 +14,7 @@ router.get('/', async (req, res) => {
|
||||||
} else {
|
} else {
|
||||||
message.mentions = [];
|
message.mentions = [];
|
||||||
}
|
}
|
||||||
|
message.replies = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
|
|
156
back/api/messages.js
Normal file
156
back/api/messages.js
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
const express = require('express');
|
||||||
|
const {
|
||||||
|
getConnection,
|
||||||
|
getChannel,
|
||||||
|
getMessage,
|
||||||
|
deleteMessage,
|
||||||
|
addMention,
|
||||||
|
getMentions,
|
||||||
|
getUserByUsername,
|
||||||
|
setHasReplies,
|
||||||
|
addReply,
|
||||||
|
getMessageReplies
|
||||||
|
} = require('../libs/mysql');
|
||||||
|
const rateLimit = require("express-rate-limit");
|
||||||
|
const slowDown = require("express-slow-down");
|
||||||
|
const { checkAuth } = require('../libs/middlewares');
|
||||||
|
|
||||||
|
const limiter = rateLimit({
|
||||||
|
windowMs: 1 * 1000,
|
||||||
|
max: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const speedLimiter = slowDown({
|
||||||
|
windowMs: 1 * 1000,
|
||||||
|
delayAfter: 2,
|
||||||
|
delayMs: () => 5000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
async function getReplies(message, connection) {
|
||||||
|
const replies = await getMessageReplies(connection, message.id);
|
||||||
|
for (const reply of replies) {
|
||||||
|
if (reply.has_replies) {
|
||||||
|
const subReplies = await getReplies(reply, connection);
|
||||||
|
reply.replies = subReplies;
|
||||||
|
}
|
||||||
|
if (reply.content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, reply.id);
|
||||||
|
reply.mentions = mentions;
|
||||||
|
} else {
|
||||||
|
reply.mentions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replies;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/:message_id', async (req, res) => {
|
||||||
|
const message_id = req.params.message_id;
|
||||||
|
const connection = await getConnection();
|
||||||
|
const message = await getMessage(connection, message_id);
|
||||||
|
if (!message[0]) {
|
||||||
|
connection.end();
|
||||||
|
return res.send({ error: 'No message found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message[0].content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, message.id);
|
||||||
|
message[0].mentions = mentions;
|
||||||
|
} else {
|
||||||
|
message[0].mentions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message[0].has_replies) {
|
||||||
|
const replies = await getReplies(message[0], connection);
|
||||||
|
message[0].replies = replies;
|
||||||
|
} else {
|
||||||
|
message[0].replies = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.end();
|
||||||
|
res.send(message[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/:message_id/reply', speedLimiter, limiter, checkAuth, async (req, res) => {
|
||||||
|
const { message } = req.body;
|
||||||
|
const { message_id } = req.params;
|
||||||
|
const user = req.user;
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return res.status(400).send({ error: 'Missing parameters' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = await getConnection();
|
||||||
|
|
||||||
|
const originalMessage = await getMessage(connection, message_id);
|
||||||
|
if (!originalMessage[0]) {
|
||||||
|
connection.end();
|
||||||
|
return res.status(400).send({ error: 'No message found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = await getChannel(connection, originalMessage[0].channel_name);
|
||||||
|
const sent_message = await addReply(connection, channel[0].id, user.id, message.replace("\"", "'"), message_id);
|
||||||
|
await setHasReplies(connection, message_id, true);
|
||||||
|
const new_message_id = sent_message.insertId;
|
||||||
|
|
||||||
|
for (const word of message.split(' ')) {
|
||||||
|
if (word.startsWith('@')) {
|
||||||
|
const username = word.substring(1);
|
||||||
|
const mentionedUser = await getUserByUsername(connection, username);
|
||||||
|
if (mentionedUser[0]) {
|
||||||
|
await addMention(connection, new_message_id, mentionedUser[0].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.end();
|
||||||
|
|
||||||
|
req.sockets.emit({
|
||||||
|
type: 'new_message',
|
||||||
|
channel_id: channel[0].id,
|
||||||
|
user_id: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.send({ message: 'Reply sent' });
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/:message_id/delete', checkAuth, async (req, res) => {
|
||||||
|
const { message_id } = req.params;
|
||||||
|
const user = req.user;
|
||||||
|
|
||||||
|
const connection = await getConnection();
|
||||||
|
|
||||||
|
const message = await getMessage(connection, message_id);
|
||||||
|
if (!message[0]) {
|
||||||
|
connection.end();
|
||||||
|
return res.status(400).send({ error: 'No message found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = await getChannel(connection, message[0].channel_name);
|
||||||
|
|
||||||
|
if (user.id !== channel[0].owner_id && user.id !== message[0].user_id && user.admin !== 1) {
|
||||||
|
connection.end();
|
||||||
|
return res.status(401).send({ error: 'Unauthorized' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message[0].reply_to_id) {
|
||||||
|
const replies = await getMessageReplies(connection, message[0].reply_to_id);
|
||||||
|
if (replies.length === 1) {
|
||||||
|
await setHasReplies(connection, replyToId, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteMessage(connection, message_id);
|
||||||
|
connection.end();
|
||||||
|
|
||||||
|
req.sockets.emit({
|
||||||
|
type: 'delete_message',
|
||||||
|
channel_id: channel[0].id,
|
||||||
|
user_id: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.send({ message: 'Message deleted' });
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -37,6 +37,7 @@ router.get('/:username/lastmessages', async (req, res) => {
|
||||||
} else {
|
} else {
|
||||||
message.mentions = [];
|
message.mentions = [];
|
||||||
}
|
}
|
||||||
|
message.replies = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
|
|
|
@ -9,6 +9,41 @@ function getConnection() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +---------------------------+
|
||||||
|
// | Users |
|
||||||
|
// +---------------------------+
|
||||||
|
|
||||||
|
function addUser(connection, username, password) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`INSERT INTO users (username, password) VALUES (?, ?)`,
|
||||||
|
[username, password],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteUser(connection, id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`DELETE FROM users WHERE id = ?`,
|
||||||
|
[id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getUsers(connection) {
|
function getUsers(connection) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
|
@ -27,22 +62,7 @@ function getUser(connection, id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`SELECT * FROM users WHERE id = ?`,
|
`SELECT * FROM users WHERE id = ?`,
|
||||||
[id], // Use parameterized query
|
[id],
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchUser(connection, search) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`SELECT * FROM users WHERE username LIKE ? LIMIT 5`,
|
|
||||||
[`%${search}%`], // Use parameterized query
|
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -57,7 +77,7 @@ function getUserByUsername(connection, username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`SELECT * FROM users WHERE username = ?`,
|
`SELECT * FROM users WHERE username = ?`,
|
||||||
[username], // Use parameterized query
|
[username],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -68,11 +88,11 @@ function getUserByUsername(connection, username) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addUser(connection, username, password) {
|
function searchUser(connection, search) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`INSERT INTO users (username, password) VALUES (?, ?)`,
|
`SELECT * FROM users WHERE username LIKE ? LIMIT 5`,
|
||||||
[username, password], // Use parameterized query
|
[`%${search}%`],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -83,46 +103,11 @@ function addUser(connection, username, password) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserLastMessages(connection, username) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name
|
|
||||||
FROM messages
|
|
||||||
JOIN users ON messages.user_id = users.id
|
|
||||||
JOIN channels ON messages.channel_id = channels.id
|
|
||||||
WHERE username = ?
|
|
||||||
ORDER BY date DESC LIMIT 5`,
|
|
||||||
[username], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteUser(connection, id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`DELETE FROM users WHERE id = ?`,
|
|
||||||
[id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function setUserPfp(connection, id, pfp) {
|
function setUserPfp(connection, id, pfp) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`UPDATE users SET pfp = ? WHERE id = ?`,
|
`UPDATE users SET pfp = ? WHERE id = ?`,
|
||||||
[pfp, id], // Use parameterized query
|
[pfp, id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -137,7 +122,7 @@ function setUserUsername(connection, id, username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`UPDATE users SET username = ? WHERE id = ?`,
|
`UPDATE users SET username = ? WHERE id = ?`,
|
||||||
[username, id], // Use parameterized query
|
[username, id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -152,7 +137,41 @@ function setUserPassword(connection, id, password) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`UPDATE users SET password = ? WHERE id = ?`,
|
`UPDATE users SET password = ? WHERE id = ?`,
|
||||||
[password, id], // Use parameterized query
|
[password, id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// +---------------------------+
|
||||||
|
// | Channels |
|
||||||
|
// +---------------------------+
|
||||||
|
|
||||||
|
function addChannel(connection, name, description, owner_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`INSERT INTO channels (name, description, owner_id) VALUES (?, ?, ?)`,
|
||||||
|
[name, description, owner_id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteChannel(connection, channel_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`DELETE FROM channels WHERE id = ?`,
|
||||||
|
[channel_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -177,6 +196,24 @@ function getChannels(connection) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChannel(connection, name) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT channels.id, name, description, owner_id, username AS owner_username
|
||||||
|
FROM channels
|
||||||
|
JOIN users ON channels.owner_id = users.id
|
||||||
|
WHERE name = ?`,
|
||||||
|
[name],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getActiveChannels(connection) {
|
function getActiveChannels(connection) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
|
@ -223,7 +260,7 @@ function searchChannels(connection, search) {
|
||||||
JOIN users ON channels.owner_id = users.id
|
JOIN users ON channels.owner_id = users.id
|
||||||
WHERE name LIKE ?
|
WHERE name LIKE ?
|
||||||
LIMIT 5`,
|
LIMIT 5`,
|
||||||
[`%${search}%`], // Use parameterized query
|
[`%${search}%`],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -234,116 +271,30 @@ function searchChannels(connection, search) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChannel(connection, name) {
|
// +---------------------------+
|
||||||
return new Promise((resolve, reject) => {
|
// | Messages |
|
||||||
connection.query(
|
// +---------------------------+
|
||||||
`SELECT channels.id, name, description, owner_id, username AS owner_username
|
|
||||||
FROM channels
|
|
||||||
JOIN users ON channels.owner_id = users.id
|
|
||||||
WHERE name = ?`,
|
|
||||||
[name], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addChannel(connection, name, description, owner_id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`INSERT INTO channels (name, description, owner_id) VALUES (?, ?, ?)`,
|
|
||||||
[name, description, owner_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteChannel(connection, channel_id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`DELETE FROM channels WHERE id = ?`,
|
|
||||||
[channel_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessages(connection, channel_id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name
|
|
||||||
FROM messages
|
|
||||||
JOIN users ON messages.user_id = users.id
|
|
||||||
JOIN channels ON messages.channel_id = channels.id
|
|
||||||
WHERE channel_id = ?
|
|
||||||
ORDER BY date DESC`,
|
|
||||||
[channel_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLastMessages(connection) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name
|
|
||||||
FROM messages
|
|
||||||
JOIN users ON messages.user_id = users.id
|
|
||||||
JOIN channels ON messages.channel_id = channels.id
|
|
||||||
ORDER BY date DESC LIMIT 5`,
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessage(connection, message_id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name
|
|
||||||
FROM messages
|
|
||||||
JOIN users ON messages.user_id = users.id
|
|
||||||
JOIN channels ON messages.channel_id = channels.id
|
|
||||||
WHERE messages.id = ?`,
|
|
||||||
[message_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMessage(connection, channel_id, user_id, message) {
|
function addMessage(connection, channel_id, user_id, message) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`INSERT INTO messages (channel_id, user_id, content, date) VALUES (?, ?, ?, ?)`,
|
`INSERT INTO messages (channel_id, user_id, content, date) VALUES (?, ?, ?, ?)`,
|
||||||
[channel_id, user_id, message, Math.floor(Date.now() / 1000)], // Use parameterized query
|
[channel_id, user_id, message, Math.floor(Date.now() / 1000)],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addReply(connection, channel_id, user_id, message, message_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`INSERT INTO messages (channel_id, user_id, content, date, reply_to_id) VALUES (?, ?, ?, ?, ?)`,
|
||||||
|
[channel_id, user_id, message, Math.floor(Date.now() / 1000), message_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -358,7 +309,7 @@ function deleteMessage(connection, message_id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`DELETE FROM messages WHERE id = ?`,
|
`DELETE FROM messages WHERE id = ?`,
|
||||||
[message_id], // Use parameterized query
|
[message_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -373,7 +324,7 @@ function deleteChannelMessages(connection, channel_id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`DELETE FROM messages WHERE channel_id = ?`,
|
`DELETE FROM messages WHERE channel_id = ?`,
|
||||||
[channel_id], // Use parameterized query
|
[channel_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -384,11 +335,16 @@ function deleteChannelMessages(connection, channel_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUserMessages(connection, user_id) {
|
function getMessages(connection, channel_id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`DELETE FROM messages WHERE user_id = ?`,
|
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name, has_replies
|
||||||
[user_id], // Use parameterized query
|
FROM messages
|
||||||
|
JOIN users ON messages.user_id = users.id
|
||||||
|
JOIN channels ON messages.channel_id = channels.id
|
||||||
|
WHERE channel_id = ? AND reply_to_id IS NULL
|
||||||
|
ORDER BY date DESC`,
|
||||||
|
[channel_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -399,11 +355,106 @@ function deleteUserMessages(connection, user_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMessage(connection, message_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name, has_replies
|
||||||
|
FROM messages
|
||||||
|
JOIN users ON messages.user_id = users.id
|
||||||
|
JOIN channels ON messages.channel_id = channels.id
|
||||||
|
WHERE messages.id = ?`,
|
||||||
|
[message_id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLastMessages(connection) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name, has_replies
|
||||||
|
FROM messages
|
||||||
|
JOIN users ON messages.user_id = users.id
|
||||||
|
JOIN channels ON messages.channel_id = channels.id
|
||||||
|
ORDER BY date DESC LIMIT 5`,
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserLastMessages(connection, username) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name, has_replies
|
||||||
|
FROM messages
|
||||||
|
JOIN users ON messages.user_id = users.id
|
||||||
|
JOIN channels ON messages.channel_id = channels.id
|
||||||
|
WHERE username = ?
|
||||||
|
ORDER BY date DESC LIMIT 5`,
|
||||||
|
[username],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageReplies(connection, message_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT messages.id, user_id, username, content, date, channels.name AS channel_name, has_replies
|
||||||
|
FROM messages
|
||||||
|
JOIN users ON messages.user_id = users.id
|
||||||
|
JOIN channels ON messages.channel_id = channels.id
|
||||||
|
WHERE reply_to_id = ?`,
|
||||||
|
[message_id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHasReplies(connection, message_id, has_replies) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`UPDATE messages SET has_replies = ? WHERE id = ?`,
|
||||||
|
[has_replies, message_id],
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// +---------------------------+
|
||||||
|
// | Mentions |
|
||||||
|
// +---------------------------+
|
||||||
|
|
||||||
function addMention(connection, message_id, user_id) {
|
function addMention(connection, message_id, user_id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`INSERT INTO mentions (message_id, user_id) VALUES (?, ?)`,
|
`INSERT INTO mentions (message_id, user_id) VALUES (?, ?)`,
|
||||||
[message_id, user_id], // Use parameterized query
|
[message_id, user_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -420,7 +471,7 @@ function getMentions(connection, message_id) {
|
||||||
`SELECT users.username FROM mentions
|
`SELECT users.username FROM mentions
|
||||||
JOIN users ON mentions.user_id = users.id
|
JOIN users ON mentions.user_id = users.id
|
||||||
WHERE message_id = ?`,
|
WHERE message_id = ?`,
|
||||||
[message_id], // Use parameterized query
|
[message_id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -431,11 +482,15 @@ function getMentions(connection, message_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleMentions(connection, message_id) {
|
// +---------------------------+
|
||||||
|
// | Emojis |
|
||||||
|
// +---------------------------+
|
||||||
|
|
||||||
|
function addEmoji(connection, name, file) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`DELETE FROM mentions WHERE message_id = ?`,
|
`INSERT INTO emojis (name, file) VALUES (?, ?)`,
|
||||||
[message_id], // Use parameterized query
|
[name, file],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -446,27 +501,11 @@ function deleMentions(connection, message_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteChannelMentions(connection, channel_id) {
|
function deleteEmoji(connection, id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`DELETE FROM mentions WHERE message_id IN
|
`DELETE FROM emojis WHERE id = ?`,
|
||||||
(SELECT id FROM messages WHERE channel_id = ?)`,
|
[id],
|
||||||
[channel_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteUserMentions(connection, user_id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`DELETE FROM mentions WHERE user_id = ?`,
|
|
||||||
[user_id], // Use parameterized query
|
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -491,41 +530,11 @@ function getEmojis(connection) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addEmoji(connection, name, file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`INSERT INTO emojis (name, file) VALUES (?, ?)`,
|
|
||||||
[name, file], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteEmoji(connection, id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
connection.query(
|
|
||||||
`DELETE FROM emojis WHERE id = ?`,
|
|
||||||
[id], // Use parameterized query
|
|
||||||
(error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(new Error(error));
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEmoji(connection, id) {
|
function getEmoji(connection, id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`SELECT * FROM emojis WHERE id = ?`,
|
`SELECT * FROM emojis WHERE id = ?`,
|
||||||
[id], // Use parameterized query
|
[id],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -540,7 +549,7 @@ function getEmojiByName(connection, name) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`SELECT * FROM emojis WHERE name = ?`,
|
`SELECT * FROM emojis WHERE name = ?`,
|
||||||
[name], // Use parameterized query
|
[name],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -555,7 +564,7 @@ function searchEmojis(connection, search) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
`SELECT * FROM emojis WHERE name LIKE ? LIMIT 5`,
|
`SELECT * FROM emojis WHERE name LIKE ? LIMIT 5`,
|
||||||
[`%${search}%`], // Use parameterized query
|
[`%${search}%`],
|
||||||
(error, result) => {
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
|
@ -567,39 +576,43 @@ function searchEmojis(connection, search) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getUsers,
|
|
||||||
getConnection,
|
getConnection,
|
||||||
|
|
||||||
|
addUser,
|
||||||
|
deleteUser,
|
||||||
|
getUsers,
|
||||||
getUser,
|
getUser,
|
||||||
searchUser,
|
searchUser,
|
||||||
getUserByUsername,
|
getUserByUsername,
|
||||||
addUser,
|
|
||||||
deleteUser,
|
|
||||||
setUserPfp,
|
setUserPfp,
|
||||||
setUserUsername,
|
setUserUsername,
|
||||||
setUserPassword,
|
setUserPassword,
|
||||||
getUserLastMessages,
|
|
||||||
|
addChannel,
|
||||||
|
deleteChannel,
|
||||||
getChannels,
|
getChannels,
|
||||||
|
getChannel,
|
||||||
getActiveChannels,
|
getActiveChannels,
|
||||||
getNewChannels,
|
getNewChannels,
|
||||||
searchChannels,
|
searchChannels,
|
||||||
getChannel,
|
|
||||||
addChannel,
|
|
||||||
deleteChannel,
|
|
||||||
getMessages,
|
|
||||||
getLastMessages,
|
|
||||||
getMessage,
|
|
||||||
addMessage,
|
addMessage,
|
||||||
|
addReply,
|
||||||
deleteMessage,
|
deleteMessage,
|
||||||
deleteChannelMessages,
|
deleteChannelMessages,
|
||||||
deleteUserMessages,
|
getMessages,
|
||||||
|
getMessage,
|
||||||
|
getUserLastMessages,
|
||||||
|
getLastMessages,
|
||||||
|
getMessageReplies,
|
||||||
|
setHasReplies,
|
||||||
|
|
||||||
addMention,
|
addMention,
|
||||||
getMentions,
|
getMentions,
|
||||||
deleMentions,
|
|
||||||
deleteUserMentions,
|
|
||||||
deleteChannelMentions,
|
|
||||||
getEmojis,
|
|
||||||
addEmoji,
|
addEmoji,
|
||||||
deleteEmoji,
|
deleteEmoji,
|
||||||
|
getEmojis,
|
||||||
getEmoji,
|
getEmoji,
|
||||||
getEmojiByName,
|
getEmojiByName,
|
||||||
searchEmojis,
|
searchEmojis,
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Message, User, Channel } from "../types";
|
import { Message, User, Channel, Users, Emojis } from "../types";
|
||||||
|
import { useState, createRef, useEffect } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
import "../styles/MessageComponent.css";
|
import "../styles/MessageComponent.css";
|
||||||
|
|
||||||
export default function MessageComponent({ message, user, channel, deleteMessage }: {
|
export default function MessageComponent({ message, user, channel }: {
|
||||||
message: Message;
|
message: Message;
|
||||||
user: User | undefined;
|
user: User | undefined;
|
||||||
channel: Channel | undefined;
|
channel: Channel | undefined;
|
||||||
deleteMessage: ((messageId: number) => void) | undefined;
|
|
||||||
}) {
|
}) {
|
||||||
|
const [reply, setReply] = useState(false);
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
const [replyContent, setReplyContent] = useState("");
|
||||||
|
const [searchedUsers, setSearchedUsers] = useState<Users>([]);
|
||||||
|
const [searchedEmojis, setSearchedEmojis] = useState<Emojis>([]);
|
||||||
|
const ref = createRef<HTMLInputElement>();
|
||||||
|
|
||||||
function getMessageArray(message: Message) {
|
function getMessageArray(message: Message) {
|
||||||
const array = []
|
const array = []
|
||||||
|
@ -39,6 +46,70 @@ export default function MessageComponent({ message, user, channel, deleteMessage
|
||||||
return array.filter((word) => word !== '');
|
return array.filter((word) => word !== '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleReply(e: React.FormEvent<HTMLFormElement>, messageId: number) {
|
||||||
|
e.preventDefault();
|
||||||
|
axios
|
||||||
|
.post(`/api/messages/${messageId}/reply`, {
|
||||||
|
token: token,
|
||||||
|
message: replyContent,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setReplyContent("");
|
||||||
|
setReply(false);
|
||||||
|
setSearchedUsers([]);
|
||||||
|
setSearchedEmojis([]);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err.response.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDelete() {
|
||||||
|
if (!window.confirm("Are you sure you want to delete this message?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.post(`/api/messages/${message.id}/delete`, {
|
||||||
|
token: token,
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err.response.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const words = replyContent.toString().split(" ");
|
||||||
|
const lastWord = words[words.length - 1];
|
||||||
|
|
||||||
|
if (lastWord && lastWord.startsWith("@")) {
|
||||||
|
const username = lastWord.slice(1);
|
||||||
|
axios
|
||||||
|
.get(`/api/searchuser?search=${username}`)
|
||||||
|
.then((res) => {
|
||||||
|
setSearchedUsers(res.data);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err.response.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setSearchedUsers([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastWord && lastWord.startsWith(":")) {
|
||||||
|
const emojiName = lastWord.slice(1);
|
||||||
|
axios
|
||||||
|
.get(`/api/searchemojis?search=${emojiName}`)
|
||||||
|
.then((res) => {
|
||||||
|
setSearchedEmojis(res.data);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err.response.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setSearchedEmojis([]);
|
||||||
|
}
|
||||||
|
}, [replyContent]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={message.id} className="message">
|
<div key={message.id} className="message">
|
||||||
<div className="message-content">
|
<div className="message-content">
|
||||||
|
@ -70,13 +141,81 @@ export default function MessageComponent({ message, user, channel, deleteMessage
|
||||||
<img src="/le_poisson_steve.png" alt="Le poisson steve" className="fish" />
|
<img src="/le_poisson_steve.png" alt="Le poisson steve" className="fish" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{channel && deleteMessage ? (
|
{channel?.owner_id == user?.id || user?.admin == 1 || user?.username == message.username ? (
|
||||||
user?.id === message.user_id || user?.id === channel?.owner_id || user?.admin === 1) && (
|
user?.id === message.user_id || user?.id === channel?.owner_id || user?.admin === 1) && (
|
||||||
<button onClick={() => {deleteMessage(message.id)}}>Delete</button>
|
<button onClick={handleDelete}>Delete</button>
|
||||||
) : (
|
) : (
|
||||||
<p>In <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
|
<p>In <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
|
||||||
)
|
)}
|
||||||
}
|
{channel && user && !reply && (
|
||||||
|
<button onClick={() => setReply(true)}>Reply</button>
|
||||||
|
)}
|
||||||
|
{reply && (
|
||||||
|
<form onSubmit={(e) => handleReply(e, message.id)} className="message-form">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Message"
|
||||||
|
value={replyContent}
|
||||||
|
onChange={(e) => setReplyContent(e.target.value)}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
<button type="submit">Send</button>
|
||||||
|
{searchedUsers.length > 0 && (
|
||||||
|
<div className="mentions">
|
||||||
|
{searchedUsers.map((user) => (
|
||||||
|
<div key={user.id} className="mention">
|
||||||
|
<Link to={`/u/${user.username}`}>{user.username}</Link>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setReplyContent(
|
||||||
|
replyContent.split(" ").slice(0, -1).join(" ") + " @" + user.username + " "
|
||||||
|
);
|
||||||
|
setSearchedUsers([]);
|
||||||
|
ref.current?.focus();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Mention
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{searchedEmojis.length > 0 && (
|
||||||
|
<div className="emojis">
|
||||||
|
{searchedEmojis.map((emoji) => (
|
||||||
|
<div key={emoji.id} className="search-emoji">
|
||||||
|
<img src={`/api/emojis/${emoji.name}`} alt={emoji.name} className="emojis-emoji" />
|
||||||
|
<span>:{emoji.name}:</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setReplyContent(
|
||||||
|
replyContent.split(" ").slice(0, -1).join(" ") + " :" + emoji.name + ": "
|
||||||
|
);
|
||||||
|
setSearchedEmojis([]);
|
||||||
|
ref.current?.focus();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Emoji
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<button onClick={() => setReply(false)}>Cancel</button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
{message.has_replies == true && (
|
||||||
|
<div className="message-replies">
|
||||||
|
{message.replies.map((reply) => (
|
||||||
|
<MessageComponent message={reply} user={user} channel={channel} key={reply.id} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!channel && (
|
||||||
|
<p>in: <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -34,14 +34,6 @@ export default function ChannelPage({socket}: {socket: WebSocket}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteMessage(message_id: number) {
|
|
||||||
axios
|
|
||||||
.post(`/api/channels/${name}/messages/delete`, { token, message_id })
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(err.response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function purgeChannel() {
|
function purgeChannel() {
|
||||||
if (!window.confirm(`Are you sure you want to purge ${channel?.name}?`)) {
|
if (!window.confirm(`Are you sure you want to purge ${channel?.name}?`)) {
|
||||||
return;
|
return;
|
||||||
|
@ -261,7 +253,6 @@ export default function ChannelPage({socket}: {socket: WebSocket}) {
|
||||||
message={message}
|
message={message}
|
||||||
user={user}
|
user={user}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
deleteMessage={deleteMessage}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{messages.length > maxMessageToShown && (
|
{messages.length > maxMessageToShown && (
|
||||||
|
|
|
@ -165,7 +165,6 @@ export default function Home({socket}: {socket: WebSocket}) {
|
||||||
message={message}
|
message={message}
|
||||||
user={user}
|
user={user}
|
||||||
channel={undefined}
|
channel={undefined}
|
||||||
deleteMessage={undefined}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
.message {
|
.message {
|
||||||
width: 95%;
|
width: 97%;
|
||||||
border: 1px solid #270722;
|
border: 1px solid #270722;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: start;
|
||||||
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-user-pfp {
|
.message-user-pfp {
|
||||||
|
@ -37,6 +42,15 @@
|
||||||
max-height: 1em;
|
max-height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-replies {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.message {
|
.message {
|
||||||
border: 1px solid #a678af;
|
border: 1px solid #a678af;
|
||||||
|
|
|
@ -34,6 +34,8 @@ export type Message = {
|
||||||
channel_id: number
|
channel_id: number
|
||||||
channel_name: string
|
channel_name: string
|
||||||
mentions: Mentions
|
mentions: Mentions
|
||||||
|
replies: Messages
|
||||||
|
has_replies: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Messages = Message[]
|
export type Messages = Message[]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue