fixed contacts status

This commit is contained in:
slawk0
2024-12-10 17:22:04 +01:00
parent eedae59646
commit 771e8764ac
9 changed files with 224 additions and 126 deletions

View File

@@ -194,6 +194,7 @@ async function createGroup(user_id, groupName) {
const group_id = result.rows[0].group_id;
const contact_user_id = await addMemberToGroup(group_id, user_id);
insertContactById(user_id, group_id, true);
return { group_id, contact_user_id };
} catch (e) {
console.error("Failed to create conversation ", e);
@@ -246,6 +247,8 @@ async function addMemberToGroupByUsername(conversation_id, username) {
console.log(
`Added user with username ${username} to conversation_id ${conversation_id}`,
);
const added_user_id = result.rows[0].added_user_id;
insertContactById(added_user_id, conversation_id, true);
return result.rows[0].added_user_id;
} else {
console.log(
@@ -376,90 +379,133 @@ async function changePassword(username, newPasswordHash) {
}
}
async function insertContact(userUsername, receiverUsername, read) {
async function insertContactById(senderId, conversation_id, read) {
const query = `
WITH user_ids AS (
SELECT
(SELECT user_id FROM Accounts WHERE LOWER(username) = LOWER($1)) AS sender_id,
(SELECT user_id FROM Accounts WHERE LOWER(username) = LOWER($2)) AS receiver_id
),
existing_conversation AS (
SELECT c.conversation_id
FROM Conversations c
JOIN Memberships m1 ON c.conversation_id = m1.conversation_id
JOIN Memberships m2 ON c.conversation_id = m2.conversation_id
JOIN user_ids ON m1.user_id = user_ids.sender_id AND m2.user_id = user_ids.receiver_id
WHERE c.conversation_type = 'direct'
LIMIT 1
),
new_conversation AS (
INSERT INTO Conversations (conversation_type)
SELECT 'direct'
WHERE NOT EXISTS (SELECT 1 FROM existing_conversation)
RETURNING conversation_id
),
conversation AS (
SELECT conversation_id FROM existing_conversation
UNION ALL
SELECT conversation_id FROM new_conversation
),
new_memberships AS (
INSERT INTO Memberships (conversation_id, user_id)
SELECT conv.conversation_id, u.user_id
FROM conversation conv
CROSS JOIN (
SELECT sender_id AS user_id FROM user_ids
UNION ALL
SELECT receiver_id FROM user_ids
) u
WHERE NOT EXISTS (
SELECT 1
FROM Memberships m
WHERE m.conversation_id = conv.conversation_id
AND m.user_id = u.user_id
)
),
contact_insert AS (
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, conversation_id, last_active, user_id, read
)
SELECT
ci.contact_id AS id,
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,
c.last_active,
ci.read,
'direct' AS type
FROM contact_insert ci
JOIN Conversations c ON ci.conversation_id = c.conversation_id;
INSERT INTO Contacts (user_id, conversation_id, read)
VALUES( $1, $2, $3)
`;
try {
const result = await client.query(query, [
userUsername,
receiverUsername,
read,
]);
const result = await client.query(query, [senderId, conversation_id, read]);
console.log(
"Insertcontactbyid: ",
result.rows[0],
senderId,
conversation_id,
);
return result.rows[0] || null;
} catch (error) {
console.error("Failed to insert contact:", error);
console.error("Failed to insert contact by IDs:", error);
return null;
}
}
async function insertContact(userUsername, receiverUsername, read) {
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]) {
throw new Error("Users not found");
}
const { initiator_id, contact_id, contact_username } = usersResult.rows[0];
// 2. Find existing conversation
const findConversationQuery = `
SELECT c.conversation_id
FROM Conversations c
JOIN Memberships m1 ON c.conversation_id = m1.conversation_id
JOIN Memberships m2 ON c.conversation_id = m2.conversation_id
WHERE c.conversation_type = 'direct'
AND m1.user_id = $1
AND m2.user_id = $2
LIMIT 1
`;
const conversationResult = await client.query(findConversationQuery, [
initiator_id,
contact_id,
]);
let conversation_id = conversationResult.rows[0]?.conversation_id;
// 3. Create new conversation if none exists
if (!conversation_id) {
const createConversationQuery = `
INSERT INTO Conversations (conversation_type)
VALUES ('direct')
RETURNING conversation_id
`;
const newConversationResult = await client.query(createConversationQuery);
conversation_id = newConversationResult.rows[0].conversation_id;
// 4. Create memberships for both users
const createMembershipsQuery = `
INSERT INTO Memberships (conversation_id, user_id)
VALUES ($1, $2), ($1, $3)
ON CONFLICT (conversation_id, user_id) DO NOTHING
`;
await client.query(createMembershipsQuery, [
conversation_id,
initiator_id,
contact_id,
]);
}
// 5. Create or update contact
const upsertContactQuery = `
INSERT INTO Contacts (user_id, conversation_id, read)
VALUES ($1, $2, $3)
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. Return formatted result with contact's user_id
return {
id: contact.contact_id,
user_id: contact_id, // Now using the contact's user_id instead of the initiator's
username: contact_username,
last_active: contact.last_active,
conversation_id: contact.conversation_id,
type: "direct",
read: contact.read,
};
} catch (error) {
console.error("Failed to insert contact:", error);
throw error;
}
}
async function getContacts(user_id) {
const contactsQuery = `
SELECT
SELECT DISTINCT ON (c.conversation_id)
c.contact_id AS id,
a2.user_id AS user_id,
a2.username AS username,
CASE
WHEN conv.conversation_type = 'group' THEN NULL
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,
@@ -468,40 +514,30 @@ async function getContacts(user_id) {
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 conv.last_active DESC;
`;
const groupsQuery = `
SELECT
c.conversation_id AS id,
c.name AS username,
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.last_active DESC;
WHERE c.user_id = $1
AND (
(conv.conversation_type = 'direct' AND a2.user_id != $1)
OR
(conv.conversation_type = 'group')
)
ORDER BY c.conversation_id, conv.last_active DESC;
`;
try {
const contactsResult = await client.query(contactsQuery, [user_id]);
const groupsResult = await client.query(groupsQuery, [user_id]);
const contacts = contactsResult.rows;
const groups = groupsResult.rows.map((group) => ({
username: group.username,
last_active: group.last_active,
type: group.type,
conversation_id: group.id,
const contacts = contactsResult.rows.map((row) => ({
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,
}));
// Combine contacts and groups
return [...contacts, ...groups];
console.log("Get contacts: ", contacts);
return contacts;
} catch (e) {
console.error("Failed to get contacts and groups:", e);
console.error("Failed to get contacts:", e);
return [];
}
}
@@ -561,17 +597,17 @@ async function deleteContact(user_id, contact_id, conversation_id) {
}
}
async function updateContactStatus(user_id, contact_id, read) {
async function updateContactStatus(user_id, conversation_id, read) {
const query = `
UPDATE Contacts SET read = $1
WHERE user_id = $2
AND contact_id = $3;
AND conversation_id = $3;
`;
try {
await client.query(query, [read, user_id, contact_id]);
await updateContactLastActive(user_id, contact_id);
await client.query(query, [read, user_id, conversation_id]);
await updateContactLastActive(user_id, conversation_id);
console.log(
`Successfully updated contact status, user_id: ${user_id}, contact_id: ${contact_id}, read: ${read}: `,
`Successfully updated contact status, user_id: ${user_id}, conversation_id: ${conversation_id}, read: ${read}: `,
);
} catch (e) {
console.error("Failed to update contact status ", e);

View File

@@ -223,19 +223,25 @@ app.delete(
},
);
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" });
}
app.put(
"/api/chat/contacts/:conversation_id",
authorizeUser,
async (req, res) => {
const conversation_id = req.params.conversation_id;
if (!conversation_id) {
return res
.status(400)
.json({ message: "Missing conversation id parameter" });
}
const read = req.body.status;
await updateContactStatus(req.user.user_id, contact_id, read);
const read = req.body.status;
await updateContactStatus(req.user.user_id, conversation_id, read);
return res
.status(200)
.json({ message: `Successfully updated contact status to: ${read}` });
});
return res
.status(200)
.json({ message: `Successfully updated contact status to: ${read}` });
},
);
app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
if (!req.params.contact) {
@@ -249,7 +255,6 @@ app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
}
try {
console.log("contact post request: ", usernameContact);
const result = await insertContact(
req.user.username,
usernameContact,
@@ -258,6 +263,9 @@ app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
if (result === null) {
return res.status(500).json({ message: "Failed to create conversation" });
}
if (!result.user_id) {
return res.status(500).json({ message: "Something went wrong" });
}
console.log("sent contact post response: ", result);
return res.status(200).json(result);
} catch (e) {
@@ -347,7 +355,9 @@ app.post("/api/chat/groups/create", authorizeUser, async (req, res) => {
if (!group_id) {
return res.status(500).json({ message: "Failed to create group" });
}
io.to(contact_user_id).emit("added to group");
console.log("Successfully created group: ", groupname, "id: ", group_id);
console.log("io.to: ", contact_user_id, "added to group");
io.to(contact_user_id).emit("added to group", { group_id });
return res.status(200).json({
message: `Successfully created group: ${groupname}`,
group_id: group_id,
@@ -365,7 +375,11 @@ app.post("/api/chat/groups/addMember", async (req, res) => {
}
const result = await addMemberToGroupByUsername(group_id, username);
if (result !== null) {
io.to(result).emit("added to group");
io.to(result).to(group_id).emit("added to group", {
username,
user_id: result,
group_id,
});
console.log("added to group: ", result);
return res.status(200).json({ message: "Successfully added member" });
}

View File

@@ -112,6 +112,7 @@ function initializeSocket(io) {
insertedMessage;
console.log("(socket) received from chat message", msg);
console.log(`io to ${username}, ${recipient}, ${recipient_id}`);
io.to(username).to(recipient).to(recipient_id).emit("chat message", {
sender,
message: content,