huge refactor
This commit is contained in:
parent
8a2967b420
commit
cad71873f4
|
@ -11,7 +11,7 @@ In case if your homeserver forbids such method of registration, you can try regi
|
||||||
Eventually, your bot will hit upon a rate limit. Even if there are only 2 users (beleive me, I tested!)
|
Eventually, your bot will hit upon a rate limit. Even if there are only 2 users (beleive me, I tested!)
|
||||||
To solve this problem, you can override rate limits for your bot if you are an administrator of a homeserver that hosts your bot OR in good relationships with one! ;)
|
To solve this problem, you can override rate limits for your bot if you are an administrator of a homeserver that hosts your bot OR in good relationships with one! ;)
|
||||||
Anyway, you should login to your synape database and type
|
Anyway, you should login to your synape database and type
|
||||||
``INSERT INTO ratelimit_override VALUES ("@name-of-your-bot:name-of-your-home.server", 0, 0);``
|
``INSERT INTO ratelimit_override VALUES ('@name-of-your-bot:name-of-your-home.server', 0, 0);``
|
||||||
That will do the trick.
|
That will do the trick.
|
||||||
## Actual programm
|
## Actual programm
|
||||||
### Docker
|
### Docker
|
||||||
|
|
|
@ -46,10 +46,13 @@ CREATE TABLE IF NOT EXISTS cities (
|
||||||
country VARCHAR(64)
|
country VARCHAR(64)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS read_profiles (
|
||||||
|
sender VARCHAR(64),
|
||||||
|
recipient VARCHAR(64)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch SCHEMA public;
|
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch SCHEMA public;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION deg2rad(double precision) RETURNS double precision AS 'SELECT $1 * 0.01745329' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
|
CREATE OR REPLACE FUNCTION deg2rad(double precision) RETURNS double precision AS 'SELECT $1 * 0.01745329' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
|
||||||
-- lat1, lng1, lat2, lng2, range
|
-- lat1, lng1, lat2, lng2, range
|
||||||
CREATE OR REPLACE FUNCTION check_distance(double precision, double precision, double precision, double precision, double precision) RETURNS BOOLEAN AS '
|
CREATE OR REPLACE FUNCTION check_distance(double precision, double precision, double precision, double precision, double precision) RETURNS BOOLEAN AS '
|
||||||
|
|
219
src/db.js
219
src/db.js
|
@ -1,6 +1,6 @@
|
||||||
import pg from 'pg';
|
import pg from 'pg';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { convertMsgType, logError } from './utils.js';
|
import { logError } from './utils.js';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
const { Client } = pg;
|
const { Client } = pg;
|
||||||
|
@ -29,219 +29,4 @@ const getClient = async () => {
|
||||||
return client;
|
return client;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const db = await getClient();
|
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
|
|
||||||
};
|
|
604
src/index.js
604
src/index.js
|
@ -1,7 +1,5 @@
|
||||||
import {
|
import {
|
||||||
EncryptionAlgorithm,
|
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MessageEvent,
|
|
||||||
RustSdkCryptoStorageProvider,
|
RustSdkCryptoStorageProvider,
|
||||||
SimpleFsStorageProvider,
|
SimpleFsStorageProvider,
|
||||||
} from "matrix-bot-sdk";
|
} from "matrix-bot-sdk";
|
||||||
|
@ -13,307 +11,368 @@ import {
|
||||||
logError,
|
logError,
|
||||||
logInfo,
|
logInfo,
|
||||||
readConfig,
|
readConfig,
|
||||||
uploadMediaFromEvent
|
uploadMediaFromEvent,
|
||||||
} from './utils.js';
|
|
||||||
|
|
||||||
import {
|
|
||||||
appendUserLikes,
|
|
||||||
appendUserPictures,
|
|
||||||
checkForMutualLike,
|
|
||||||
fullEraseUser,
|
|
||||||
getAmountOfUserPictures,
|
|
||||||
getCurrentUserAction,
|
|
||||||
getUnreadMessages,
|
|
||||||
getUserCurrentlyViewingProfile,
|
|
||||||
insertMessageIntoDB,
|
|
||||||
markMessageAsRead,
|
|
||||||
setUserState,
|
|
||||||
uploadMediaAsMessage,
|
uploadMediaAsMessage,
|
||||||
setUserLanguage,
|
|
||||||
getUserLanguage,
|
|
||||||
findCity,
|
findCity,
|
||||||
doesUserExist,
|
insertMessageIntoDB
|
||||||
createUser,
|
} from './utils.js';
|
||||||
eraseUserPfp,
|
|
||||||
getProfileInfo
|
|
||||||
} from './db.js';
|
|
||||||
|
|
||||||
import {
|
|
||||||
processRequest,
|
|
||||||
showRandomProfileToUser,
|
|
||||||
showNewLikes,
|
|
||||||
wait_start,
|
|
||||||
range,
|
|
||||||
interest,
|
|
||||||
pictures,
|
|
||||||
loc,
|
|
||||||
age,
|
|
||||||
sex,
|
|
||||||
showProfileToUser,
|
|
||||||
showProfile
|
|
||||||
} from "./interactions.js";
|
|
||||||
|
|
||||||
import { db } from "./db.js";
|
|
||||||
|
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
import { I18n } from "i18n-js";
|
import { I18n } from "i18n-js";
|
||||||
|
|
||||||
const config = readConfig();
|
import { User } from "./user.js";
|
||||||
|
|
||||||
const homeserverUrl = config.homeserverURL;
|
const config = readConfig();
|
||||||
const accessToken = config.token;
|
|
||||||
const maxAmountOfPhotoesPerUser = config.maxAmountOfPhotoesPerUser;
|
|
||||||
|
|
||||||
const crypto = new RustSdkCryptoStorageProvider("./bot_data/encryption_bot_sled", StoreType.Sled);
|
const crypto = new RustSdkCryptoStorageProvider("./bot_data/encryption_bot_sled", StoreType.Sled);
|
||||||
const storage = new SimpleFsStorageProvider("./bot_data/bot.json");
|
const storage = new SimpleFsStorageProvider("./bot_data/bot.json");
|
||||||
|
|
||||||
const client = new MatrixClient(homeserverUrl, accessToken, storage, crypto);
|
const client = new MatrixClient(config.homeserverURL, config.token, storage, crypto);
|
||||||
|
|
||||||
client.on("room.message", async (roomId, event) => {
|
client.on("room.message", async (roomId, event) => {
|
||||||
try {
|
if (event.sender === await client.getUserId()) return;
|
||||||
if (event.sender === await client.getUserId()) return;
|
if (event.content?.msgtype !== 'm.text' && event.content?.msgtype !== 'm.image' && event.content?.msgtype !== 'm.video') return;
|
||||||
|
|
||||||
const i18n = new I18n({
|
const i18n = new I18n({
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!await doesUserExist(roomId)) {
|
|
||||||
i18n.locale = 'en'
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "usernotexists"]));
|
|
||||||
i18n.locale = 'ru'
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "usernotexists"]));
|
|
||||||
let mx_id = event.sender;
|
|
||||||
await createUser(mx_id, roomId);
|
|
||||||
|
|
||||||
return;
|
let user = new User(roomId);
|
||||||
}
|
|
||||||
|
|
||||||
if (event.content?.msgtype !== 'm.text' && event.content?.msgtype !== 'm.image' && event.content?.msgtype !== 'm.video') return;
|
if (!await user.exists()) {
|
||||||
|
i18n.locale = 'en'
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "usernotexists"]));
|
||||||
|
i18n.locale = 'ru'
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "usernotexists"]));
|
||||||
|
let mxid = event.sender;
|
||||||
|
|
||||||
let current_action = await getCurrentUserAction(roomId);
|
await user.init(mxid);
|
||||||
let answer = event.content.body;
|
return;
|
||||||
let msgtype = event.content.msgtype
|
}
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
const current_action = await user.getCurrentAction();
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
switch (current_action) {
|
const language = await user.getLanguage();
|
||||||
case "wait_start":
|
i18n.locale = language;
|
||||||
await wait_start(client, roomId, current_action, answer, false);
|
|
||||||
break;
|
|
||||||
case "wait_start_u":
|
|
||||||
await wait_start(client, roomId, current_action, answer, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "location":
|
let answer = event.content.body;
|
||||||
await loc(client, roomId, current_action, answer, false);
|
let msgtype = event.content.msgtype
|
||||||
break;
|
|
||||||
case "location_u":
|
|
||||||
await loc(client, roomId, current_action, answer, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "range":
|
|
||||||
await range(client, roomId, current_action, answer, false);
|
|
||||||
break;
|
|
||||||
case "range_u":
|
|
||||||
await range(client, roomId, current_action, answer, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "name":
|
// // Updating actions are "<action>-u"
|
||||||
await processRequest(client, roomId, current_action, answer, 'age');
|
let action = current_action.split("-")
|
||||||
break;
|
|
||||||
case "name_u":
|
|
||||||
await processRequest(client, roomId, current_action, answer, 'menu');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "age":
|
switch (action[0]) {
|
||||||
await age(client, roomId, current_action, answer, false);
|
case "wait_start":
|
||||||
break;
|
let command = answer.split(" ");
|
||||||
case "age_u":
|
if (command[0] !== "!start") return;
|
||||||
await age(client, roomId, current_action, answer, true);
|
if (command[1] !== "ru" && command[1] !== "en") return;
|
||||||
break;
|
|
||||||
|
|
||||||
case "sex":
|
await user.set("language", command[1]);
|
||||||
await sex(client, roomId, current_action, answer, false);
|
await user.setState("location");
|
||||||
break;
|
await client.sendText(roomId, i18n.t(["setup", "location"]));
|
||||||
case "sex_u":
|
break;
|
||||||
await sex(client, roomId, current_action, answer, true);
|
case "location":
|
||||||
break;
|
let number = parseInt(answer);
|
||||||
|
if (!number) {
|
||||||
|
const cities = await findCity(answer);
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "choosecity"], {
|
||||||
|
number1: cities[0].id,
|
||||||
|
name1: cities[0].name,
|
||||||
|
country1: cities[0].country,
|
||||||
|
lat1: cities[0].lat,
|
||||||
|
lng1: cities[0].lng,
|
||||||
|
|
||||||
case "interest":
|
number2: cities[1].id,
|
||||||
await interest(client, roomId, current_action, answer, false);
|
name2: cities[1].name,
|
||||||
break;
|
country2: cities[1].country,
|
||||||
case "interest_u":
|
lat2: cities[1].lat,
|
||||||
await interest(client, roomId, current_action, answer, true);
|
lng2: cities[1].lng,
|
||||||
break;
|
|
||||||
|
|
||||||
case "description":
|
number3: cities[2].id,
|
||||||
await processRequest(client, roomId, current_action, answer, 'pictures');
|
name3: cities[2].name,
|
||||||
break;
|
country3: cities[2].country,
|
||||||
case "description_u":
|
lat3: cities[2].lat,
|
||||||
await processRequest(client, roomId, current_action, answer, 'menu');
|
lng3: cities[2].lng,
|
||||||
break;
|
|
||||||
|
|
||||||
case "pictures":
|
number4: cities[3].id,
|
||||||
pictures(client, roomId, current_action, event, false);
|
name4: cities[3].name,
|
||||||
break;
|
country4: cities[3].country,
|
||||||
case "pictures_u":
|
lat4: cities[3].lat,
|
||||||
pictures(client, roomId, current_action, event, true);
|
lng4: cities[3].lng,
|
||||||
break;
|
|
||||||
|
|
||||||
case "language_u":
|
number5: cities[4].id,
|
||||||
if (answer !== "ru" && answer !== "en") return;
|
name5: cities[4].name,
|
||||||
await setUserLanguage(roomId, answer);
|
country5: cities[4].country,
|
||||||
i18n.locale = answer;
|
lat5: cities[4].lat,
|
||||||
await setUserState(roomId, "menu");
|
lng5: cities[4].lng,
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
}));
|
||||||
break;
|
|
||||||
|
|
||||||
case "view_profiles":
|
|
||||||
if (answer == '👍️' || answer == '❤️' || answer == '1') {
|
|
||||||
let currently_viewing = await getUserCurrentlyViewingProfile(roomId);
|
|
||||||
await appendUserLikes(roomId, currently_viewing);
|
|
||||||
let value = await checkForMutualLike(roomId, currently_viewing);
|
|
||||||
if (value) {
|
|
||||||
await client.sendText(currently_viewing, i18n.t(["general", "newlikes"]));
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "newlikes"]));
|
|
||||||
}
|
|
||||||
} else if (answer == '💌' || answer == '3') {
|
|
||||||
await setUserState(roomId, 'send_message');
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "message"]));
|
|
||||||
return;
|
|
||||||
} else if (answer == '🏠️' || answer == '4') {
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
await setUserState(roomId, 'menu');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
break;
|
|
||||||
case 'send_message':
|
|
||||||
let recipient = await getUserCurrentlyViewingProfile(roomId);
|
|
||||||
let content;
|
|
||||||
if (msgtype == "m.image" || msgtype == "m.video") {
|
|
||||||
let mxc = await uploadMediaFromEvent(client, event);
|
|
||||||
await uploadMediaAsMessage(roomId, msgtype, mxc);
|
|
||||||
content = mxc;
|
|
||||||
} else {
|
|
||||||
content = answer;
|
|
||||||
}
|
|
||||||
if (await insertMessageIntoDB(roomId, recipient, msgtype, content)) {
|
|
||||||
await client.sendText(recipient, i18n.t(["general", "newmessage"]));
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "messagesent"]));
|
|
||||||
} else {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "alreadymessaged"]));
|
|
||||||
}
|
|
||||||
await setUserState(roomId, 'view_profiles');
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
break;
|
|
||||||
case 'menu':
|
|
||||||
switch (answer) {
|
|
||||||
case '0':
|
|
||||||
let profile = await getProfileInfo(roomId);
|
|
||||||
await showProfile(client, roomId, profile);
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
await setUserState(roomId, 'view_profiles');
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
await showNewLikes(client, roomId);
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
let unreadMessages = await getUnreadMessages(roomId);
|
|
||||||
if (!unreadMessages || unreadMessages.length == 0) {
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "nonewmessages"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "msg"]));
|
|
||||||
|
|
||||||
for (let message of unreadMessages) {
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "showmessage"], { user: message.mx_id }));
|
|
||||||
|
|
||||||
if (message.type == "t") {
|
|
||||||
await client.sendText(roomId, message.content)
|
|
||||||
} else if (message.type == "p" || message.type == "v") {
|
|
||||||
let msgtype;
|
|
||||||
|
|
||||||
if (message.type == "p") {
|
|
||||||
msgtype = "m.image";
|
|
||||||
} else if (message.type == "v") {
|
|
||||||
msgtype = "m.video";
|
|
||||||
}
|
|
||||||
|
|
||||||
await client.sendMessage(roomId, {
|
|
||||||
msgtype: msgtype,
|
|
||||||
body: "Message",
|
|
||||||
url: message.content
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await markMessageAsRead(message.sender, roomId);
|
|
||||||
}
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
setUserState(roomId, 'location_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "location"]));
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
setUserState(roomId, 'range_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "range"]));
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
setUserState(roomId, 'name_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "name"]));
|
|
||||||
break;
|
|
||||||
case '7':
|
|
||||||
setUserState(roomId, 'age_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "age"]));
|
|
||||||
break;
|
|
||||||
case '8':
|
|
||||||
setUserState(roomId, 'sex_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "sex"]));
|
|
||||||
break;
|
|
||||||
case '9':
|
|
||||||
setUserState(roomId, 'interest_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "interest"]));
|
|
||||||
break;
|
|
||||||
case '10':
|
|
||||||
setUserState(roomId, 'description_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "description"]));
|
|
||||||
break;
|
|
||||||
case '11':
|
|
||||||
await eraseUserPfp(roomId);
|
|
||||||
setUserState(roomId, 'pictures_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "pictures"]));
|
|
||||||
break;
|
|
||||||
case '12':
|
|
||||||
setUserState(roomId, 'language_u');
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "language"]));
|
|
||||||
default:
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "didntunderstand"]));
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "didntunderstand"]));
|
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
} catch (e) {
|
if (action[1] == "u")
|
||||||
logError(e);
|
await user.update(answer)
|
||||||
|
else
|
||||||
|
await user.process(answer)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "range":
|
||||||
|
const range = parseInt(answer);
|
||||||
|
if (!range && range !== 0)
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "range"]));
|
||||||
|
else
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(range)
|
||||||
|
else
|
||||||
|
await user.process(range);
|
||||||
|
break;
|
||||||
|
case "name":
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(answer)
|
||||||
|
else
|
||||||
|
await user.process(answer);
|
||||||
|
break;
|
||||||
|
case "age":
|
||||||
|
const age = parseInt(answer);
|
||||||
|
if (!age || age > 100)
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "age"]));
|
||||||
|
else if (age < 14) {
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "tooyoung"]));
|
||||||
|
await client.leaveRoom(roomId);
|
||||||
|
await user.fullErase();
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(age)
|
||||||
|
else
|
||||||
|
await user.process(age);
|
||||||
|
break;
|
||||||
|
case "sex":
|
||||||
|
const sex = answer.toLowerCase().trim();
|
||||||
|
if (sex !== "female" &&
|
||||||
|
sex !== "f" &&
|
||||||
|
sex !== "male" &&
|
||||||
|
sex !== "m")
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "sex"]));
|
||||||
|
else
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(sex[0])
|
||||||
|
else
|
||||||
|
await user.process(sex[0]);
|
||||||
|
break;
|
||||||
|
case "interest":
|
||||||
|
const interest = answer.toLowerCase().trim();
|
||||||
|
if (interest !== "female" &&
|
||||||
|
interest !== "f" &&
|
||||||
|
interest !== "male" &&
|
||||||
|
interest !== "m" &&
|
||||||
|
interest !== "b" &&
|
||||||
|
interest !== "both")
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "interest"]));
|
||||||
|
else
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(interest[0])
|
||||||
|
else
|
||||||
|
await user.process(interest[0]);
|
||||||
|
break;
|
||||||
|
case "description":
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(answer)
|
||||||
|
else
|
||||||
|
await user.process(answer);
|
||||||
|
break;
|
||||||
|
case "language":
|
||||||
|
if (answer !== "en" && answer !== "ru") {
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "language"]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i18n.locale = answer
|
||||||
|
user.i18n.locale = answer
|
||||||
|
if (action[1] == "u")
|
||||||
|
await user.update(answer);
|
||||||
|
else
|
||||||
|
await user.process(answer);
|
||||||
|
await user.getLanguage()
|
||||||
|
break;
|
||||||
|
case "pictures":
|
||||||
|
if (event.content?.msgtype !== 'm.image' && event.content?.msgtype !== 'm.video') {
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "done"]));
|
||||||
|
await user.setState("view_profiles")
|
||||||
|
await user.showRandomProfile();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const pictures_count = (await user.getProfilePictures()).length
|
||||||
|
|
||||||
|
if (pictures_count >= config.maxAmountOfPhotoesPerUser) {
|
||||||
|
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "toomuch"]));
|
||||||
|
await user.setState("view_profiles");
|
||||||
|
await user.showRandomProfile();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let mxc = await uploadMediaFromEvent(client, event);
|
||||||
|
let type = convertMsgType(msgtype);
|
||||||
|
await user.addProfilePicture(type, mxc);
|
||||||
|
const pictures_count = (await user.getProfilePictures()).length;
|
||||||
|
if (pictures_count < config.maxAmountOfPhotoesPerUser) {
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "more"], { amount: String(config.maxAmountOfPhotoesPerUser - pictures_count) }));
|
||||||
|
} else {
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "enough"]));
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "done"]));
|
||||||
|
await user.setState("view_profiles");
|
||||||
|
await user.showRandomProfile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "view_profiles":
|
||||||
|
if (answer == '👍️' || answer == '❤️' || answer == '1') {
|
||||||
|
let currently_viewing = await user.getCurrentlyViewingProfile();
|
||||||
|
|
||||||
|
await user.addLikeTo(currently_viewing);
|
||||||
|
let value = await user.checkForMutualLikeWith(currently_viewing);
|
||||||
|
if (value) {
|
||||||
|
await client.sendText(currently_viewing, i18n.t(["general", "newlikes"]));
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "newlikes"]));
|
||||||
|
}
|
||||||
|
} else if (answer == '💌' || answer == '3') {
|
||||||
|
await user.setState('send_message');
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "message"]));
|
||||||
|
return;
|
||||||
|
} else if (answer == '🏠️' || answer == '4') {
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
||||||
|
await user.setState('menu');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await user.showRandomProfile();
|
||||||
|
break;
|
||||||
|
case "send_message":
|
||||||
|
let recipient = await user.getCurrentlyViewingProfile();
|
||||||
|
let content;
|
||||||
|
|
||||||
|
if (msgtype == "m.image" || msgtype == "m.video") {
|
||||||
|
let mxc = await uploadMediaFromEvent(client, event);
|
||||||
|
await uploadMediaAsMessage(roomId, msgtype, mxc);
|
||||||
|
content = mxc;
|
||||||
|
} else {
|
||||||
|
content = answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await insertMessageIntoDB(roomId, recipient, msgtype, content)) {
|
||||||
|
await client.sendText(recipient, i18n.t(["general", "newmessage"]));
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "messagesent"]));
|
||||||
|
} else {
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "alreadymessaged"]));
|
||||||
|
}
|
||||||
|
await user.setState("view_profiles");
|
||||||
|
await user.showRandomProfile();
|
||||||
|
break;
|
||||||
|
case 'menu':
|
||||||
|
switch (answer) {
|
||||||
|
case '0':
|
||||||
|
let profile = await user.getProfileInfo();
|
||||||
|
await user.showProfile(profile);
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
await user.setState('view_profiles');
|
||||||
|
await user.showRandomProfile();
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
await user.showNewLikes();
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
let unreadMessages = await user.getUnreadMessages();
|
||||||
|
if (!unreadMessages || unreadMessages.length == 0) {
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "nonewmessages"]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "msg"]));
|
||||||
|
|
||||||
|
for (let message of unreadMessages) {
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "showmessage"], { user: message.mx_id }));
|
||||||
|
|
||||||
|
if (message.type == "t") {
|
||||||
|
await client.sendText(roomId, message.content)
|
||||||
|
} else if (message.type == "p" || message.type == "v") {
|
||||||
|
let msgtype;
|
||||||
|
|
||||||
|
if (message.type == "p") {
|
||||||
|
msgtype = "m.image";
|
||||||
|
} else if (message.type == "v") {
|
||||||
|
msgtype = "m.video";
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.sendMessage(roomId, {
|
||||||
|
msgtype: msgtype,
|
||||||
|
body: "Message",
|
||||||
|
url: message.content
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await user.markMessageAsRead(message.sender);
|
||||||
|
}
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
await user.setState('location-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "location"]));
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
await user.setState('range-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "range"]));
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
await user.setState('name-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "name"]));
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
await user.setState('age-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "age"]));
|
||||||
|
break;
|
||||||
|
case '8':
|
||||||
|
await user.setState('sex-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "sex"]));
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
await user.setState('interest-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "interest"]));
|
||||||
|
break;
|
||||||
|
case '10':
|
||||||
|
await user.setState('description-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "description"]));
|
||||||
|
break;
|
||||||
|
case '11':
|
||||||
|
await user.erasePfp();
|
||||||
|
await user.setState('pictures-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "pictures"]));
|
||||||
|
break;
|
||||||
|
case '12':
|
||||||
|
await user.setState('language-u');
|
||||||
|
await client.sendText(roomId, i18n.t(["setup", "language"]));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "didntunderstand"]));
|
||||||
|
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await client.sendText(roomId, i18n.t(["errors", "didntunderstand"]));
|
||||||
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on("room.event", async (roomId, event) => {
|
client.on("room.event", async (roomId, event) => {
|
||||||
try {
|
try {
|
||||||
|
const user = new User(roomId);
|
||||||
|
|
||||||
if (event.type === "m.room.member" && event.content?.membership === "leave") {
|
if (event.type === "m.room.member" && event.content?.membership === "leave") {
|
||||||
await fullEraseUser(roomId);
|
await user.fullErase();
|
||||||
logInfo(`Bot has left a room with ID ${roomId}`);
|
logInfo(`Bot has left a room with ID ${roomId}`);
|
||||||
client.leaveRoom(roomId);
|
client.leaveRoom(roomId);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -341,21 +400,22 @@ client.on("room.invite", async (roomId, event) => {
|
||||||
logInfo(`Bot has joined a room with ID ${roomId}`);
|
logInfo(`Bot has joined a room with ID ${roomId}`);
|
||||||
|
|
||||||
let mx_id = event.sender;
|
let mx_id = event.sender;
|
||||||
|
const user = new User(roomId);
|
||||||
if (!await doesUserExist(roomId)) {
|
if (!await user.exists()) {
|
||||||
await createUser(mx_id, roomId);
|
await user.init(mx_id);
|
||||||
|
|
||||||
i18n.locale = "en";
|
i18n.locale = "en";
|
||||||
await client.sendText(roomId, i18n.t(["general", "welcome"]));
|
await client.sendText(roomId, i18n.t(["general", "welcome"]));
|
||||||
i18n.locale = "ru";
|
i18n.locale = "ru";
|
||||||
await client.sendText(roomId, i18n.t(["general", "welcome"]));
|
await client.sendText(roomId, i18n.t(["general", "welcome"]));
|
||||||
} else {
|
} else {
|
||||||
setUserState(roomId, 'view_profiles');
|
user.setState('view_profiles');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.start().then(() => logInfo("Bot started!"));
|
client.start().then(() => logInfo("Bot started!"));
|
||||||
|
|
||||||
|
export { client };
|
|
@ -1,352 +0,0 @@
|
||||||
import {
|
|
||||||
logError,
|
|
||||||
logInfo,
|
|
||||||
readConfig,
|
|
||||||
uploadMediaFromEvent,
|
|
||||||
convertMsgType
|
|
||||||
} from './utils.js';
|
|
||||||
|
|
||||||
import {
|
|
||||||
appendUserPictures,
|
|
||||||
checkForMutualLike,
|
|
||||||
fullEraseUser,
|
|
||||||
getAmountOfUserPictures,
|
|
||||||
setUserLanguage,
|
|
||||||
getUserLanguage,
|
|
||||||
findCity,
|
|
||||||
db,
|
|
||||||
setUserState,
|
|
||||||
selectProfilesForUser,
|
|
||||||
setUserCurrentlyViewingProfile,
|
|
||||||
getProfileInfo,
|
|
||||||
getAllLikesForUser,
|
|
||||||
markLikeAsRead,
|
|
||||||
getCountryNameByID,
|
|
||||||
getCityNameByID
|
|
||||||
} from "./db.js";
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
const config = readConfig();
|
|
||||||
const maxAmountOfPhotoesPerUser = config.maxAmountOfPhotoesPerUser;
|
|
||||||
|
|
||||||
|
|
||||||
import { I18n } from "i18n-js";
|
|
||||||
|
|
||||||
|
|
||||||
const requiresLengths = {
|
|
||||||
"location": 32,
|
|
||||||
"description": 512,
|
|
||||||
"name": 32
|
|
||||||
};
|
|
||||||
|
|
||||||
const processRequest = async (client, roomId, question, answer, nextQuestion) => {
|
|
||||||
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
if (answer.length > requiresLengths[question]) {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "toobig"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let q = question.split("_")
|
|
||||||
if (q[1] == "u")
|
|
||||||
await db.query(`UPDATE users SET ${q[0]} = $1 WHERE room_id = $2`, [answer, roomId]);
|
|
||||||
else
|
|
||||||
await db.query(`UPDATE users SET ${question} = $1 WHERE room_id = $2`, [answer, roomId]);
|
|
||||||
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "setopt"], { opt: answer }));
|
|
||||||
if (nextQuestion == "menu")
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "menu"]));
|
|
||||||
else
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", nextQuestion]));
|
|
||||||
|
|
||||||
setUserState(roomId, nextQuestion);
|
|
||||||
};
|
|
||||||
|
|
||||||
const showProfile = async (client, roomId, chosenProfile) => {
|
|
||||||
chosenProfile.country = await getCountryNameByID(chosenProfile.location);
|
|
||||||
chosenProfile.city = await getCityNameByID(chosenProfile.location);
|
|
||||||
|
|
||||||
let message =
|
|
||||||
`${chosenProfile.country}, ${chosenProfile.city}.
|
|
||||||
${chosenProfile.name}, ${chosenProfile.sex == 'm' ? 'male' : 'female'}, ${chosenProfile.age}.
|
|
||||||
${chosenProfile.description}`;
|
|
||||||
|
|
||||||
await client.sendText(roomId, message);
|
|
||||||
|
|
||||||
if (chosenProfile.media) {
|
|
||||||
for (let media of chosenProfile.media) {
|
|
||||||
let msgtype;
|
|
||||||
if (media.type == 'p') {
|
|
||||||
msgtype = "m.image";
|
|
||||||
} else if (media.type == 'v') {
|
|
||||||
msgtype = "m.video";
|
|
||||||
}
|
|
||||||
await client.sendMessage(roomId, {
|
|
||||||
msgtype: msgtype,
|
|
||||||
body: "Profile media",
|
|
||||||
url: media.url
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showRandomProfileToUser = async (client, roomId) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
let chosenProfile = await selectProfilesForUser(roomId);
|
|
||||||
|
|
||||||
if (!chosenProfile) {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "noprofiles"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await showProfile(client, roomId, chosenProfile);
|
|
||||||
|
|
||||||
await setUserCurrentlyViewingProfile(roomId, chosenProfile.room_id);
|
|
||||||
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "rate"]));
|
|
||||||
};
|
|
||||||
|
|
||||||
const showProfileToUser = async (client, roomId, profileId) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
let profileInfo = await getProfileInfo(profileId);
|
|
||||||
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "showalike"]));
|
|
||||||
|
|
||||||
await showProfile(client, roomId, profileInfo);
|
|
||||||
|
|
||||||
await client.sendText(roomId, i18n.t(["general", "mxid"], { mxid: profileInfo.mx_id }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const showNewLikes = async (client, roomId) => {
|
|
||||||
let likes = (await getAllLikesForUser(roomId));
|
|
||||||
for (let liked of likes) {
|
|
||||||
if (await checkForMutualLike(liked.sender, roomId)) {
|
|
||||||
await showProfileToUser(client, roomId, liked.sender);
|
|
||||||
await markLikeAsRead(liked.sender, roomId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const wait_start = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
let a = answer.split(" ");
|
|
||||||
if (a[0] !== "!start") return;
|
|
||||||
if (a[1] !== "ru" && a[1] !== "en") return;
|
|
||||||
await setUserLanguage(roomId, a[1]);
|
|
||||||
i18n.locale = a[1];
|
|
||||||
await setUserState(roomId, update ? "menu" : "location");
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "location"]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const loc = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
let number = parseInt(answer);
|
|
||||||
if (!number) {
|
|
||||||
let cities = await findCity(answer);
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "choosecity"], {
|
|
||||||
number1: cities[0].id,
|
|
||||||
name1: cities[0].name,
|
|
||||||
country1: cities[0].country,
|
|
||||||
lat1: cities[0].lat,
|
|
||||||
lng1: cities[0].lng,
|
|
||||||
|
|
||||||
number2: cities[1].id,
|
|
||||||
name2: cities[1].name,
|
|
||||||
country2: cities[1].country,
|
|
||||||
lat2: cities[1].lat,
|
|
||||||
lng2: cities[1].lng,
|
|
||||||
|
|
||||||
number3: cities[2].id,
|
|
||||||
name3: cities[2].name,
|
|
||||||
country3: cities[2].country,
|
|
||||||
lat3: cities[2].lat,
|
|
||||||
lng3: cities[2].lng,
|
|
||||||
|
|
||||||
number4: cities[3].id,
|
|
||||||
name4: cities[3].name,
|
|
||||||
country4: cities[3].country,
|
|
||||||
lat4: cities[3].lat,
|
|
||||||
lng4: cities[3].lng,
|
|
||||||
|
|
||||||
number5: cities[4].id,
|
|
||||||
name5: cities[4].name,
|
|
||||||
country5: cities[4].country,
|
|
||||||
lat5: cities[4].lat,
|
|
||||||
lng5: cities[4].lng,
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
await processRequest(client, roomId, current_action, number, update ? "menu" : "range");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const range = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
answer = parseInt(answer.split(" ")[0]);
|
|
||||||
if (!answer && answer != 0) {
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "range"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await processRequest(client, roomId, current_action, answer, update ? "menu" : "name");
|
|
||||||
}
|
|
||||||
|
|
||||||
const age = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
answer = parseInt(answer);
|
|
||||||
if (!answer) {
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "age"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (answer < 14) {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "tooyoung"]));
|
|
||||||
await client.leaveRoom(roomId);
|
|
||||||
await fullEraseUser(roomId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await processRequest(client, roomId, current_action, answer, update ? "menu" : "sex");
|
|
||||||
}
|
|
||||||
|
|
||||||
const sex = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
answer = answer.toLowerCase().trim();
|
|
||||||
if (answer.toLowerCase() != "male" && answer.toLowerCase() != "female") {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "twosexes"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await processRequest(client, roomId, current_action, answer[0], update ? "menu" : "interest");
|
|
||||||
}
|
|
||||||
|
|
||||||
const interest = async (client, roomId, current_action, answer, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
answer = answer.toLowerCase().trim();
|
|
||||||
if (answer != "male" && answer != "female" && answer != "both") {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "didntunderstand"]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await processRequest(client, roomId, current_action, answer[0], update ? "menu" : "description");
|
|
||||||
}
|
|
||||||
|
|
||||||
const pictures = async (client, roomId, current_action, event, update) => {
|
|
||||||
const i18n = new I18n({
|
|
||||||
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
|
||||||
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
|
||||||
});
|
|
||||||
|
|
||||||
let preferredLanguage = await getUserLanguage(roomId);
|
|
||||||
if (!preferredLanguage) preferredLanguage = i18n.defaultLocale;
|
|
||||||
i18n.locale = preferredLanguage;
|
|
||||||
|
|
||||||
const msgtype = event.content.msgtype;
|
|
||||||
if (event.content?.msgtype !== 'm.image' && event.content?.msgtype !== 'm.video') {
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "done"]));
|
|
||||||
await setUserState(roomId, update ? "menu" : "view_profiles");
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
} else {
|
|
||||||
let pictures_count = parseInt(await getAmountOfUserPictures(roomId));
|
|
||||||
if (pictures_count >= maxAmountOfPhotoesPerUser) {
|
|
||||||
await client.sendText(roomId, i18n.t(["errors", "toomuch"]));
|
|
||||||
await setUserState(roomId, update ? "menu" : "view_profiles");
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
} else {
|
|
||||||
let mxc = await uploadMediaFromEvent(client, event);
|
|
||||||
let type = convertMsgType(msgtype);
|
|
||||||
await appendUserPictures(roomId, mxc, type);
|
|
||||||
let pictures_count = await getAmountOfUserPictures(roomId);
|
|
||||||
if (pictures_count < maxAmountOfPhotoesPerUser) {
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "more"], { amount: String(maxAmountOfPhotoesPerUser - pictures_count) }));
|
|
||||||
} else {
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "enough"]));
|
|
||||||
await client.sendText(roomId, i18n.t(["setup", "done"]));
|
|
||||||
await setUserState(roomId, update ? "menu" : "view_profiles");
|
|
||||||
await showRandomProfileToUser(client, roomId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
processRequest,
|
|
||||||
showRandomProfileToUser,
|
|
||||||
showNewLikes,
|
|
||||||
showProfileToUser,
|
|
||||||
wait_start,
|
|
||||||
loc,
|
|
||||||
range,
|
|
||||||
age,
|
|
||||||
sex,
|
|
||||||
interest,
|
|
||||||
pictures,
|
|
||||||
showProfile
|
|
||||||
};
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
import { client } from "./index.js";
|
||||||
|
import { sequence, max_length, getCityNameByID, getCountryNameByID } from "./utils.js";
|
||||||
|
import { I18n } from "i18n-js";
|
||||||
|
import fs from "fs";
|
||||||
|
import { db } from "./db.js";
|
||||||
|
|
||||||
|
export class User {
|
||||||
|
constructor(roomId) {
|
||||||
|
this.roomId = roomId
|
||||||
|
this.i18n = new I18n({
|
||||||
|
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
||||||
|
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
||||||
|
});
|
||||||
|
this.i18n.locale = "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
async go(one, two) {
|
||||||
|
await client.sendText(this.roomId, this.i18n.t([one, two]));
|
||||||
|
await this.setState(two);
|
||||||
|
}
|
||||||
|
|
||||||
|
async exists() {
|
||||||
|
return (await db.query("SELECT EXISTS (SELECT * FROM users WHERE room_id = $1)", [this.roomId])).rows[0].exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(mxid) {
|
||||||
|
await db.query("INSERT INTO users(mx_id, room_id, current_action) VALUES ($1, $2, $3)", [mxid, this.roomId, "wait_start"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setState(state) {
|
||||||
|
await db.query("UPDATE users SET current_action = $1 WHERE room_id = $2", [state, this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(property, value) {
|
||||||
|
//${property} is passed from the code, not user input. It's safe. Maybe. I don't know ;)
|
||||||
|
await db.query(`UPDATE users SET ${property} = $1 WHERE room_id = $2`, [value, this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLanguage() {
|
||||||
|
const language = (await db.query("SELECT language FROM users WHERE room_id = $1", [this.roomId])).rows[0].language;
|
||||||
|
this.i18n.locale = language
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentAction() {
|
||||||
|
return (await db.query('SELECT current_action FROM users WHERE room_id = $1', [this.roomId])).rows[0].current_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
async process(answer) {
|
||||||
|
const current_action = await this.getCurrentAction();
|
||||||
|
|
||||||
|
let next_action = "menu";
|
||||||
|
if (sequence[current_action]) next_action = sequence[current_action]
|
||||||
|
if (max_length[current_action] < answer.length) {
|
||||||
|
await client.sendText(this.roomId, this.i18n.t(["error", "toobig"]));
|
||||||
|
await client.sendText(this.roomId, this.i18n.t(["setup", current_action]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.set(current_action, answer);
|
||||||
|
await client.sendText(this.roomId, this.i18n.t(["general", "setopt"], { opt: answer }));
|
||||||
|
|
||||||
|
await this.go(next_action == "menu" ? "general" : "setup", next_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(answer) {
|
||||||
|
const i18n = new I18n({
|
||||||
|
en: JSON.parse(fs.readFileSync("./translations/en.json")),
|
||||||
|
ru: JSON.parse(fs.readFileSync("./translations/ru.json"))
|
||||||
|
});
|
||||||
|
i18n.locale = await this.getLanguage();
|
||||||
|
|
||||||
|
//when updating a field, current_action = <action>-u.
|
||||||
|
const current_action = (await this.getCurrentAction()).split("-")[0];
|
||||||
|
|
||||||
|
if (max_length[current_action] < answer.length) {
|
||||||
|
await client.sendText(this.roomId, i18n.t(["error", "toobig"]));
|
||||||
|
await client.sendText(this.roomId, i18n.t(["setup", current_action]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.set(current_action, answer);
|
||||||
|
await this.markProfileAsUnRead();
|
||||||
|
await this.getLanguage()
|
||||||
|
await client.sendText(this.roomId, i18n.t(["general", "setopt"], { opt: answer }));
|
||||||
|
await this.go("general", "menu");
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfilePictures() {
|
||||||
|
return (await db.query("SELECT url, type FROM media WHERE owner = $1 AND purpose = 'p'", [this.roomId])).rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addProfilePicture(type, mxc) {
|
||||||
|
await db.query("INSERT INTO media (owner, type, purpose, url) VALUES ($1, $2, 'p', $3)", [this.roomId, type, mxc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfileInfo() {
|
||||||
|
let user = (await db.query("SELECT mx_id, room_id, name, age, sex, description, location FROM users WHERE room_id = $1", [this.roomId])).rows[0];
|
||||||
|
if (!user) return null;
|
||||||
|
const u = new User(user.room_id);
|
||||||
|
const media = await u.getProfilePictures();
|
||||||
|
user.media = media;
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async markProfileAsRead(whoRead) {
|
||||||
|
await db.query("INSERT INTO read_profiles(sender, recipient) VALUES ($1, $2)", [whoRead, this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async markProfileAsUnRead() {
|
||||||
|
await db.query("DELETE FROM read_profiles WHERE recipient = $1", [this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectRandomProfile() {
|
||||||
|
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`, [this.roomId])
|
||||||
|
).rows[0];
|
||||||
|
|
||||||
|
const { lat, lng } = (await db.query("SELECT lat, lng FROM cities WHERE ID = $1", [mycity])).rows[0];
|
||||||
|
//TODO: figure out how to move it to PG function
|
||||||
|
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')
|
||||||
|
AND NOT (room_id = ANY(ARRAY(SELECT recipient FROM read_profiles)))
|
||||||
|
ORDER BY RANDOM()
|
||||||
|
LIMIT 1`, [myage, this.roomId, myinterest, mysex, myrange, lat, lng])
|
||||||
|
).rows[0];
|
||||||
|
|
||||||
|
if (!user) return null;
|
||||||
|
const u = new User(user.room_id);
|
||||||
|
const media = await u.getProfilePictures();
|
||||||
|
u.markProfileAsRead(this.roomId);
|
||||||
|
|
||||||
|
user.media = media;
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async showProfile(profile) {
|
||||||
|
if (!profile) {
|
||||||
|
await client.sendText(this.roomId, this.i18n.t(["errors", "noprofiles"]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.country = await getCountryNameByID(profile.location);
|
||||||
|
profile.city = await getCityNameByID(profile.location);
|
||||||
|
|
||||||
|
let message =
|
||||||
|
`${profile.country}, ${profile.city}.
|
||||||
|
${profile.name}, ${profile.sex == 'm' ? 'male' : 'female'}, ${profile.age}.
|
||||||
|
${profile.description}`;
|
||||||
|
|
||||||
|
await client.sendText(this.roomId, message);
|
||||||
|
|
||||||
|
if (profile.media) {
|
||||||
|
for (let media of profile.media) {
|
||||||
|
let msgtype;
|
||||||
|
if (media.type == 'p') {
|
||||||
|
msgtype = "m.image";
|
||||||
|
} else if (media.type == 'v') {
|
||||||
|
msgtype = "m.video";
|
||||||
|
}
|
||||||
|
await client.sendMessage(this.roomId, {
|
||||||
|
msgtype: msgtype,
|
||||||
|
body: "Profile media",
|
||||||
|
url: media.url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async showRandomProfile() {
|
||||||
|
let profile = await this.selectRandomProfile();
|
||||||
|
await this.showProfile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentlyViewingProfile() {
|
||||||
|
return (await db.query("SELECT currently_viewing FROM users WHERE room_id = $1", [this.roomId])).rows[0].currently_viewing;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addLikeTo(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", [this.roomId, like]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkForMutualLikeWith(person) {
|
||||||
|
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`, [this.roomId, person])).rows[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLikes() {
|
||||||
|
return (await db.query("SELECT sender FROM likes WHERE recipient = $1 AND read = FALSE", [this.roomId])).rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async markLikeAsRead(sender) {
|
||||||
|
await db.query("UPDATE likes SET read = TRUE WHERE sender = $1 AND recipient = $2", [sender, this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async showNewLikes() {
|
||||||
|
let likes = (await this.getLikes());
|
||||||
|
for (let liked of likes) {
|
||||||
|
if (await this.checkForMutualLikeWith(liked.sender)) {
|
||||||
|
await this.showProfile(liked.sender);
|
||||||
|
await this.markLikeAsRead(liked.sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async markMessageAsRead(sender) {
|
||||||
|
return (await db.query("UPDATE messages SET read = TRUE WHERE sender = $1 AND recipient = $2", [sender, this.roomId]));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUnreadMessages() {
|
||||||
|
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", [this.roomId])).rows
|
||||||
|
}
|
||||||
|
|
||||||
|
async erasePfp() {
|
||||||
|
await db.query("DELETE FROM media WHERE owner = $1 AND purpose = 'p'", [this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async eraseMessages() {
|
||||||
|
await db.query("DELETE FROM messages WHERE sender = $1 OR recipient = $1", [this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async eraseMedia() {
|
||||||
|
await db.query("DELETE FROM media WHERE owner = $1", [this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async eraseLikes() {
|
||||||
|
await db.query("DELETE FROM likes WHERE sender = $1 OR recipient = $1", [this.roomId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fullErase() {
|
||||||
|
await this.eraseMessages()
|
||||||
|
await this.eraseMedia()
|
||||||
|
await this.eraseLikes()
|
||||||
|
}
|
||||||
|
}
|
69
src/utils.js
69
src/utils.js
|
@ -1,12 +1,6 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import {
|
import { MessageEvent } from "matrix-bot-sdk";
|
||||||
EncryptionAlgorithm,
|
import { db } from "./db.js"
|
||||||
MatrixClient,
|
|
||||||
MessageEvent,
|
|
||||||
RustSdkCryptoStorageProvider,
|
|
||||||
SimpleFsStorageProvider,
|
|
||||||
} from "matrix-bot-sdk";
|
|
||||||
|
|
||||||
const configPath = './config.json';
|
const configPath = './config.json';
|
||||||
|
|
||||||
const logError = (message) => {
|
const logError = (message) => {
|
||||||
|
@ -47,6 +41,10 @@ const uploadMediaFromEvent = async (client, event) => {
|
||||||
return mxc;
|
return mxc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 convertMsgType = (msgtype) => {
|
const convertMsgType = (msgtype) => {
|
||||||
switch (msgtype) {
|
switch (msgtype) {
|
||||||
case "m.image":
|
case "m.image":
|
||||||
|
@ -60,4 +58,57 @@ const convertMsgType = (msgtype) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { readConfig, logError, logInfo, uploadMediaFromEvent, convertMsgType };
|
|
||||||
|
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 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 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 sequence = {
|
||||||
|
"wait_start": "location",
|
||||||
|
"location": "range",
|
||||||
|
"range": "name",
|
||||||
|
"name": "age",
|
||||||
|
"age": "sex",
|
||||||
|
"sex": "interest",
|
||||||
|
"interest": "description",
|
||||||
|
"description": "pictures",
|
||||||
|
"pictures": "view_profiles"
|
||||||
|
};
|
||||||
|
|
||||||
|
const max_length = {
|
||||||
|
"name": 32,
|
||||||
|
"description": 512,
|
||||||
|
"message": 128
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
readConfig,
|
||||||
|
logError,
|
||||||
|
logInfo,
|
||||||
|
uploadMediaFromEvent,
|
||||||
|
convertMsgType,
|
||||||
|
sequence,
|
||||||
|
max_length,
|
||||||
|
getCityNameByID,
|
||||||
|
getCountryNameByID,
|
||||||
|
findCity,
|
||||||
|
insertMessageIntoDB,
|
||||||
|
uploadMediaAsMessage
|
||||||
|
};
|
Loading…
Reference in New Issue