implemented messages
This commit is contained in:
		| @@ -5,7 +5,12 @@ | ||||
|         "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!", | ||||
|         "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": { | ||||
|         "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.", | ||||
|         "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! ;)", | ||||
|         "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!" | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -31,5 +31,8 @@ CREATE TABLE IF NOT EXISTS messages ( | ||||
|     sender 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 | ||||
|     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); | ||||
|   | ||||
							
								
								
									
										47
									
								
								src/db.js
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								src/db.js
									
									
									
									
									
								
							| @@ -1,5 +1,6 @@ | ||||
| import pg from 'pg'; | ||||
| import fs from 'fs'; | ||||
| import { convertMsgType } from './utils.js'; | ||||
|  | ||||
| const { Client } = pg; | ||||
|  | ||||
| @@ -56,24 +57,24 @@ const selectProfilesForUser = async (roomId) => { | ||||
|     //Selecting profiles other than user's and with difference in age +-2. | ||||
|     let user; | ||||
|     if (myInterest === 'b') // both, no matter what sex | ||||
|         user = (await db.query(`SELECT  | ||||
|                                     room_id, name, age, sex, description, country, city FROM users  | ||||
|                                 WHERE  | ||||
|                                     age::numeric <@ ANY(ARRAY[numrange($1 - 2, $1 + 2)])  | ||||
|         user = (await db.query(`SELECT | ||||
|                                     room_id, name, age, sex, description, country, city FROM users | ||||
|                                 WHERE | ||||
|                                     age::numeric <@ ANY(ARRAY[numrange($1 - 2, $1 + 2)]) | ||||
|                                 AND room_id != $2 | ||||
|                                 AND (interest = $3 OR interest = 'b') | ||||
|                                 ORDER BY RANDOM()  | ||||
|                                 ORDER BY RANDOM() | ||||
|                                 LIMIT 1`, [userAge, roomId, mySex]) | ||||
|         ).rows[0]; | ||||
|     else { | ||||
|         user = (await db.query(`SELECT  | ||||
|                                     room_id, name, age, sex, description, country, city FROM users  | ||||
|                                 WHERE  | ||||
|                                     age::numeric <@ ANY(ARRAY[numrange($1 - 2, $1 + 2)])  | ||||
|                                 AND room_id != $2  | ||||
|                                 AND sex = $3  | ||||
|                                     room_id, name, age, sex, description, country, city FROM users | ||||
|                                 WHERE | ||||
|                                     age::numeric <@ ANY(ARRAY[numrange($1 - 2, $1 + 2)]) | ||||
|                                 AND room_id != $2 | ||||
|                                 AND sex = $3 | ||||
|                                 AND (interest = $4 OR interest = 'b') | ||||
|                                 ORDER BY RANDOM()  | ||||
|                                 ORDER BY RANDOM() | ||||
|                                 LIMIT 1`, [userAge, roomId, myInterest, mySex]) | ||||
|         ).rows[0]; | ||||
|     } | ||||
| @@ -137,6 +138,24 @@ const getAllLikesForUser = async (roomId) => { | ||||
| 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])); | ||||
| } | ||||
|  | ||||
| export { | ||||
|     eraseUser, | ||||
|     appendUserPictures, | ||||
| @@ -153,5 +172,9 @@ export { | ||||
|     getAllLikesForUser, | ||||
|     markLikeAsRead, | ||||
|     eraseUserLikes, | ||||
|     eraseUserMedia | ||||
|     eraseUserMedia, | ||||
|     uploadMediaAsMessage, | ||||
|     insertMessageIntoDB, | ||||
|     getUnreadMessages, | ||||
|     markMessageAsRead | ||||
| }; | ||||
							
								
								
									
										81
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								src/index.js
									
									
									
									
									
								
							| @@ -9,10 +9,12 @@ import { | ||||
| import { StoreType } from "@matrix-org/matrix-sdk-crypto-nodejs"; | ||||
|  | ||||
| import { | ||||
|     convertMsgType, | ||||
|     logError, | ||||
|     logInfo, | ||||
|     readConfig, | ||||
|     readMessages | ||||
|     readMessages, | ||||
|     uploadMediaFromEvent | ||||
| } from './utils.js'; | ||||
|  | ||||
| import { | ||||
| @@ -24,8 +26,12 @@ import { | ||||
|     eraseUserMedia, | ||||
|     getAmountOfUserPictures, | ||||
|     getCurrentUserAction, | ||||
|     getUnreadMessages, | ||||
|     getUserCurrentlyViewingProfile, | ||||
|     setUserState | ||||
|     insertMessageIntoDB, | ||||
|     markMessageAsRead, | ||||
|     setUserState, | ||||
|     uploadMediaAsMessage | ||||
| } from './db.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 answer = event.content.body; | ||||
|         let msgtype = event.content.msgtype | ||||
|  | ||||
|         switch (current_action) { | ||||
|             case "wait_start": | ||||
|                 if (answer !== "!start") return; | ||||
|                 await setUserState(roomId, "country"); | ||||
|                 await client.sendText(roomId, messages.setup.country); | ||||
|  | ||||
|                 break; | ||||
|             case "country": | ||||
|                 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 showRandomProfileToUser(client, roomId); | ||||
|                     } else { | ||||
|                         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); | ||||
|                         let type; | ||||
|                         if (event.content.msgtype === "m.image") { | ||||
|                             type = 'p'; | ||||
|                         } else if (event.content.msgtype === "m.video") { | ||||
|                             type = 'v'; | ||||
|                         } | ||||
|                         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) { | ||||
| @@ -148,17 +146,35 @@ client.on("room.message", async (roomId, event) => { | ||||
|                         await client.sendText(currently_viewing, messages.general.newlikes); | ||||
|                     } | ||||
|                 } 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') { | ||||
|                     await client.sendText(roomId, messages.general.menu); | ||||
|                     await setUserState(roomId, 'menu') | ||||
|                     return | ||||
|                     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, 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; | ||||
|             case 'menu': | ||||
|                 switch (answer) { | ||||
| @@ -171,11 +187,38 @@ client.on("room.message", async (roomId, event) => { | ||||
|                         await client.sendText(roomId, messages.general.menu); | ||||
|                         break; | ||||
|                     case '3': | ||||
|                         await setUserState(roomId, 'send_message'); | ||||
|                         await client.sendText(roomId, messages.errors.notimplemented); | ||||
|                         let unreadMessages = await getUnreadMessages(roomId); | ||||
|                         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; | ||||
|                     default: | ||||
|                         await client.sendText(roomId, messages.errors.didntunderstand); | ||||
|                         await client.sendText(roomId, messages.general.menu); | ||||
|                         break; | ||||
|                 } | ||||
|                 break; | ||||
|   | ||||
							
								
								
									
										30
									
								
								src/utils.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/utils.js
									
									
									
									
									
								
							| @@ -1,4 +1,11 @@ | ||||
| import fs from 'fs'; | ||||
| import { | ||||
|     EncryptionAlgorithm, | ||||
|     MatrixClient, | ||||
|     MessageEvent, | ||||
|     RustSdkCryptoStorageProvider, | ||||
|     SimpleFsStorageProvider, | ||||
| } from "matrix-bot-sdk"; | ||||
|  | ||||
| const configPath = './config.json'; | ||||
| const messagesPath = './messages.json'; | ||||
| @@ -41,4 +48,25 @@ const readMessages = () => { | ||||
|     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 }; | ||||
		Reference in New Issue
	
	Block a user