refactoring code for fresh database
This commit is contained in:
@@ -7,5 +7,5 @@ ORIGIN=http://localhost:5173
|
||||
|
||||
PG_HOST=192.168.0.47
|
||||
PG_USER=postgres
|
||||
PG_PASSWORD=haslo
|
||||
PG_PASSWORD=chaslo
|
||||
PG_DATABASE=relay
|
||||
|
||||
267
server/db/db.js
267
server/db/db.js
@@ -15,11 +15,11 @@ client
|
||||
.then(() => {
|
||||
createTables()
|
||||
.then(() => {
|
||||
client.end();
|
||||
//client.end();
|
||||
console.log("Tables created successfully");
|
||||
})
|
||||
.catch((e) => {
|
||||
client.end();
|
||||
//client.end();
|
||||
console.error("Failed to create tables ", e);
|
||||
});
|
||||
console.log(
|
||||
@@ -40,12 +40,10 @@ async function createTables() {
|
||||
CREATE TABLE IF NOT EXISTS Accounts (
|
||||
user_id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255) UNIQUE NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_username ON Accounts (username);
|
||||
CREATE INDEX IF NOT EXISTS idx_email ON Accounts (email);
|
||||
`);
|
||||
} catch (e) {
|
||||
console.error("Failed to create Accounts table: ", e);
|
||||
@@ -74,6 +72,7 @@ async function createTables() {
|
||||
conversation_id INT REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||
sender_id INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
content TEXT NOT NULL,
|
||||
attachment_url TEXT,
|
||||
sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON Messages (conversation_id);
|
||||
@@ -102,30 +101,33 @@ async function createTables() {
|
||||
}
|
||||
|
||||
try {
|
||||
// Create Contacts Table
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS Contacts (
|
||||
username VARCHAR(255) NOT NULL,
|
||||
usernameContact VARCHAR(255) NOT NULL,
|
||||
read BOOLEAN NOT NULL,
|
||||
lastActive TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT unique_username_contact UNIQUE (username, usernameContact)
|
||||
contact_id SERIAL PRIMARY KEY,
|
||||
sender_id INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
contact_name INT REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||
read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT unique_contact UNIQUE (sender_id, contact_name)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_sender_id ON Contacts (sender_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_contact_name ON Contacts (contact_name);
|
||||
`);
|
||||
console.log("Contacts table created successfully.");
|
||||
} catch (e) {
|
||||
console.error("Failed to create Contacts table: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function insertUser(username, password) {
|
||||
const user_id = crypto.randomUUID();
|
||||
|
||||
async function insertUser(username, passwordHash) {
|
||||
const query = `
|
||||
INSERT INTO accounts (username, password, user_id)
|
||||
VALUES ($1, $2, $3);
|
||||
INSERT INTO Accounts (username, password_hash)
|
||||
VALUES ($1, $2)
|
||||
RETURNING user_id;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [username, password, user_id]);
|
||||
const result = await client.query(query, [username, passwordHash]);
|
||||
return result.rows[0].user_id;
|
||||
} catch (e) {
|
||||
console.error("Failed to insert user ", e);
|
||||
}
|
||||
@@ -133,28 +135,38 @@ async function insertUser(username, password) {
|
||||
|
||||
async function getUserId(username) {
|
||||
const query = `
|
||||
SELECT user_id FROM accounts
|
||||
SELECT user_id FROM Accounts
|
||||
WHERE username = $1;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [username]);
|
||||
console.log("GETUSERID: ", result.rows[0].user_id);
|
||||
return result.rows[0].user_id;
|
||||
if (result.rows.length > 0) {
|
||||
console.log("GETUSERID: ", result.rows[0].user_id);
|
||||
return result.rows[0].user_id;
|
||||
} else {
|
||||
console.log("No user found with username: ", username);
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to get user id", e);
|
||||
}
|
||||
}
|
||||
async function insertMessage(sender, recipient, message, attachmentUrl) {
|
||||
|
||||
async function insertMessage(sender_id, recipient_id, content, attachmentUrl) {
|
||||
const query = `
|
||||
INSERT INTO messages (sender, recipient, message, attachment_url)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING message, timestamp, message_id, attachment_url;
|
||||
INSERT INTO Messages (conversation_id, sender_id, content, attachment_url)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING message_id, content, sent_at, attachment_url;
|
||||
`;
|
||||
try {
|
||||
const conversation_id = await getOrCreateConversation(
|
||||
sender_id,
|
||||
recipient_id,
|
||||
);
|
||||
const results = await client.query(query, [
|
||||
sender,
|
||||
recipient,
|
||||
message,
|
||||
conversation_id,
|
||||
sender_id,
|
||||
content,
|
||||
attachmentUrl,
|
||||
]);
|
||||
return results.rows[0];
|
||||
@@ -163,30 +175,81 @@ async function insertMessage(sender, recipient, message, attachmentUrl) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessages(username, recipient, limit = 50, cursor = 0) {
|
||||
async function getOrCreateConversation(sender_id, recipient_id) {
|
||||
// Check if a conversation between these two users already exists
|
||||
const query = `
|
||||
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 = $2
|
||||
)
|
||||
LIMIT 1;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [sender_id, recipient_id]);
|
||||
if (result.rows.length > 0) {
|
||||
return result.rows[0].conversation_id;
|
||||
} else {
|
||||
// Create a new conversation
|
||||
return await createConversation(sender_id, recipient_id);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to get or create conversation ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function createConversation(sender_id, recipient_id) {
|
||||
const query = `
|
||||
INSERT INTO Conversations (conversation_type)
|
||||
VALUES ('direct')
|
||||
RETURNING conversation_id;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query);
|
||||
const conversation_id = result.rows[0].conversation_id;
|
||||
|
||||
// Add both users to the conversation
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO Memberships (conversation_id, user_id)
|
||||
VALUES ($1, $2), ($1, $3);
|
||||
`,
|
||||
[conversation_id, sender_id, recipient_id],
|
||||
);
|
||||
|
||||
return conversation_id;
|
||||
} catch (e) {
|
||||
console.error("Failed to create conversation ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessages(sender_id, recipient_id, limit = 50, cursor = 0) {
|
||||
console.log(
|
||||
`getMessages for Username: ${username}, recipient: ${recipient}, limit: ${limit}, cursor: ${cursor}`,
|
||||
`getMessages for sender_id: ${sender_id}, recipient_id: ${recipient_id}, limit: ${limit}, cursor: ${cursor}`,
|
||||
);
|
||||
let query;
|
||||
let params;
|
||||
|
||||
if (cursor) {
|
||||
query = `
|
||||
SELECT * FROM messages
|
||||
WHERE ((sender = $1 AND recipient = $2) OR (sender = $2 AND recipient = $1))
|
||||
AND message_id < $3
|
||||
ORDER BY message_id DESC
|
||||
LIMIT $4;
|
||||
`;
|
||||
params = [username, recipient, cursor, limit];
|
||||
} else {
|
||||
query = `
|
||||
SELECT * FROM messages
|
||||
WHERE (sender = $1 AND recipient = $2) OR (sender = $2 AND recipient = $1)
|
||||
SELECT * FROM Messages
|
||||
WHERE conversation_id = $1
|
||||
AND message_id < $2
|
||||
ORDER BY message_id DESC
|
||||
LIMIT $3;
|
||||
`;
|
||||
params = [username, recipient, limit];
|
||||
params = [await getConversationId(sender_id, recipient_id), cursor, limit];
|
||||
} else {
|
||||
query = `
|
||||
SELECT * FROM Messages
|
||||
WHERE conversation_id = $1
|
||||
ORDER BY message_id DESC
|
||||
LIMIT $2;
|
||||
`;
|
||||
params = [await getConversationId(sender_id, recipient_id), limit];
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -202,9 +265,37 @@ async function getMessages(username, recipient, limit = 50, cursor = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getConversationId(sender_id, recipient_id) {
|
||||
console.log(
|
||||
`kldsdfjklsdfjklsdjfkl , sender_id: ${sender_id}, recipient_id: ${recipient_id}`,
|
||||
);
|
||||
const query = `
|
||||
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 = $2
|
||||
)
|
||||
LIMIT 1;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [sender_id, recipient_id]);
|
||||
if (result.rows.length > 0) {
|
||||
return result.rows[0].conversation_id;
|
||||
} else {
|
||||
console.log("No conversation found between these users.");
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to get conversation id ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkUserExist(username) {
|
||||
const query = `
|
||||
SELECT 1 FROM accounts
|
||||
SELECT 1 FROM Accounts
|
||||
WHERE LOWER(username) = LOWER($1)
|
||||
LIMIT 1;
|
||||
`;
|
||||
@@ -213,7 +304,7 @@ async function checkUserExist(username) {
|
||||
const result = await client.query(query, [username]);
|
||||
return result.rows.length > 0;
|
||||
} catch (e) {
|
||||
console.error("Failed to check if user exist ", e);
|
||||
console.error("Failed to check if user exists ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -221,75 +312,89 @@ async function checkUserExist(username) {
|
||||
async function getPassword(username) {
|
||||
console.log(`Get password for: ${username}`);
|
||||
const query = `
|
||||
SELECT password FROM accounts
|
||||
WHERE LOWER(username) = LOWER($1);
|
||||
SELECT password_hash FROM Accounts
|
||||
WHERE LOWER(username) = LOWER($1);
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [username]);
|
||||
return result.rows[0].password;
|
||||
if (result.rows.length > 0) {
|
||||
return result.rows[0].password_hash;
|
||||
} else {
|
||||
console.log("No user found with username: ", username);
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to get user password ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function changePassword(username, newPassword) {
|
||||
async function changePassword(username, newPasswordHash) {
|
||||
const query = `
|
||||
UPDATE accounts
|
||||
SET password = $1
|
||||
UPDATE Accounts
|
||||
SET password_hash = $1
|
||||
WHERE username = $2;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [newPassword, username]);
|
||||
await client.query(query, [newPasswordHash, username]);
|
||||
} catch (e) {
|
||||
console.error("Failed to change password ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function insertContact(username, usernameContact, read) {
|
||||
async function insertContact(sender_id, receiverUsername, read) {
|
||||
const timestamp = getTime();
|
||||
console.log(
|
||||
`insertContact username: ${username}, usernameContact: ${usernameContact}, read: ${read}`,
|
||||
`insertContact sender_id: ${sender_id}, receiverUsername: ${receiverUsername}, read: ${read}`,
|
||||
);
|
||||
|
||||
const contact_name = await getUserId(receiverUsername);
|
||||
|
||||
const query = `
|
||||
INSERT INTO contacts (username, usernameContact, lastActive, read)
|
||||
INSERT INTO Contacts (sender_id, contact_name, last_active, read)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT ON CONSTRAINT unique_username_contact
|
||||
ON CONFLICT ON CONSTRAINT unique_contact
|
||||
DO NOTHING;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [username, usernameContact, timestamp, read]);
|
||||
await client.query(query, [sender_id, contact_name, timestamp, read]);
|
||||
} catch (e) {
|
||||
console.error("Failed to insert contact ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function getContacts(username) {
|
||||
async function getContacts(user_id) {
|
||||
const query = `
|
||||
SELECT usernameContact, read FROM contacts
|
||||
WHERE username = $1
|
||||
ORDER BY lastActive ASC;
|
||||
SELECT
|
||||
c.contact_name,
|
||||
c.read,
|
||||
c.last_active,
|
||||
a.username as receiver_username
|
||||
FROM Contacts c
|
||||
JOIN Accounts a ON c.contact_name = a.user_id
|
||||
WHERE c.sender_id = $1
|
||||
ORDER BY c.last_active DESC;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [username]);
|
||||
const result = await client.query(query, [user_id]);
|
||||
return result.rows;
|
||||
} catch (e) {
|
||||
console.error("Failed to get contacts ", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteContact(username, usernamecontact) {
|
||||
async function deleteContact(user_id, contact_name) {
|
||||
const query = `
|
||||
DELETE FROM contacts
|
||||
WHERE (LOWER(username) = LOWER($1) AND LOWER(usernamecontact) = LOWER($2))
|
||||
DELETE FROM Contacts
|
||||
WHERE sender_id = $1 AND contact_name = $2
|
||||
RETURNING *;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [username, usernamecontact]);
|
||||
const result = await client.query(query, [user_id, contact_name]);
|
||||
if (result.rowCount === 0) {
|
||||
console.log("No matching contact found with:", {
|
||||
username,
|
||||
usernamecontact,
|
||||
user_id,
|
||||
contact_name,
|
||||
});
|
||||
} else {
|
||||
console.log("Successfully deleted contact");
|
||||
@@ -299,45 +404,39 @@ async function deleteContact(username, usernamecontact) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateContactStatus(username, usernamecontact, read) {
|
||||
async function updateContactStatus(user_id, contact_name, read) {
|
||||
const query = `
|
||||
UPDATE contacts SET read = $1
|
||||
WHERE username = $2 AND usernamecontact = $3
|
||||
UPDATE Contacts SET read = $1
|
||||
WHERE sender_id = $2 AND contact_name = $3;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [read, username, usernamecontact]);
|
||||
await updateContactLastActive(username, usernamecontact);
|
||||
await client.query(query, [read, user_id, contact_name]);
|
||||
await updateContactLastActive(user_id, contact_name);
|
||||
console.log("Successfully updated contact status");
|
||||
} catch (e) {
|
||||
console.error("Failed to update contact status ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateContactLastActive(username, usernamecontact) {
|
||||
async function updateContactLastActive(user_id, contact_name) {
|
||||
const timestamp = getTime();
|
||||
const query = `
|
||||
UPDATE contacts SET lastActive = $1
|
||||
WHERE username = $2 AND usernamecontact = $3
|
||||
UPDATE Contacts
|
||||
SET last_active = $1
|
||||
WHERE sender_id = $2 AND contact_name = $3;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [timestamp, username, usernamecontact]);
|
||||
await client.query(query, [timestamp, user_id, contact_name]);
|
||||
console.log("Successfully updated contact last active time");
|
||||
} catch (e) {
|
||||
console.error("Failed to update contact last active time");
|
||||
console.error("Failed to update contact last active time ", e);
|
||||
}
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = ("0" + (now.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + now.getDate()).slice(-2);
|
||||
|
||||
const hour = ("0" + now.getHours()).slice(-2);
|
||||
const minute = ("0" + now.getMinutes()).slice(-2);
|
||||
const second = ("0" + now.getSeconds()).slice(-2);
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
return new Date();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
client,
|
||||
insertUser,
|
||||
|
||||
@@ -192,7 +192,7 @@ app.post("/api/auth/login", async (req, res) => {
|
||||
app.get("/api/auth/validate", authorizeUser, (req, res) => {
|
||||
return res.status(200).json({
|
||||
message: "Authorized",
|
||||
username: req.user.username,
|
||||
username: req.user.user_id,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -209,7 +209,7 @@ app.delete("/api/chat/contacts/:contact", authorizeUser, async (req, res) => {
|
||||
return res.status(400).json({ message: "Invalid username provided" });
|
||||
}
|
||||
|
||||
await deleteContact(req.user.username, usernameContact);
|
||||
await deleteContact(req.user.user_id, usernameContact);
|
||||
return res.status(200).json({ message: "Successfully deleted contact" });
|
||||
});
|
||||
|
||||
@@ -225,7 +225,7 @@ app.put("/api/chat/contacts/:contact", authorizeUser, async (req, res) => {
|
||||
}
|
||||
|
||||
const read = req.body.status;
|
||||
await updateContactStatus(req.user.username, usernameContact, read);
|
||||
await updateContactStatus(req.user.user_id, usernameContact, read);
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
@@ -243,19 +243,19 @@ app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
|
||||
return res.status(400).json({ message: "Invalid username provided" });
|
||||
}
|
||||
|
||||
await insertContact(req.user.username, usernameContact, true);
|
||||
await insertContact(req.user.user_id, usernameContact, true);
|
||||
|
||||
return res.status(200).json({ message: "Successfully inserted contact" });
|
||||
});
|
||||
|
||||
app.get("/api/chat/contacts", authorizeUser, async (req, res) => {
|
||||
if (!req.user.username) {
|
||||
if (!req.user.user_id) {
|
||||
return res.status(401).json({
|
||||
message: "Missing username (that's weird you shouldn't see that)",
|
||||
});
|
||||
}
|
||||
const contacts = await getContacts(req.user.username);
|
||||
console.log("Sent contacts list for: ", req.user.username);
|
||||
const contacts = await getContacts(req.user.user_id);
|
||||
console.log("Sent contacts list for: ", req.user.user_id);
|
||||
return res.status(200).json(contacts);
|
||||
});
|
||||
|
||||
@@ -266,9 +266,15 @@ app.get("/api/chat/messages/:contact", authorizeUser, async (req, res) => {
|
||||
const limit = parseInt(req.query.limit) || 50;
|
||||
const cursor = parseInt(req.query.cursor) || 0;
|
||||
|
||||
const contactId = await getUserId(req.params.contact);
|
||||
|
||||
// if (!contactId) {
|
||||
// console.log("abcdefg", req.params.contact);
|
||||
// return res.status(400).json({ messaeg: "Invalid contact" });
|
||||
// }
|
||||
const messages = await getMessages(
|
||||
req.user.username,
|
||||
req.params.contact,
|
||||
req.user.user_id,
|
||||
contactId,
|
||||
limit,
|
||||
cursor,
|
||||
);
|
||||
@@ -276,17 +282,10 @@ app.get("/api/chat/messages/:contact", authorizeUser, async (req, res) => {
|
||||
return res.status(404).json({ message: "No more messages found" });
|
||||
}
|
||||
|
||||
console.log("Sent messages for: ", req.user.username, "messages: ", messages);
|
||||
console.log("Sent messages for: ", req.user.user_id, "messages: ", messages);
|
||||
return res.status(200).json({ messages });
|
||||
});
|
||||
|
||||
app.post("/api/chat/sendmessage", authorizeUser, async (req, res) => {
|
||||
const message = req.body.message?.trim();
|
||||
//TODO filter for invalid characters in message
|
||||
|
||||
return res.status(500).json({ message: "HUJ!" });
|
||||
});
|
||||
|
||||
app.post(
|
||||
"/api/chat/attachment",
|
||||
upload.single("attachment"),
|
||||
|
||||
Reference in New Issue
Block a user