fixed (I hope so) insertContact function

This commit is contained in:
slawk0
2025-01-04 23:35:10 +01:00
parent 930ae98ab7
commit 17c2427413
4 changed files with 221 additions and 104 deletions

View File

@@ -15,7 +15,10 @@ function ContactProfile() {
<img className="w-4 mr-2 invert" src={profile} alt="profile img" /> <img className="w-4 mr-2 invert" src={profile} alt="profile img" />
)} )}
<p>{currentContact ? currentContact.username : null}</p> <p>
{currentContact ? currentContact.username : null} user id:{' '}
{currentContact?.user_id} conv id: {currentContact?.conversation_id}
</p>
</div> </div>
<div className="flex-grow"></div> <div className="flex-grow"></div>

View File

@@ -34,6 +34,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
withCredentials: true, withCredentials: true,
}); });
setUser({ username: res.data.username, id: res.data.user_id }); setUser({ username: res.data.username, id: res.data.user_id });
console.info('user: : ', {
username: res.data.username,
id: res.data.user_id,
});
setAuthorized(true); setAuthorized(true);
} catch (err) { } catch (err) {
setAuthorized(false); setAuthorized(false);

View File

@@ -474,14 +474,37 @@ async function changePassword(username, newPasswordHash) {
} }
async function insertContactById(senderId, conversation_id, read) { async function insertContactById(senderId, conversation_id, read) {
const query = ` // First check if contact already exists
INSERT INTO Contacts (user_id, conversation_id, read) const checkQuery = `
VALUES( $1, $2, $3) SELECT contact_id, conversation_id, user_id, read, last_active
FROM Contacts
WHERE user_id = $1 AND conversation_id = $2
`; `;
try { try {
const result = await client.query(query, [senderId, conversation_id, read]); // Check if contact already exists
console.log("Insertcontactbyid: ", senderId, conversation_id); const existingContact = await client.query(checkQuery, [
senderId,
conversation_id,
]);
if (existingContact.rows.length > 0) {
console.log("Contact already exists:", senderId, conversation_id);
return existingContact.rows[0];
}
// If contact doesn't exist, create new one
const insertQuery = `
INSERT INTO Contacts (user_id, conversation_id, read)
VALUES($1, $2, $3)
RETURNING contact_id, conversation_id, user_id, read, last_active
`;
const result = await client.query(insertQuery, [
senderId,
conversation_id,
read,
]);
console.log("Insert contact by id:", senderId, conversation_id);
return result.rows[0] || null; return result.rows[0] || null;
} catch (error) { } catch (error) {
console.error("Failed to insert contact by IDs:", error); console.error("Failed to insert contact by IDs:", error);
@@ -489,49 +512,35 @@ async function insertContactById(senderId, conversation_id, read) {
} }
} }
async function insertContact(userUsername, receiverUsername, read) { async function insertContact(initiatorId, receiverId, contactUsername, read) {
try { try {
// 1. Get user IDs
const getUsersQuery = `
SELECT
u1.user_id AS initiator_id,
u1.username AS initiator_username,
u2.user_id AS contact_id,
u2.username AS contact_username
FROM Accounts u1
CROSS JOIN Accounts u2
WHERE LOWER(u1.username) = LOWER($1)
AND LOWER(u2.username) = LOWER($2)
`;
const usersResult = await client.query(getUsersQuery, [
userUsername,
receiverUsername,
]);
if (!usersResult.rows[0]) {
console.error("Users not found");
return null;
}
const { initiator_id, contact_id, contact_username } = usersResult.rows[0];
// 2. Find existing conversation
const findConversationQuery = ` const findConversationQuery = `
SELECT c.conversation_id SELECT c.conversation_id
FROM Conversations c FROM Conversations c
JOIN Memberships m1 ON c.conversation_id = m1.conversation_id JOIN Memberships m1 ON c.conversation_id = m1.conversation_id
JOIN Memberships m2 ON c.conversation_id = m2.conversation_id JOIN Memberships m2 ON c.conversation_id = m2.conversation_id
WHERE c.conversation_type = 'direct' WHERE c.conversation_type = 'direct'
AND m1.user_id = $1 AND (
AND m2.user_id = $2 (m1.user_id = $1 AND m2.user_id = $2)
LIMIT 1 OR
(m1.user_id = $2 AND m2.user_id = $1)
)
AND (
SELECT COUNT(DISTINCT user_id)
FROM Memberships
WHERE conversation_id = c.conversation_id
) = 1 -- Allow a conversation with a single user (self)
LIMIT 1
`; `;
const conversationResult = await client.query(findConversationQuery, [ const conversationResult = await client.query(findConversationQuery, [
initiator_id, initiatorId,
contact_id, receiverId,
]); ]);
let conversation_id = conversationResult.rows[0]?.conversation_id; let conversation_id = conversationResult.rows[0]?.conversation_id;
// 3. Create new conversation if none exists // Create new conversation if none exists
if (!conversation_id) { if (!conversation_id) {
console.error("CONVERSATION DON'T EXIST: ", conversation_id);
const createConversationQuery = ` const createConversationQuery = `
INSERT INTO Conversations (conversation_type) INSERT INTO Conversations (conversation_type)
VALUES ('direct') VALUES ('direct')
@@ -539,8 +548,8 @@ async function insertContact(userUsername, receiverUsername, read) {
`; `;
const newConversationResult = await client.query(createConversationQuery); const newConversationResult = await client.query(createConversationQuery);
conversation_id = newConversationResult.rows[0].conversation_id; conversation_id = newConversationResult.rows[0].conversation_id;
console.error("NEW CONVERSATION ID: ", conversation_id);
// 4. Create memberships for both users // Create memberships for both users (or single user if they are the same)
const createMembershipsQuery = ` const createMembershipsQuery = `
INSERT INTO Memberships (conversation_id, user_id) INSERT INTO Memberships (conversation_id, user_id)
VALUES ($1, $2), ($1, $3) VALUES ($1, $2), ($1, $3)
@@ -548,27 +557,18 @@ async function insertContact(userUsername, receiverUsername, read) {
`; `;
await client.query(createMembershipsQuery, [ await client.query(createMembershipsQuery, [
conversation_id, conversation_id,
initiator_id, initiatorId,
contact_id, receiverId,
]); ]);
} }
// 5. Create or update contact const contact = await insertContactById(initiatorId, conversation_id, read);
const upsertContactQuery = ` if (!contact.contact_id) {
INSERT INTO Contacts (user_id, conversation_id, read) console.error("Failed to insert contact by id");
VALUES ($1, $2, $3) return null;
ON CONFLICT (user_id, conversation_id) }
DO UPDATE SET last_active = CURRENT_TIMESTAMP, read = $3
RETURNING contact_id, conversation_id, user_id, read, last_active
`;
const contactResult = await client.query(upsertContactQuery, [
initiator_id,
conversation_id,
read,
]);
const contact = contactResult.rows[0];
// 6. Retrieve the last message, last active time, and last message sender // Retrieve the last message, last active time, and last message sender
const lastMessageQuery = ` const lastMessageQuery = `
SELECT DISTINCT ON (m.conversation_id) SELECT DISTINCT ON (m.conversation_id)
m.content AS last_message, m.content AS last_message,
@@ -590,18 +590,18 @@ async function insertContact(userUsername, receiverUsername, read) {
lastMessageSender = lastMessageResult.rows[0].last_message_sender; lastMessageSender = lastMessageResult.rows[0].last_message_sender;
} }
// 7. Return formatted result with contact's user_id, last message, last active time, and last message sender // Return formatted result with contact's user_id, last message, last active time, and last message sender
return { return {
id: contact.contact_id, id: contact.contact_id,
user_id: contact_id, // Now using the contact's user_id instead of the initiator's user_id: receiverId, // Now using the contact's user_id instead of the initiator's
username: contact_username, username: contactUsername,
last_active: contact.last_active, last_active: contact.last_active,
conversation_id: contact.conversation_id, conversation_id: contact.conversation_id,
type: "direct", type: "direct",
read: contact.read, read: contact.read,
last_message: lastMessage, last_message: lastMessage || null,
last_message_time: lastMessageTime, last_message_time: lastMessageTime || null,
last_message_sender: lastMessageSender, last_message_sender: lastMessageSender || null,
}; };
} catch (error) { } catch (error) {
console.error("Failed to insert contact:", error); console.error("Failed to insert contact:", error);
@@ -609,53 +609,158 @@ async function insertContact(userUsername, receiverUsername, read) {
} }
} }
async function getLatestMessage(conversation_id) {
const latestMessageQuery = `
WITH LatestMessage AS (
SELECT
m.message_id as id,
m.user_id,
m.content as last_message,
m.sent_at as last_message_time,
a.username as last_message_sender
FROM Messages m
JOIN Accounts a ON m.user_id = a.user_id
WHERE m.conversation_id = $1
ORDER BY m.sent_at DESC
LIMIT 1
),
ConversationUsers AS (
SELECT
m.user_id,
a.username,
c.read
FROM Memberships m
JOIN Accounts a ON m.user_id = a.user_id
LEFT JOIN Contacts c ON c.user_id = m.user_id AND c.conversation_id = $1
WHERE m.conversation_id = $1
LIMIT 1
)
SELECT
lm.*,
cu.user_id,
cu.username,
cu.read,
c.conversation_type as type,
c.last_active,
c.conversation_id
FROM Conversations c
LEFT JOIN LatestMessage lm ON TRUE
LEFT JOIN ConversationUsers cu ON TRUE
WHERE c.conversation_id = $1;
`;
try {
// Get latest message and details
const result = await client.query(latestMessageQuery, [conversation_id]);
if (result.rows.length === 0) {
console.error("No messages found in conversation:", conversation_id);
return null;
}
const row = result.rows[0];
return {
id: row.id,
user_id: row.user_id,
username: row.username,
last_active: row.last_active,
conversation_id: row.conversation_id,
type: row.type,
read: row.read,
last_message: row.last_message,
last_message_time: row.last_message_time,
last_message_sender: row.last_message_sender,
};
} catch (error) {
console.error("Failed to get latest message:", error);
return null;
}
}
async function checkMembership(user_id, conversation_id) {
const query = `
SELECT EXISTS (
SELECT 1
FROM Memberships
WHERE user_id = $1
AND conversation_id = $2
) AS is_member;
`;
try {
const result = await client.query(query, [user_id, conversation_id]);
return result.rows[0].is_member;
} catch (error) {
console.error("Error checking membership:", error);
return false;
}
}
async function getContacts(user_id) { async function getContacts(user_id) {
const contactsQuery = ` const contactsQuery = `
WITH LastMessages AS ( WITH LastMessages AS (
SELECT DISTINCT ON (m.conversation_id) SELECT DISTINCT ON (m.conversation_id)
m.conversation_id, m.conversation_id,
m.content as last_message, m.content AS last_message,
m.sent_at as last_message_time, m.sent_at AS last_message_time,
a.username as last_message_sender a.username AS last_message_sender
FROM Messages m FROM Messages m
JOIN Accounts a ON m.user_id = a.user_id JOIN Accounts a ON m.user_id = a.user_id
ORDER BY m.conversation_id, m.sent_at DESC ORDER BY m.conversation_id, m.sent_at DESC
),
DirectContacts AS (
SELECT
c.contact_id AS id,
a.user_id AS user_id,
a.username AS username,
conv.last_active,
c.conversation_id,
conv.conversation_type AS type,
c.read,
lm.last_message,
lm.last_message_time,
lm.last_message_sender
FROM Contacts c
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
JOIN Memberships m ON m.conversation_id = c.conversation_id
JOIN Accounts a ON a.user_id = m.user_id
LEFT JOIN LastMessages lm ON c.conversation_id = lm.conversation_id
WHERE c.user_id = $1
AND conv.conversation_type = 'direct'
AND a.user_id != $1
ORDER BY c.conversation_id, conv.last_active DESC
),
GroupContacts AS (
SELECT
c.contact_id AS id,
NULL::uuid AS user_id,
conv.name AS username,
conv.last_active,
c.conversation_id,
conv.conversation_type AS type,
c.read,
lm.last_message,
lm.last_message_time,
lm.last_message_sender
FROM Contacts c
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
LEFT JOIN LastMessages lm ON c.conversation_id = lm.conversation_id
WHERE c.user_id = $1
AND conv.conversation_type = 'group'
ORDER BY c.conversation_id, conv.last_active DESC
) )
SELECT DISTINCT ON (c.conversation_id) SELECT * FROM DirectContacts
c.contact_id AS id, UNION ALL
CASE SELECT * FROM GroupContacts
WHEN conv.conversation_type = 'group' THEN NULL ORDER BY last_active DESC;
ELSE a2.user_id
END AS user_id,
CASE
WHEN conv.conversation_type = 'group' THEN conv.name
ELSE a2.username
END AS username,
conv.last_active,
c.conversation_id,
conv.conversation_type AS type,
c.read,
lm.last_message,
lm.last_message_time,
lm.last_message_sender
FROM Contacts c
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
LEFT JOIN LastMessages lm ON c.conversation_id = lm.conversation_id
WHERE c.user_id = $1
AND (
conv.conversation_type = 'direct'
OR
conv.conversation_type = 'group'
)
ORDER BY c.conversation_id, conv.last_active DESC;
`; `;
try { try {
// Execute the query with the user_id parameter // Execute the query with the user_id parameter
const contactsResult = await client.query(contactsQuery, [user_id]); const contactsResult = await client.query(contactsQuery, [user_id]);
console.error(contactsResult.rows); console.log(contactsResult.rows); // Debugging: log the results to verify
// Map the results to a more friendly format // Map the results to a more friendly format
const contacts = contactsResult.rows.map((row) => ({ const contacts = contactsResult.rows.map((row) => ({
id: row.id, id: row.id,

View File

@@ -250,17 +250,22 @@ app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
if (!req.params.contact) { if (!req.params.contact) {
return res.status(400).json({ message: "Missing contact parameter" }); return res.status(400).json({ message: "Missing contact parameter" });
} }
const usernameContact = req.params.contact; const contactUsername = req.params.contact;
// Validate username for invalid characters, length, and type // Validate username for invalid characters, length, and type
if (!isValidUsername(usernameContact)) { if (!isValidUsername(contactUsername)) {
return res.status(400).json({ message: "Invalid username provided" }); return res.status(400).json({ message: "Invalid username provided" });
} }
// Get contact user id and check if exist
const contact = await getUserId(contactUsername);
if (!contact) {
return res.status(400).json({ message: "User does not exist" });
}
try { try {
const result = await insertContact( const result = await insertContact(
req.user.username, req.user.user_id,
usernameContact, contact.user_id,
contactUsername,
true, true,
); );
if (result === null) { if (result === null) {