implemented messages

This commit is contained in:
leca 2024-08-08 14:42:20 +03:00
parent a691dec2e8
commit 10994b6612
5 changed files with 140 additions and 36 deletions

View File

@ -5,7 +5,12 @@
"menu": "Pick an action:\n1) Start watching profiles\n2) Check for mutual likes\n3) Check for messages", "menu": "Pick an action:\n1) Start watching profiles\n2) Check for mutual likes\n3) Check for messages",
"newlikes": "You have new mutual like(s)! Go into menu (🏠️) to see!", "newlikes": "You have new mutual like(s)! Go into menu (🏠️) to see!",
"showalike": "This person and you mutually liked each other!", "showalike": "This person and you mutually liked each other!",
"mxid": "Go drop them a line! Their MXID is: " "mxid": "Go drop them a line! Their MXID is: ",
"message": "Write one message to this person or upload one picture/video to send them!",
"newmessage": "You've got new message(s)! Go to a menu (🏠️) to see!",
"showmessage": " sent you this: ",
"nonewmessages": "You have no new messages!",
"messagesent": "You message was sent!"
}, },
"setup": { "setup": {
"country": "Write a name of country you are living in. Prefer local language. For example, 'Россия', 'United States' or 'Україна'.", "country": "Write a name of country you are living in. Prefer local language. For example, 'Россия', 'United States' or 'Україна'.",
@ -28,6 +33,8 @@
"twosexes": "There are only two sexes! Please, choose your biological one.", "twosexes": "There are only two sexes! Please, choose your biological one.",
"didntunderstand": "I cannot understand your answer. Please, read my question again and answer!", "didntunderstand": "I cannot understand your answer. Please, read my question again and answer!",
"notimplemented": "This feature is not yet implemented! Please, keep track of my updates at https://git.foxarmy.org/leca/heart2heart. Bother your admins to update, if released! ;)", "notimplemented": "This feature is not yet implemented! Please, keep track of my updates at https://git.foxarmy.org/leca/heart2heart. Bother your admins to update, if released! ;)",
"noprofiles": "There are no profiles left for you! I'm sorry. Please, come back later!" "noprofiles": "There are no profiles left for you! I'm sorry. Please, come back later!",
"alreadymessaged": "You have already messaged that person. Your message was not sent!"
} }
} }

View File

@ -31,5 +31,8 @@ CREATE TABLE IF NOT EXISTS messages (
sender VARCHAR(64), -- link to room_id sender VARCHAR(64), -- link to room_id
recipient VARCHAR(64), -- link to room_id recipient VARCHAR(64), -- link to room_id
type CHAR, -- 't' for text, 'p' for picture and 'v' for video type CHAR, -- 't' for text, 'p' for picture and 'v' for video
content VARCHAR(128) -- will contain a url if media and text if the message is just a text content VARCHAR(128), -- will contain a url if media and text if the message is just a text
read BOOLEAN DEFAULT FALSE
); );
CREATE UNIQUE INDEX IF NOT EXISTS unique_messages ON messages(sender, recipient);

View File

