From 6c39838a61fd70f06b5dbe509f50180bdb97bbae Mon Sep 17 00:00:00 2001 From: Itamar Shubin Date: Mon, 18 Mar 2024 10:09:14 +0200 Subject: [PATCH 1/3] fix crash if special message is not set --- src/constants/special-response.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/constants/special-response.ts b/src/constants/special-response.ts index 491f59e..f208461 100644 --- a/src/constants/special-response.ts +++ b/src/constants/special-response.ts @@ -1,18 +1,14 @@ import fs from "fs"; import { Client } from "whatsapp-web.js"; -let specialMessages:any; - fs.readFile( - "special-messages.json", - "utf-8", - (err, data) => { - if (err) return null; - - specialMessages= JSON.parse(data); - } -); +let specialMessages: any; +fs.readFile("special-messages.json", "utf-8", (err, data) => { + if (err) return null; + specialMessages = JSON.parse(data); +}); export const sendSpecialMessages = (from: string, client: Client) => { - if (specialMessages[from]) client.sendMessage(from, specialMessages[from]); + if (specialMessages && specialMessages[from]) + client.sendMessage(from, specialMessages[from]); }; From 85af38a05e708393a3615a01edce78b49f4dd54a Mon Sep 17 00:00:00 2001 From: Itamar Shubin Date: Mon, 18 Mar 2024 15:54:57 +0200 Subject: [PATCH 2/3] add option to subscribe and unsubscribe --- src/constants/help-message.ts | 6 +- src/constants/subscription.ts | 173 +++++++++++++++++++++++++++++++++ src/firebase/shabbas-manage.ts | 9 +- src/message-handler.ts | 50 ++++++++-- 4 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 src/constants/subscription.ts diff --git a/src/constants/help-message.ts b/src/constants/help-message.ts index 2063e18..a7e912d 100644 --- a/src/constants/help-message.ts +++ b/src/constants/help-message.ts @@ -1,4 +1,4 @@ -import { BOT_MANAGER } from "./bot-manager" +import { BOT_MANAGER } from "./bot-manager"; export const HELP_MESSAGE: string = ` היי, זה בוט השבתות ויו"ט של דרך חיים, הוא לא יודע לעשות הרבה. זה מה שאפשר לעשות בנתיים: @@ -9,5 +9,7 @@ export const HELP_MESSAGE: string = ` מי מעניין - אפשרות לסינון מחזורים שמעניינים אותך על הפקודה 'מי מגיע' כולם מעניינים אותי - ביטול הסינונים על הפקודה 'מי מגיע' בעתיד יתווספו פעולות נוספות 😁 +עדכן אותי - אפשרות לקבלת עדכונים על משתמש +אל תעדכן - להפסיק לקבל עדכונים על משתמש אם ישנה בעייה צור קשר עם ${BOT_MANAGER.name} (${BOT_MANAGER.phoneNumber}) -` as const; \ No newline at end of file +` as const; diff --git a/src/constants/subscription.ts b/src/constants/subscription.ts new file mode 100644 index 0000000..d14abdc --- /dev/null +++ b/src/constants/subscription.ts @@ -0,0 +1,173 @@ +import { + arrayUnion, + DocumentData, + getDocFromServer, + QueryDocumentSnapshot, + arrayRemove, + DocumentSnapshot, + updateDoc, + collection, + getDocs, + query, + DocumentReference, +} from "@firebase/firestore"; + +import { Client, Message } from "whatsapp-web.js"; +import { fireStore, getUserRef } from "../firebase/shabbas-manage"; +import { client } from "../app"; + +type User = { phone: string; name: string }; +export const updateRelevantUsers = async ( + userRef: QueryDocumentSnapshot, + client: Client, + coming: boolean +): Promise => { + const subscribedUsers: DocumentReference[] = + userRef.get("subscribedUsers"); + + subscribedUsers?.forEach(async (user) => { + const userData = (await getDocFromServer(user)).data(); + userData && + client.sendMessage( + userData.phone, + `${userRef.get("name")} ${coming ? "מגיע" : "לא מגיע"} לשבת` + ); + }); +}; + +let users: QueryDocumentSnapshot[] = []; +export const sessionedAddSubscribersAlert: Record< + string, + { matches: QueryDocumentSnapshot[] } +> = {}; +export const sessionedRemoveSubscribersAlert: Record< + string, + { followers: DocumentSnapshot[] } +> = {}; + +//refetch users twice a day and save it in the cache. +//you probably should use some library to fetch user by name. +//but I didn't want to get all the users every time +setInterval(() => { + users = []; +}, 43200000); + +export const removeAlertSubscription = async (msg: Message) => { + if (!users.length) { + const docs = await getDocs(query(collection(fireStore, "/users"))); + docs.forEach((doc) => { + users.push(doc); + }); + } + if (!sessionedRemoveSubscribersAlert[msg.from]) { + const userRef = await getUserRef(msg); + + const followersRef: DocumentReference[] = + userRef.data().subscribedUsers; + const followers = await Promise.all( + followersRef.map((followerRef) => getDocFromServer(followerRef)) + ); + + let response = "אלה האנשים שאתה תקבל עליהם עדכונים: \n"; + + followers.forEach((follower, index) => { + response += index + 1 + ". " + String(follower.data()?.name) + "\n"; + }); + + client.sendMessage( + msg.from, + response + " שלח את המספר של מי שאתה רוצה להסיר" + ); + sessionedRemoveSubscribersAlert[msg.from] = { followers }; + return; + } + + if (msg.body === "בטל") { + return delete sessionedRemoveSubscribersAlert[msg.from]; + } + + const userRef = await getUserRef(msg); + + const userToRemove = + sessionedRemoveSubscribersAlert[msg.from].followers[Number(msg.body) - 1]; + if (!userToRemove) { + return client.sendMessage( + msg.from, + "הזן מספר תקין או כתוב 'בטל' בשביל להפסיק את הפעולה" + ); + } + + await updateDoc(userRef.ref, { + subscribedUsers: arrayRemove(userToRemove.ref), + }); + client.sendMessage( + msg.from, + `הסרנו את ${userToRemove.data()?.name}, לא תקבל יותר עדכונים עליו` + ); + delete sessionedRemoveSubscribersAlert[msg.from]; +}; + +export const createAlertSubscription = async (msg: Message) => { + if (!users.length) { + const docs = await getDocs(query(collection(fireStore, "/users"))); + docs.forEach((doc) => { + users.push(doc); + }); + } + if (!sessionedAddSubscribersAlert[msg.from]) { + client.sendMessage( + msg.from, + "כתוב שם (מלא או חלקי) של מישהו שתרצה לקבל עדכון כשהוא מגיע" + ); + sessionedAddSubscribersAlert[msg.from] = { matches: [] }; + return; + } + if (msg.body === "בטל") { + return delete sessionedAddSubscribersAlert[msg.from]; + } + + if (!sessionedAddSubscribersAlert[msg.from].matches.length) { + const matches = users.filter((user) => + user.data().name?.includes(msg.body) + ); + if (!matches) { + return client.sendMessage( + msg.from, + "לא נמצא משתמש עם שם כזה, הזן שם אחר או 'בטל' כדי להפסיק את הפעולה" + ); + } + let response = ""; + matches.forEach((match, index) => { + response += String( + index + + 1 + + ". " + + match.data().name + + ", מחזור: " + + match.data().year + + "\n" + ); + }); + + client.sendMessage(msg.from, response); + sessionedAddSubscribersAlert[msg.from].matches = matches; + return; + } + + const userRef = await getUserRef(msg); + + const userToAdd = + sessionedAddSubscribersAlert[msg.from].matches[Number(msg.body) - 1]; + if (!userToAdd) { + return client.sendMessage( + msg.from, + "הזן מספר תקין או כתוב 'בטל' בשביל להפסיק את הפעולה" + ); + } + await updateDoc(userRef.ref, { subscribedUsers: arrayUnion(userToAdd.ref) }); + client.sendMessage( + msg.from, + `תקבל הודעה כש${userToAdd.data().name} יעדכן על מצב ההגעה שלו` + ); + delete sessionedAddSubscribersAlert[msg.from]; +}; diff --git a/src/firebase/shabbas-manage.ts b/src/firebase/shabbas-manage.ts index 9c7ad6c..6afb951 100644 --- a/src/firebase/shabbas-manage.ts +++ b/src/firebase/shabbas-manage.ts @@ -18,8 +18,9 @@ import { import { Message } from "whatsapp-web.js"; import { client } from "../app"; import { ALL_YESHIVA_YEARS } from "../constants/yeshiva-years"; +import { updateRelevantUsers } from "../constants/subscription"; -const fireStore = getFirestore(); +export const fireStore = getFirestore(); const getShabbasDoc = async (): Promise< QueryDocumentSnapshot @@ -35,7 +36,7 @@ const getShabbasDoc = async (): Promise< return shabbasDocs.docs[0]; }; -const getUserRef = async (msg: Message) => { +export const getUserRef = async (msg: Message) => { const userRef = ( await getDocs( query(collection(fireStore, "/users"), where("phone", "==", msg.from)) @@ -58,6 +59,7 @@ export const addUser = async (msg: Message) => { await updateDoc(shabbas.ref, { participants: arrayUnion(userRef.ref) }); await client.sendMessage(msg.from, "נהדר! נשמח לראותך."); } + await updateRelevantUsers(userRef, client, true); }; export const addAlcoholic = async (msg: Message) => { @@ -151,6 +153,7 @@ export const removeUser = async (msg: Message) => { await updateDoc(shabbas.ref, { participants: arrayRemove(userRef.ref) }); } await client.sendMessage(msg.from, "טוב נו... פעם הבאה."); + await updateRelevantUsers(userRef, client, false); }; export const getParticipants = async (msg: Message) => { @@ -326,3 +329,5 @@ export const resetSubscribedYears = async ( msg.from ); }; + +const alertSubscribers = async (msg: Message) => {}; diff --git a/src/message-handler.ts b/src/message-handler.ts index dbdd346..5ef6b95 100644 --- a/src/message-handler.ts +++ b/src/message-handler.ts @@ -18,10 +18,50 @@ import { } from "./firebase/shabbas-manage"; import { HELP_MESSAGE } from "./constants/help-message"; import { sendSpecialMessages } from "./constants/special-response"; +import { + createAlertSubscription, + removeAlertSubscription, + sessionedAddSubscribersAlert, + sessionedRemoveSubscribersAlert, +} from "./constants/subscription"; export const messageHandler = async (msg: Message) => { sendSpecialMessages(msg.from, client); + //prevent interrupt in middle action + if (sessionedSubscribers[msg.from]) { + await addSubscribedYears(msg); + return; + } + + if (sessionedAddSubscribersAlert[msg.from]) { + await createAlertSubscription(msg); + return; + } + + if (sessionedRemoveSubscribersAlert[msg.from]) { + await removeAlertSubscription(msg); + return; + } + + if (msg.body.includes("מי מעניין")) { + await addSubscribedYears(msg); + return; + } + + if ( + msg.body.includes("עדכן אותי") || + sessionedAddSubscribersAlert[msg.from] + ) { + await createAlertSubscription(msg); + return; + } + + if (msg.body.includes("אל תעדכן")) { + await removeAlertSubscription(msg); + return; + } + if (msg.body.startsWith("!new") && (await isAdmin(msg))) { await addShabbas(msg); return; @@ -38,10 +78,6 @@ export const messageHandler = async (msg: Message) => { } if (msg.body.includes("מי מגיע")) { - await client.sendMessage( - msg.from, - "*פיצ'ר חדש!!!* מעכשיו תוכל לערוך אילו מחזורים מעניינים אותך על ידי הפקודה מי מעניין " - ); await getParticipants(msg); return; } @@ -51,10 +87,6 @@ export const messageHandler = async (msg: Message) => { return; } - if (msg.body.includes("מי מעניין") || sessionedSubscribers[msg.from]) { - await addSubscribedYears(msg); - return; - } if (msg.body.includes("כולם מעניינים אותי")) { await resetSubscribedYears(msg); await client.sendMessage(msg.from, " די נו איזה חמוד אתה 🤓"); @@ -63,7 +95,7 @@ export const messageHandler = async (msg: Message) => { if (!(await auth(msg))) { return; } - + if (msg.body.includes("מי מביא אלכוהול")) { await getAlcoholics(msg); return; From 5f05e1a557266f0e88c5488e8f219914a5cf033d Mon Sep 17 00:00:00 2001 From: Itamar Shubin Date: Mon, 18 Mar 2024 15:56:27 +0200 Subject: [PATCH 3/3] type --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 194bf85..5dbea89 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # whatsapp-shabbat -this code looks like shit, so feal free to pr me +this code looks like shit, so feel free to pr me how to use: @@ -8,7 +8,5 @@ how to use: 2. put it in the app. 3. the bot is running - - my setup is ec2 in aws. -I didn't use Docker, so if you want your project to run on linux (at least ubuntu) you need to install all the packages in the Docker file. \ No newline at end of file +I didn't use Docker, so if you want your project to run on linux (at least ubuntu) you need to install all the packages in the Docker file.