247 lines
9.8 KiB
JavaScript
247 lines
9.8 KiB
JavaScript
import pg from 'pg';
|
|
import fs from 'fs';
|
|
import { convertMsgType, logError } from './utils.js';
|
|
import { exec } from 'child_process';
|
|
|
|
const { Client } = pg;
|
|
|
|
const getClient = async () => {
|
|
const client = new Client({
|
|
user: process.env.POSTGRES_USER,
|
|
password: process.env.POSTGRES_PASSWORD,
|
|
host: process.env.POSTGRES_HOST,
|
|
port: process.env.POSTGRES_PORT,
|
|
database: process.env.POSTGRES_DB
|
|
});
|
|
await client.connect();
|
|
|
|
await client.query(fs.readFileSync('./scheme.psql').toString());
|
|
|
|
if ((await client.query("SELECT * FROM cities")).rowCount < 6079) {
|
|
await client.query("DELETE FROM cities");
|
|
|
|
//Not sure if pg has support for such kind of things, sooooooooo
|
|
exec(`PGPASSWORD=${process.env.POSTGRES_PASSWORD} psql -h ${process.env.POSTGRES_HOST} -p ${process.env.POSTGRES_PORT} -d ${process.env.POSTGRES_DB} -U ${process.env.POSTGRES_USER} -f ./cities.sql`, (error) => {
|
|
if (error) logError(error);
|
|
})
|
|
}
|
|
|
|
return client;
|
|
};
|
|
|
|
export const db = await getClient();
|
|
|
|
|
|
const getAmountOfUserPictures = async (roomId) => {
|
|
return (await db.query("SELECT COUNT(*) FROM media WHERE owner = $1 AND purpose = 'p'", [roomId])).rows[0].count;
|
|
};
|
|
|
|
const getCurrentUserAction = async (roomId) => {
|
|
return (await db.query('SELECT current_action FROM users WHERE room_id = $1', [roomId])).rows[0].current_action;
|
|
};
|
|
|
|
const setUserState = async (roomId, state) => {
|
|
await db.query("UPDATE users SET current_action = $1 WHERE room_id = $2", [state, roomId]);
|
|
};
|
|
|
|
const appendUserPictures = async (roomId, mxc, type) => {
|
|
await db.query("INSERT INTO media (owner, type, purpose, url) VALUES ($1, $2, 'p', $3)", [roomId, type, mxc]);
|
|
};
|
|
|
|
const fullEraseUser = async (roomId) => {
|
|
await eraseUser(roomId)
|
|
await eraseUserLikes(roomId);
|
|
await eraseUserMedia(roomId);
|
|
await eraseUserMessages(roomId);
|
|
}
|
|
|
|
const eraseUser = async (roomId) => {
|
|
await db.query("DELETE FROM users WHERE room_id = $1", [roomId]);
|
|
};
|
|
|
|
const eraseUserLikes = async (roomId) => {
|
|
await db.query("DELETE FROM likes WHERE sender = $1 OR recipient = $1", [roomId]);
|
|
};
|
|
|
|
const eraseUserMedia = async (roomId) => {
|
|
await db.query("DELETE FROM media WHERE owner = $1", [roomId]);
|
|
};
|
|
|
|
const eraseUserMessages = async (roomid) => {
|
|
await db.query("DELETE FROM messages WHERE sender = $1 OR recipient = $1", [roomId]);
|
|
}
|
|
|
|
const eraseUserPfp = async (roomId) => {
|
|
await db.query("DELETE FROM media WHERE owner = $1 AND purpose = 'p'", [roomId]);
|
|
}
|
|
|
|
const selectProfilesForUser = async (roomId) => {
|
|
const { myrange, myinterest, mysex, myage, mycity } = (await db.query(`SELECT range AS myrange,
|
|
interest AS myinterest,
|
|
sex AS mysex,
|
|
age AS myage,
|
|
location AS mycity
|
|
FROM users WHERE room_id = $1`, [roomId])
|
|
).rows[0];
|
|
const { lat, lng } = (await db.query("SELECT lat, lng FROM cities WHERE ID = $1", [mycity])).rows[0];
|
|
//Selecting profiles other than user's and fitting their needs
|
|
let user = (await db.query(`SELECT
|
|
room_id, name, age, sex, description, location, range FROM users
|
|
WHERE
|
|
age::numeric <@ ANY(ARRAY[numrange($1 - 2, $1 + 2)])
|
|
AND room_id != $2
|
|
AND ${myinterest !== 'b' ? "sex = $3" : "$3 = $3 AND $4 = $4 AND $5 = $5 AND $6 = $6 AND $7 = $7"}
|
|
AND ${myrange !== 0 ?
|
|
`location = ANY(ARRAY(SELECT ID
|
|
FROM cities
|
|
WHERE
|
|
check_distance($6::double precision, $7::double precision, lat, lng, $5::double precision)
|
|
AND (check_distance($6::double precision, $7::double precision, lat, lng, range) OR range = 0)
|
|
))`
|
|
:
|
|
`range = 0 OR
|
|
check_distance($6::double precision, $7::double precision, (SELECT lat FROM cities WHERE ID = location), (SELECT lng FROM cities WHERE ID = location), range)`
|
|
}
|
|
AND (interest = $4 OR interest = 'b')
|
|
ORDER BY RANDOM()
|
|
LIMIT 1`, [myage, roomId, myinterest, mysex, myrange, lat, lng])
|
|
).rows[0];
|
|
|
|
if (!user) return null;
|
|
let media = await getUserProfilePictures(user.room_id);
|
|
|
|
user.media = media;
|
|
return user;
|
|
};
|
|
|
|
const setUserCurrentlyViewingProfile = async (roomId, anotherRoomId) => {
|
|
await db.query("UPDATE users SET currently_viewing = $1 WHERE room_id = $2", [anotherRoomId, roomId]);
|
|
};
|
|
|
|
const getUserCurrentlyViewingProfile = async (roomId) => {
|
|
return (await db.query("SELECT currently_viewing FROM users WHERE room_id = $1", [roomId])).rows[0].currently_viewing;
|
|
};
|
|
|
|
//Newlike is a room id of a user who was liked_profiles
|
|
const appendUserLikes = async (roomId, newLike) => {
|
|
//We need to delete likes that was read from both, so we can add a new (the same) like.
|
|
await db.query(`DELETE FROM likes l1
|
|
USING likes l2
|
|
WHERE l1.sender = l2.recipient
|
|
AND l1.recipient = l2.sender
|
|
AND l1.read = TRUE
|
|
AND l2.read = TRUE`);
|
|
|
|
await db.query("INSERT INTO likes (sender, recipient) VALUES ($1, $2) ON CONFLICT DO NOTHING", [roomId, newLike]);
|
|
};
|
|
|
|
const getUserLikes = async (roomId) => {
|
|
return (await db.query("SELECT recipient FROM likes WHERE sender = $1", [roomId])).rows[0].recipient;
|
|
};
|
|
|
|
const checkForMutualLike = async (roomId1, roomId2) => {
|
|
return (await db.query(`SELECT COUNT(*) > 0 AS value
|
|
FROM likes l1
|
|
JOIN likes l2 ON l1.sender = l2.recipient AND l1.recipient = l2.sender
|
|
WHERE (l1.read = FALSE OR l2.read = FALSE)
|
|
AND l1.sender = $1
|
|
AND l1.recipient = $2`, [roomId1, roomId2])).rows[0].value;
|
|
};
|
|
|
|
const getProfileInfo = async (roomId) => {
|
|
let user = (await db.query("SELECT mx_id, room_id, name, age, sex, description, location FROM users WHERE room_id = $1", [roomId])).rows[0];
|
|
if (!user) return null;
|
|
let media = await getUserProfilePictures(user.room_id);
|
|
user.media = media;
|
|
return user;
|
|
};
|
|
|
|
const getUserProfilePictures = async (roomId) => {
|
|
return (await db.query("SELECT url, type FROM media WHERE owner = $1 AND purpose = 'p'", [roomId])).rows;
|
|
};
|
|
|
|
const getAllLikesForUser = async (roomId) => {
|
|
return (await db.query("SELECT sender FROM likes WHERE recipient = $1 AND read = FALSE", [roomId])).rows;
|
|
};
|
|
|
|
const markLikeAsRead = async (roomId, recipient,) => {
|
|
await db.query("UPDATE likes SET read = TRUE WHERE sender = $1 AND recipient = $2", [roomId, recipient]);
|
|
};
|
|
|
|
const uploadMediaAsMessage = async (roomId, type, mxc) => {
|
|
await db.query("INSERT INTO media(owner, type, purpose, url) VALUES ($1, $2, 'm', $3)", [roomId, convertMsgType(type), mxc]);
|
|
};
|
|
|
|
const insertMessageIntoDB = async (roomId, recipient, type, content) => {
|
|
let rowAmount = (await db.query("INSERT INTO messages (sender, recipient, type, content) VALUES ($1, $2, $3, $4) ON CONFLICT(sender, recipient) DO NOTHING RETURNING *", [roomId, recipient, convertMsgType(type), content])).rowCount;
|
|
return rowAmount == 1;
|
|
};
|
|
|
|
const getUnreadMessages = async (roomId) => {
|
|
return (await db.query("SELECT (SELECT mx_id FROM users WHERE room_id = sender LIMIT 1), sender, type, content FROM messages WHERE recipient = $1 AND read = FALSE", [roomId])).rows
|
|
};
|
|
|
|
const markMessageAsRead = async (roomId, recipient) => {
|
|
return (await db.query("UPDATE messages SET read = TRUE WHERE sender = $1 AND recipient = $2", [roomId, recipient]));
|
|
}
|
|
|
|
const setUserLanguage = async (roomId, language) => {
|
|
await db.query("UPDATE users SET language = $1 WHERE room_id = $2", [language, roomId]);
|
|
}
|
|
|
|
const getUserLanguage = async (roomId) => {
|
|
return (await db.query("SELECT language FROM users WHERE room_id = $1", [roomId])).rows[0].language;
|
|
}
|
|
|
|
const findCity = async (name) => {
|
|
return (await db.query(`SELECT ID, name, lat, lng, country, levenshtein(name, $1) AS similarity
|
|
FROM cities
|
|
ORDER BY similarity ASC
|
|
LIMIT 5`, [name])
|
|
).rows;
|
|
}
|
|
|
|
const getCityNameByID = async (id) => {
|
|
return (await db.query(`SELECT name FROM cities WHERE ID = $1`, [id])).rows[0].name;
|
|
}
|
|
|
|
const getCountryNameByID = async (id) => {
|
|
return (await db.query(`SELECT country FROM cities WHERE ID = $1`, [id])).rows[0].country;
|
|
}
|
|
|
|
const doesUserExist = async (roomId) => {
|
|
return (await db.query("SELECT EXISTS (SELECT * FROM users WHERE room_id = $1)", [roomId])).rows[0].exists;
|
|
}
|
|
|
|
const createUser = async (mx_id, roomId) => {
|
|
await db.query("INSERT INTO users(mx_id, room_id, current_action) VALUES ($1, $2, $3)", [mx_id, roomId, "wait_start"]);
|
|
}
|
|
|
|
export {
|
|
fullEraseUser,
|
|
appendUserPictures,
|
|
setUserState,
|
|
getCurrentUserAction,
|
|
getAmountOfUserPictures,
|
|
selectProfilesForUser,
|
|
setUserCurrentlyViewingProfile,
|
|
getUserCurrentlyViewingProfile,
|
|
appendUserLikes,
|
|
getUserLikes,
|
|
checkForMutualLike,
|
|
getProfileInfo,
|
|
getAllLikesForUser,
|
|
markLikeAsRead,
|
|
uploadMediaAsMessage,
|
|
insertMessageIntoDB,
|
|
getUnreadMessages,
|
|
markMessageAsRead,
|
|
setUserLanguage,
|
|
getUserLanguage,
|
|
findCity,
|
|
getCityNameByID,
|
|
getCountryNameByID,
|
|
doesUserExist,
|
|
createUser,
|
|
eraseUserPfp
|
|
}; |