@ -1,5 +1,6 @@
import pg from 'pg'; import pg from 'pg';
import fs from 'fs'; import fs from 'fs';
import { convertMsgType } from './utils.js';
const { Client } = pg; const { Client } = pg;
@ -137,6 +138,24 @@ const getAllLikesForUser = async (roomId) => {
const markLikeAsRead = async (roomId, recipient,) => { const markLikeAsRead = async (roomId, recipient,) => {
await db.query("UPDATE likes SET read = TRUE WHERE sender = $1 AND recipient = $2", [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]));
}
export { export {
eraseUser, eraseUser,
appendUserPictures, appendUserPictures,
@ -153,5 +172,9 @@ export {
getAllLikesForUser, getAllLikesForUser,
markLikeAsRead, markLikeAsRead,
eraseUserLikes, eraseUserLikes,
eraseUserMedia eraseUserMedia,
uploadMediaAsMessage,
insertMessageIntoDB,
getUnreadMessages,
markMessageAsRead
}; };

View File

@ -9,10 +9,12 @@ import {
import { StoreType } from "@matrix-org/matrix-sdk-crypto-nodejs"; import { StoreType } from "@matrix-org/matrix-sdk-crypto-nodejs";
import { import {
convertMsgType,
logError, logError,
logInfo, logInfo,
readConfig, readConfig,
readMessages readMessages,
uploadMediaFromEvent
} from './utils.js'; } from './utils.js';
import { import {
@ -24,8 +26,12 @@ import {
eraseUserMedia, eraseUserMedia,
getAmountOfUserPictures, getAmountOfUserPictures,
getCurrentUserAction, getCurrentUserAction,
getUnreadMessages,
getUserCurrentlyViewingProfile, getUserCurrentlyViewingProfile,
setUserState insertMessageIntoDB,
markMessageAsRead,
setUserState,
uploadMediaAsMessage
} from './db.js'; } from './db.js';
import { processRequest, showRandomProfileToUser, showNewLikes } from "./interactions.js"; import { processRequest, showRandomProfileToUser, showNewLikes } from "./interactions.js";
@ -52,13 +58,13 @@ client.on("room.message", async (roomId, event) => {
let current_action = await getCurrentUserAction(roomId); let current_action = await getCurrentUserAction(roomId);
let answer = event.content.body; let answer = event.content.body;
let msgtype = event.content.msgtype
switch (current_action) { switch (current_action) {
case "wait_start": case "wait_start":
if (answer !== "!start") return; if (answer !== "!start") return;
await setUserState(roomId, "country"); await setUserState(roomId, "country");
await client.sendText(roomId, messages.setup.country); await client.sendText(roomId, messages.setup.country);
break; break;
case "country": case "country":
await processRequest(client, roomId, current_action, answer, 'city'); await processRequest(client, roomId, current_action, answer, 'city');
@ -115,16 +121,8 @@ client.on("room.message", async (roomId, event) => {
await setUserState(roomId, 'view_profiles'); await setUserState(roomId, 'view_profiles');
await showRandomProfileToUser(client, roomId); await showRandomProfileToUser(client, roomId);
} else { } else {
const message = new MessageEvent(event); let mxc = await uploadMediaFromEvent(client, event);
const fileEvent = new MessageEvent(message.raw); let type = convertMsgType(msgtype);
const decrypted = await client.crypto.decryptMedia(fileEvent.content.file);
const mxc = await client.uploadContent(decrypted);
let type;
if (event.content.msgtype === "m.image") {
type = 'p';
} else if (event.content.msgtype === "m.video") {
type = 'v';
}
await appendUserPictures(roomId, mxc, type); await appendUserPictures(roomId, mxc, type);
let pictures_count = await getAmountOfUserPictures(roomId); let pictures_count = await getAmountOfUserPictures(roomId);
if (pictures_count < maxAmountOfPhotoesPerUser) { if (pictures_count < maxAmountOfPhotoesPerUser) {
@ -148,17 +146,35 @@ client.on("room.message", async (roomId, event) => {
await client.sendText(currently_viewing, messages.general.newlikes); await client.sendText(currently_viewing, messages.general.newlikes);
} }
} else if (answer == '💌' || answer == '3') { } else if (answer == '💌' || answer == '3') {
await client.sendText(roomId, messages.errors.notimplemented); await setUserState(roomId, 'send_message');
await client.sendText(roomId, messages.general.message);
return;
} else if (answer == '🏠️' || answer == '4') { } else if (answer == '🏠️' || answer == '4') {
await client.sendText(roomId, messages.general.menu); await client.sendText(roomId, messages.general.menu);
await setUserState(roomId, 'menu') await setUserState(roomId, 'menu');
return return;
} }
await showRandomProfileToUser(client, roomId); await showRandomProfileToUser(client, roomId);
break; break;
case 'send_message': 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, messages.general.newmessage);
await client.sendText(roomId, messages.general.messagesent);
} else {
await client.sendText(roomId, messages.errors.alreadymessaged);
}
await setUserState(roomId, 'view_profiles');
await showRandomProfileToUser(client, roomId);
break; break;
case 'menu': case 'menu':
switch (answer) { switch (answer) {
@ -171,11 +187,38 @@ client.on("room.message", async (roomId, event) => {
await client.sendText(roomId, messages.general.menu); await client.sendText(roomId, messages.general.menu);
break; break;
case '3': case '3':
await setUserState(roomId, 'send_message'); let unreadMessages = await getUnreadMessages(roomId);
await client.sendText(roomId, messages.errors.notimplemented); if (!unreadMessages || unreadMessages.length == 0) {
await client.sendText(roomId, messages.general.nonewmessages);
return;
}
await client.sendText(roomId, "Messages:");
for (let message of unreadMessages) {
await client.sendText(roomId, message.mx_id + messages.general.showmessage);
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, messages.general.menu);
break; break;
default: default:
await client.sendText(roomId, messages.errors.didntunderstand); await client.sendText(roomId, messages.errors.didntunderstand);
await client.sendText(roomId, messages.general.menu);
break; break;
} }
break; break;

View File

@ -1,4 +1,11 @@
import fs from 'fs'; import fs from 'fs';
import {
EncryptionAlgorithm,
MatrixClient,
MessageEvent,
RustSdkCryptoStorageProvider,
SimpleFsStorageProvider,
} from "matrix-bot-sdk";
const configPath = './config.json'; const configPath = './config.json';
const messagesPath = './messages.json'; const messagesPath = './messages.json';
@ -41,4 +48,25 @@ const readMessages = () => {
return JSON.parse(fs.readFileSync(messagesPath)); return JSON.parse(fs.readFileSync(messagesPath));
}; };
export {readMessages, readConfig, logError, logInfo}; const uploadMediaFromEvent = async (client, event) => {
const message = new MessageEvent(event);
const fileEvent = new MessageEvent(message.raw);
const decrypted = await client.crypto.decryptMedia(fileEvent.content.file);
const mxc = await client.uploadContent(decrypted);
return mxc;
};
const convertMsgType = (msgtype) => {
switch (msgtype) {
case "m.image":
return "p";
case "m.video":
return "v";
case "m.text":
return "t";
default:
return msgtype;
}
};
export { readMessages, readConfig, logError, logInfo, uploadMediaFromEvent, convertMsgType };