generated from lucien/api-template
add: added mentions
This commit is contained in:
parent
dfb6639ecf
commit
6c8f354bf6
9 changed files with 208 additions and 9 deletions
|
@ -1,5 +1,5 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { getConnection, getChannels, getChannel, addChannel, getMessages, getMessage, addMessage, deleteMessage, getLastMessages } = require('../libs/mysql');
|
const { getConnection, getChannels, getChannel, addChannel, getMessages, getMessage, addMessage, deleteMessage, addMention, getMentions, getUserByUsername, deleMentions } = require('../libs/mysql');
|
||||||
const { checkAuth } = require('../libs/middlewares');
|
const { checkAuth } = require('../libs/middlewares');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
@ -32,6 +32,16 @@ router.get('/:name/messages', async (req, res) => {
|
||||||
return res.send('No channel found');
|
return res.send('No channel found');
|
||||||
}
|
}
|
||||||
const messages = await getMessages(connection, channel[0].id);
|
const messages = await getMessages(connection, channel[0].id);
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
if (message.content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, message.id);
|
||||||
|
message.mentions = mentions;
|
||||||
|
} else {
|
||||||
|
message.mentions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
res.send(messages);
|
res.send(messages);
|
||||||
});
|
});
|
||||||
|
@ -54,7 +64,19 @@ router.post('/:name/messages/send', async (req, res) => {
|
||||||
return res.send('No channel found');
|
return res.send('No channel found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await addMessage(connection, channel[0].id, user.id, message.replace("\"", "'"));
|
const sent_message = await addMessage(connection, channel[0].id, user.id, message.replace("\"", "'"));
|
||||||
|
const 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, message_id, mentionedUser[0].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
res.send({ message: 'Message sent' });
|
res.send({ message: 'Message sent' });
|
||||||
});
|
});
|
||||||
|
@ -89,6 +111,7 @@ router.post('/:name/messages/delete', async (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteMessage(connection, message_id);
|
await deleteMessage(connection, message_id);
|
||||||
|
await deleMentions(connection, message_id);
|
||||||
connection.end();
|
connection.end();
|
||||||
res.send({ message: 'Message deleted' });
|
res.send({ message: 'Message deleted' });
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { getConnection, getLastMessages } = require('../libs/mysql');
|
const { getConnection, getLastMessages, getMentions } = require('../libs/mysql');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/', async (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
const connection = await getConnection();
|
const connection = await getConnection();
|
||||||
const messages = await getLastMessages(connection);
|
const messages = await getLastMessages(connection);
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
if (message.content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, message.id);
|
||||||
|
message.mentions = mentions;
|
||||||
|
} else {
|
||||||
|
message.mentions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
res.send(messages);
|
res.send(messages);
|
||||||
});
|
});
|
||||||
|
|
14
back/api/searchuser.js
Normal file
14
back/api/searchuser.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
const express = require('express');
|
||||||
|
const { getConnection, searchUser } = require('../libs/mysql');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/', async (req, res) => {
|
||||||
|
const { search } = req.query;
|
||||||
|
const connection = await getConnection();
|
||||||
|
const users = await searchUser(connection, search);
|
||||||
|
connection.end();
|
||||||
|
res.send(users);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -1,5 +1,5 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { getConnection, getUserByUsername, getUserLastMessages } = require('../libs/mysql');
|
const { getConnection, getUserByUsername, getUserLastMessages, getMentions } = require('../libs/mysql');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
@ -19,6 +19,16 @@ router.get('/:username/lastmessages', async (req, res) => {
|
||||||
const username = req.params.username;
|
const username = req.params.username;
|
||||||
const connection = await getConnection();
|
const connection = await getConnection();
|
||||||
const messages = await getUserLastMessages(connection, username);
|
const messages = await getUserLastMessages(connection, username);
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
if (message.content.includes('@')) {
|
||||||
|
const mentions = await getMentions(connection, message.id);
|
||||||
|
message.mentions = mentions;
|
||||||
|
} else {
|
||||||
|
message.mentions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connection.end();
|
connection.end();
|
||||||
res.send(messages);
|
res.send(messages);
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,6 +24,21 @@ function getUser(connection, id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getUserByUsername(connection, username) {
|
function getUserByUsername(connection, username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(
|
connection.query(
|
||||||
|
@ -248,9 +263,57 @@ function deleteMessage(connection, message_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMention(connection, message_id, user_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`INSERT INTO mentions (message_id, user_id) VALUES (?, ?)`,
|
||||||
|
[message_id, user_id], // Use parameterized query
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMentions(connection, message_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`SELECT users.username FROM mentions
|
||||||
|
JOIN users ON mentions.user_id = users.id
|
||||||
|
WHERE message_id = ?`,
|
||||||
|
[message_id], // Use parameterized query
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleMentions(connection, message_id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(
|
||||||
|
`DELETE FROM mentions WHERE message_id = ?`,
|
||||||
|
[message_id], // Use parameterized query
|
||||||
|
(error, result) => {
|
||||||
|
if (error) {
|
||||||
|
reject(new Error(error));
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getConnection,
|
getConnection,
|
||||||
getUser,
|
getUser,
|
||||||
|
searchUser,
|
||||||
getUserByUsername,
|
getUserByUsername,
|
||||||
addUser,
|
addUser,
|
||||||
getUserLastMessages,
|
getUserLastMessages,
|
||||||
|
@ -263,5 +326,8 @@ module.exports = {
|
||||||
getLastMessages,
|
getLastMessages,
|
||||||
getMessage,
|
getMessage,
|
||||||
addMessage,
|
addMessage,
|
||||||
deleteMessage
|
deleteMessage,
|
||||||
|
addMention,
|
||||||
|
getMentions,
|
||||||
|
deleMentions,
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ export default function ChannelPage() {
|
||||||
const [user, setUser] = useState<User>();
|
const [user, setUser] = useState<User>();
|
||||||
const [message, setMessage] = useState<string>("");
|
const [message, setMessage] = useState<string>("");
|
||||||
const [maxMessageToShown, setMaxMessageToShown] = useState<number>(10);
|
const [maxMessageToShown, setMaxMessageToShown] = useState<number>(10);
|
||||||
|
const [searchedUsers, setSearchedUsers] = useState<User[]>([]);
|
||||||
|
|
||||||
function handleSubmit(e: React.FormEvent) {
|
function handleSubmit(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -75,6 +76,26 @@ export default function ChannelPage() {
|
||||||
return () => { clearInterval(id) }
|
return () => { clearInterval(id) }
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const words = message.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);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setSearchedUsers([]);
|
||||||
|
}
|
||||||
|
}, [message]);
|
||||||
|
|
||||||
|
|
||||||
if (!channel || !messages) {
|
if (!channel || !messages) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
|
@ -91,6 +112,27 @@ export default function ChannelPage() {
|
||||||
{
|
{
|
||||||
token ? (
|
token ? (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
|
{searchedUsers.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<p>Mentions:</p>
|
||||||
|
{searchedUsers.map((user) => (
|
||||||
|
<div key={user.id}>
|
||||||
|
<Link to={`/u/${user.username}`}>{user.username}</Link>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setMessage(
|
||||||
|
message.split(" ").slice(0, -1).join(" ") + " @" + user.username + " "
|
||||||
|
);
|
||||||
|
setSearchedUsers([]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Mention
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Message"
|
placeholder="Message"
|
||||||
|
@ -109,7 +151,16 @@ export default function ChannelPage() {
|
||||||
<ul>
|
<ul>
|
||||||
{messages.slice(0, maxMessageToShown).map((message) => (
|
{messages.slice(0, maxMessageToShown).map((message) => (
|
||||||
<li key={message.id}>
|
<li key={message.id}>
|
||||||
<p><Link to={`/u/${message.username}`}>{message.username}</Link>: {message.content}</p>
|
<Link to={`/u/${message.username}`}>{message.username}</Link>:{" "}
|
||||||
|
{message.content.split(" ").map((word, index) => {
|
||||||
|
if (word.startsWith("@")) {
|
||||||
|
const mention = message.mentions.find((mention) => `@${mention.username}` === word);
|
||||||
|
if (mention) {
|
||||||
|
return <Link key={index} to={`/u/${mention.username}`}>{word}</Link>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <span key={index}>{word} </span>;
|
||||||
|
})}
|
||||||
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
||||||
{(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={() => {deleteMessage(message.id)}}>Delete</button>
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default function Home() {
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get("/api/activechannels")
|
.get("/api/activechannels")
|
||||||
.then((res) => {
|
.then((res) => {channels
|
||||||
setChannels(res.data)
|
setChannels(res.data)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -123,7 +123,16 @@ export default function Home() {
|
||||||
<ul>
|
<ul>
|
||||||
{messages?.map((message) => (
|
{messages?.map((message) => (
|
||||||
<li key={message.id}>
|
<li key={message.id}>
|
||||||
<p><Link to={`/u/${message.username}`}>{message.username}</Link>: {message.content}</p>
|
<Link to={`/u/${message.username}`}>{message.username}</Link>:{" "}
|
||||||
|
{message.content.split(" ").map((word, index) => {
|
||||||
|
if (word.startsWith("@")) {
|
||||||
|
const mention = message.mentions.find((mention) => `@${mention.username}` === word);
|
||||||
|
if (mention) {
|
||||||
|
return <Link key={index} to={`/u/${mention.username}`}>{word}</Link>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <span key={index}>{word} </span>;
|
||||||
|
})}
|
||||||
<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>
|
||||||
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -42,7 +42,16 @@ export default function UserPage() {
|
||||||
<ul>
|
<ul>
|
||||||
{messages?.map((message) => (
|
{messages?.map((message) => (
|
||||||
<li key={message.id}>
|
<li key={message.id}>
|
||||||
<p><Link to={`/u/${message.username}`}>{message.username}</Link>: {message.content}</p>
|
<Link to={`/u/${message.username}`}>{message.username}</Link>:{" "}
|
||||||
|
{message.content.split(" ").map((word, index) => {
|
||||||
|
if (word.startsWith("@")) {
|
||||||
|
const mention = message.mentions.find((mention) => `@${mention.username}` === word);
|
||||||
|
if (mention) {
|
||||||
|
return <Link key={index} to={`/u/${mention.username}`}>{word}</Link>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <span key={index}>{word} </span>;
|
||||||
|
})}
|
||||||
<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>
|
||||||
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
<p>{new Date(message.date * 1000).toLocaleString()}</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -19,6 +19,12 @@ export type RecentChannel = {
|
||||||
|
|
||||||
export type RecentChannels = RecentChannel[]
|
export type RecentChannels = RecentChannel[]
|
||||||
|
|
||||||
|
export type Mention = {
|
||||||
|
username: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Mentions = Mention[]
|
||||||
|
|
||||||
export type Message = {
|
export type Message = {
|
||||||
id: number,
|
id: number,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
|
@ -27,6 +33,7 @@ export type Message = {
|
||||||
date: number,
|
date: number,
|
||||||
channel_id: number,
|
channel_id: number,
|
||||||
channel_name: string
|
channel_name: string
|
||||||
|
mentions: Mentions
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Messages = Message[]
|
export type Messages = Message[]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue