nie wiem co zrobilem ale zmienilem tajmstamp zeby byl utc domyslnie, naprawilem statusy kontaktow a i w sumie najwazniejsze zmienilem contact_user_id na conversation_id poprostu w bazie kontaktow
This commit is contained in:
@@ -12,10 +12,11 @@ export async function getContactsList(): Promise<ContactsProps[]> {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
export async function setContactStatus(contact: string, read: boolean) {
|
||||
|
||||
export async function setContactStatus(contactId: number, read: boolean) {
|
||||
try {
|
||||
const response = await axiosClient.put(
|
||||
`/api/chat/contacts/${contact}`,
|
||||
`/api/chat/contacts/${contactId}`,
|
||||
{ status: read },
|
||||
{ withCredentials: true },
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ type MessagesAreaProps = {
|
||||
setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
|
||||
fetchPreviousMessages: (contact: number | null) => Promise<void>;
|
||||
errorMessage: string | null;
|
||||
setContactStatus: (contact: string, read: boolean) => Promise<void>;
|
||||
contactsList: ContactsProps[];
|
||||
};
|
||||
|
||||
function MessagesArea({
|
||||
@@ -30,6 +30,7 @@ function MessagesArea({
|
||||
fetchPreviousMessages,
|
||||
errorMessage,
|
||||
setMessages,
|
||||
contactsList,
|
||||
}: MessagesAreaProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const { username }: { username: string } = useOutletContext();
|
||||
@@ -101,9 +102,12 @@ function MessagesArea({
|
||||
msg.sender !== username
|
||||
) {
|
||||
setContactsList((prevContacts) => {
|
||||
if (
|
||||
!prevContacts.some((c) => c.conversation_id === msg.conversation_id)
|
||||
) {
|
||||
// Find if contact already exists
|
||||
const existingContact = prevContacts.find(
|
||||
(c) => c.conversation_id === msg.conversation_id,
|
||||
);
|
||||
|
||||
if (!existingContact) {
|
||||
sendContact(msg.sender);
|
||||
return [
|
||||
...prevContacts,
|
||||
@@ -119,11 +123,17 @@ function MessagesArea({
|
||||
}
|
||||
return prevContacts;
|
||||
});
|
||||
|
||||
// Find the existing contact from contactsList
|
||||
const existingContact = contactsList.find(
|
||||
(c) => c.conversation_id === msg.conversation_id,
|
||||
);
|
||||
|
||||
updateContactStatus(
|
||||
{
|
||||
username: msg.sender,
|
||||
read: false,
|
||||
id: msg.message_id,
|
||||
id: existingContact ? existingContact.id : msg.message_id, // Use existing contact's ID if found
|
||||
user_id: msg.sender_id,
|
||||
type: 'direct',
|
||||
conversation_id: msg.conversation_id,
|
||||
@@ -174,7 +184,12 @@ function MessagesArea({
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<span title={new Date(msg.sent_at).toLocaleTimeString()}>
|
||||
<span
|
||||
title={`${new Intl.DateTimeFormat('en-Gb', {
|
||||
timeStyle: 'medium',
|
||||
dateStyle: 'short',
|
||||
}).format(msg.sent_at)}`}
|
||||
>
|
||||
{msg.sender}: {msg.message}
|
||||
</span>
|
||||
{msg.attachment_urls && (
|
||||
|
||||
@@ -159,11 +159,13 @@ function Chat() {
|
||||
}
|
||||
|
||||
function updateContactStatus(contactObj: ContactsProps, read: boolean) {
|
||||
console.log('Update contact status: ', contactObj);
|
||||
|
||||
setContactsList((prevContacts) =>
|
||||
prevContacts.map((contact) => {
|
||||
if (contact.username === contactObj.username) {
|
||||
if (contact.conversation_id === contactObj.conversation_id) {
|
||||
if (!contactObj.read) {
|
||||
setContactStatus(contactObj.username, read);
|
||||
setContactStatus(contactObj.id, read);
|
||||
}
|
||||
return { ...contact, read: read };
|
||||
} else {
|
||||
@@ -209,12 +211,12 @@ function Chat() {
|
||||
messages={messages}
|
||||
setMessages={setMessages}
|
||||
currentContact={currentContact}
|
||||
setContactStatus={setContactStatus}
|
||||
updateContactStatus={updateContactStatus}
|
||||
messageHandler={messageHandler}
|
||||
setContactsList={setContactsList}
|
||||
fetchPreviousMessages={fetchPreviousMessages}
|
||||
errorMessage={errorMessage}
|
||||
contactsList={contactsList}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
119
server/db/db.js
119
server/db/db.js
@@ -39,7 +39,7 @@ async function createTables() {
|
||||
user_id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_username ON Accounts (username);
|
||||
`);
|
||||
@@ -54,7 +54,8 @@ async function createTables() {
|
||||
conversation_id SERIAL PRIMARY KEY,
|
||||
conversation_type VARCHAR(10) NOT NULL CHECK (conversation_type IN ('direct', 'group')),
|
||||
name VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
last_active TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_conversation_type ON Conversations (conversation_type);
|
||||
`);
|
||||
@@ -71,7 +72,7 @@ async function createTables() {
|
||||
user_id INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
content TEXT NOT NULL,
|
||||
attachment_urls TEXT[],
|
||||
sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
sent_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON Messages (conversation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_user_id ON Messages (user_id);
|
||||
@@ -85,9 +86,9 @@ async function createTables() {
|
||||
// Create Memberships Table
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS Memberships (
|
||||
conversation_id INT REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||
conversation_id INT NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||
user_id INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
PRIMARY KEY (conversation_id, user_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_memberships_conversation_id ON Memberships (conversation_id);
|
||||
@@ -103,13 +104,14 @@ async function createTables() {
|
||||
CREATE TABLE IF NOT EXISTS Contacts (
|
||||
contact_id SERIAL PRIMARY KEY,
|
||||
user_id INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
contact_user_id INT NOT NULL REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
conversation_id INT NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||
read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT unique_contact UNIQUE (user_id, contact_user_id)
|
||||
last_active TIMESTAMPTZ DEFAULT NOW(),
|
||||
CONSTRAINT unique_contact UNIQUE (user_id, conversation_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_user_id ON Contacts (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_contact_user_id ON Contacts (contact_user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_conversation_id ON Contacts (conversation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_contact_id ON Contacts (contact_id);
|
||||
`);
|
||||
console.log("Contacts table created successfully.");
|
||||
} catch (e) {
|
||||
@@ -180,14 +182,14 @@ async function insertMessage(
|
||||
}
|
||||
}
|
||||
|
||||
async function createGroup(user_id, groupname) {
|
||||
async function createGroup(user_id, groupName) {
|
||||
const query = `
|
||||
INSERT INTO Conversations (conversation_type, name)
|
||||
VALUES ('group', $1)
|
||||
RETURNING conversation_id AS group_id;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [groupname]);
|
||||
const result = await client.query(query, [groupName]);
|
||||
const group_id = result.rows[0].group_id;
|
||||
|
||||
const contact_user_id = await addMemberToGroup(group_id, user_id);
|
||||
@@ -417,23 +419,24 @@ async function insertContact(userUsername, receiverUsername, read) {
|
||||
)
|
||||
),
|
||||
contact_insert AS (
|
||||
INSERT INTO Contacts (user_id, contact_user_id, read)
|
||||
SELECT sender_id, receiver_id, $3
|
||||
FROM user_ids
|
||||
ON CONFLICT (user_id, contact_user_id)
|
||||
INSERT INTO Contacts (user_id, conversation_id, read)
|
||||
SELECT sender_id, conversation_id, $3
|
||||
FROM user_ids, conversation
|
||||
ON CONFLICT (user_id, conversation_id)
|
||||
DO UPDATE SET last_active = CURRENT_TIMESTAMP, read = $3
|
||||
RETURNING contact_id, contact_user_id, last_active
|
||||
RETURNING contact_id, conversation_id, last_active, user_id, read
|
||||
)
|
||||
SELECT
|
||||
ci.contact_id AS id,
|
||||
ci.contact_user_id AS user_id,
|
||||
a.username,
|
||||
ci.conversation_id,
|
||||
CASE
|
||||
WHEN ci.user_id = (SELECT sender_id FROM user_ids) THEN (SELECT username FROM Accounts WHERE user_id = (SELECT receiver_id FROM user_ids))
|
||||
ELSE (SELECT username FROM Accounts WHERE user_id = (SELECT sender_id FROM user_ids))
|
||||
END AS username,
|
||||
ci.read,
|
||||
ci.last_active,
|
||||
'direct' AS type,
|
||||
c.conversation_id
|
||||
FROM contact_insert ci
|
||||
JOIN Accounts a ON a.user_id = ci.contact_user_id
|
||||
CROSS JOIN conversation c;
|
||||
'direct' AS type
|
||||
FROM contact_insert ci;
|
||||
`;
|
||||
|
||||
try {
|
||||
@@ -453,32 +456,19 @@ async function getContacts(user_id) {
|
||||
const contactsQuery = `
|
||||
SELECT
|
||||
c.contact_id AS id,
|
||||
c.contact_user_id AS user_id,
|
||||
a.username AS username,
|
||||
a2.user_id AS user_id,
|
||||
a2.username AS username,
|
||||
c.last_active,
|
||||
m.conversation_id,
|
||||
'direct' AS type
|
||||
c.conversation_id,
|
||||
conv.conversation_type AS type,
|
||||
c.read
|
||||
FROM Contacts c
|
||||
JOIN Accounts a ON a.user_id = c.contact_user_id
|
||||
JOIN Memberships m ON m.user_id = c.contact_user_id AND m.conversation_id = (
|
||||
SELECT conversation_id
|
||||
FROM Conversations
|
||||
WHERE conversation_type = 'direct'
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM Memberships
|
||||
WHERE conversation_id = Conversations.conversation_id
|
||||
AND user_id = $1
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM Memberships
|
||||
WHERE conversation_id = Conversations.conversation_id
|
||||
AND user_id = c.contact_user_id
|
||||
)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE c.user_id = $1
|
||||
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
|
||||
JOIN Memberships m ON m.conversation_id = c.conversation_id
|
||||
JOIN Accounts a2 ON a2.user_id = m.user_id
|
||||
WHERE c.user_id = $1
|
||||
AND conv.conversation_type = 'direct'
|
||||
AND a2.user_id != $1
|
||||
ORDER BY c.last_active DESC;
|
||||
`;
|
||||
|
||||
@@ -486,12 +476,12 @@ async function getContacts(user_id) {
|
||||
SELECT
|
||||
c.conversation_id AS id,
|
||||
c.name AS username,
|
||||
c.created_at AS last_active,
|
||||
c.last_active,
|
||||
c.conversation_type AS type
|
||||
FROM Memberships m
|
||||
JOIN Conversations c ON m.conversation_id = c.conversation_id
|
||||
WHERE m.user_id = $1 AND c.conversation_type = 'group'
|
||||
ORDER BY c.created_at DESC;
|
||||
ORDER BY c.last_active DESC;
|
||||
`;
|
||||
|
||||
try {
|
||||
@@ -569,36 +559,32 @@ async function deleteContact(user_id, contact_id, conversation_id) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateContactStatus(userUsername, contact_user_id, read) {
|
||||
async function updateContactStatus(user_id, contact_id, read) {
|
||||
const query = `
|
||||
WITH users AS (
|
||||
SELECT
|
||||
(SELECT user_id FROM Accounts WHERE username = $2) as user_id,
|
||||
(SELECT user_id FROM Accounts WHERE username = $3) as contact_user_id
|
||||
)
|
||||
UPDATE Contacts SET read = $1
|
||||
WHERE user_id = (SELECT user_id FROM users)
|
||||
AND contact_user_id = (SELECT contact_user_id FROM users);
|
||||
WHERE user_id = $2
|
||||
AND contact_id = $3;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [read, userUsername, contact_user_id]);
|
||||
await updateContactLastActive(userUsername, contact_user_id);
|
||||
console.log("Successfully updated contact status");
|
||||
await client.query(query, [read, user_id, contact_id]);
|
||||
await updateContactLastActive(user_id, contact_id);
|
||||
console.log(
|
||||
`Successfully updated contact status, user_id: ${user_id}, contact_id: ${contact_id}, read: ${read}: `,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to update contact status ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateContactLastActive(userUsername, receiverUsername) {
|
||||
const timestamp = getTime();
|
||||
async function updateContactLastActive(user_id, contact_id) {
|
||||
const query = `
|
||||
UPDATE Contacts
|
||||
SET last_active = $1
|
||||
WHERE user_id = (SELECT user_id FROM Accounts WHERE username = $2)
|
||||
AND contact_user_id = (SELECT user_id FROM Accounts WHERE username = $3);
|
||||
SET last_active = NOW()
|
||||
WHERE user_id = $1
|
||||
AND contact_id = $2;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [timestamp, userUsername, receiverUsername]);
|
||||
await client.query(query, [user_id, contact_id]);
|
||||
console.log("Successfully updated contact last active time");
|
||||
} catch (e) {
|
||||
console.error("Failed to update contact last active time ", e);
|
||||
@@ -715,7 +701,6 @@ module.exports = {
|
||||
getUserId,
|
||||
getContacts,
|
||||
updateContactStatus,
|
||||
updateContactLastActive,
|
||||
createGroup,
|
||||
addMemberToGroup,
|
||||
addMemberToGroupByUsername,
|
||||
|
||||
@@ -41,6 +41,7 @@ const {
|
||||
contactSuggestion,
|
||||
deleteMessage,
|
||||
getMembers,
|
||||
insertContactByUsername,
|
||||
} = require("./db/db");
|
||||
const { extname } = require("node:path");
|
||||
|
||||
@@ -126,7 +127,7 @@ app.post("/api/auth/signup", async (req, res) => {
|
||||
await insertUser(username, hash);
|
||||
|
||||
// Get user id from database to store it in jwt token
|
||||
const user_id = await getUserId(username);
|
||||
const { user_id } = await getUserId(username);
|
||||
console.log(`Registered: ${username} with id: ${user_id}`);
|
||||
// Set JWT token to cookies
|
||||
const token = generateJwtToken(username, user_id);
|
||||
@@ -222,23 +223,18 @@ app.delete(
|
||||
},
|
||||
);
|
||||
|
||||
app.put("/api/chat/contacts/:contact", authorizeUser, async (req, res) => {
|
||||
if (!req.params.contact) {
|
||||
return res.status(400).json({ message: "Missing contact parameter" });
|
||||
}
|
||||
const usernameContact = req.params.contact;
|
||||
|
||||
// Validate username for invalid characters, length, and type
|
||||
if (!isValidUsername(usernameContact)) {
|
||||
return res.status(400).json({ message: "Invalid contact provided" });
|
||||
app.put("/api/chat/contacts/:contact_id", authorizeUser, async (req, res) => {
|
||||
const contact_id = req.params.contact_id;
|
||||
if (!contact_id) {
|
||||
return res.status(400).json({ message: "Missing contact id parameter" });
|
||||
}
|
||||
|
||||
const read = req.body.status;
|
||||
await updateContactStatus(req.user.user_id, usernameContact, read);
|
||||
await updateContactStatus(req.user.user_id, contact_id, read);
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ message: "Successfully updated contact status" });
|
||||
.json({ message: `Successfully updated contact status to: ${read}` });
|
||||
});
|
||||
|
||||
app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user