Skip to content

Commit 00873f3

Browse files
committed
daily request count
1 parent f758d58 commit 00873f3

File tree

5 files changed

+132
-25
lines changed

5 files changed

+132
-25
lines changed

ChangeLogs.md

+11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
**Latests are on top**
44

5+
## 17) 30th November, 2024
6+
- Add Active users field
7+
- Forward messages to the active users only and give proper report
8+
- `/login` command to login as an admin
9+
- Keep log of daily request count in `db.analytics`
10+
11+
12+
## 16) 29th November, 2024
13+
14+
- Better Search for the Surahs
15+
516
## 15) 20th October, 2024
617

718
- Bot can now send the audio of a Full Surah.

bot/bot.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ def runBot(token):
4545

4646
# Send a message to the admin when the bot starts
4747
loop = asyncio.get_event_loop()
48-
49-
msg = f"<b>Bot started at {datetime.now(timezone.utc).strftime('%d %B %Y, %H:%M:%S %A UTC')} 🚀</b>"
48+
49+
currentTime = datetime.now(timezone.utc).strftime('%d %B %Y, %H:%M:%S %A UTC')
50+
msg = f"<b>Bot started at {currentTime} 🚀</b>"
5051
print(msg[3:-4])
5152
loop.run_until_complete(app.bot.sendMessage(5596148289, msg))
5253

bot/handlers/command/adminCommand.py

+83-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import os
12
import html
3+
import asyncio
4+
import hashlib
25

36

7+
from datetime import datetime, timezone
8+
49
from telegram.ext import CommandHandler, filters
510
from telegram import (
611
Bot,
@@ -70,41 +75,105 @@ async def forwardMessage(u: Update, c):
7075

7176
return
7277

78+
if chatID == "me":
79+
try:
80+
await message.reply_to_message.forward(userID)
81+
await message.reply_html("<b>Message forwarded</b>")
82+
except Exception as e:
83+
await message.reply_html(f"<b>Error:</b> <code>{e}</code>")
84+
85+
return
86+
87+
reply = """
88+
Sending message to <b>{total}</b> users.
89+
90+
Success: {success}
91+
Failed: {failed}
92+
93+
Progress: {progress}%
94+
"""
95+
7396
if chatID == "all":
74-
users = db.getAllUsers()
97+
users = db.getActiveUsers() # send message to the active users only
7598
success = 0
7699
errors = 0
77-
for user in users:
100+
m = await message.reply_text(
101+
reply.format(total=len(users), success=success, failed=errors, progress=0)
102+
)
103+
for count, user in enumerate(users, 1):
78104
userID = user["_id"]
79105
try:
80106
await message.reply_to_message.forward(userID)
107+
success += 1
81108
with open("success.txt", "a") as f:
82109
f.write(f"{userID}\n")
83110

84-
success += 1
85-
86111
except Exception as e:
87112
logger.error(f"Error while forwarding to {userID}: {e}")
88-
with open("errors.txt", "a") as f:
89-
f.write(f"{userID}\n")
90-
91113
errors += 1
92-
93-
await message.reply_html("<b>Message forwarded to all users</b>")
94-
95-
await message.reply_document(
114+
with open("errors.txt", "a") as f:
115+
f.write(f"{userID} - {e}\n")
116+
finally:
117+
await asyncio.sleep(0.3)
118+
119+
# edit the message after 10 iterations
120+
currentTime = datetime.now(timezone.utc).strftime(
121+
"%d %B %Y, %H:%M:%S %A UTC"
122+
)
123+
if count % 10 == 0:
124+
text = (
125+
reply.format(
126+
total=len(users),
127+
success=success,
128+
failed=errors,
129+
progress=round(count / len(users), 2),
130+
)
131+
+ "\n"
132+
+ currentTime
133+
)
134+
try:
135+
await m.edit_text(text)
136+
except Exception as e:
137+
logger.error(f"Error editing the message in forward: {e}")
138+
139+
# after the loop is finished
140+
await m.reply_html("<b>Message forwarded to all users</b>")
141+
await m.reply_document(
96142
open("success.txt", "rb"),
97143
caption=f"<b>Success</b>\nCount: <code>{success} / {len(users)}</code>",
98144
)
99-
await message.reply_document(
145+
await m.reply_document(
100146
open("errors.txt", "rb"),
101147
caption=f"<b>Errors</b>\nCount: <code>{errors} / {len(users)}</code>",
102148
)
149+
try:
150+
os.remove("success.txt")
151+
os.remove("errors.txt")
152+
except Exception as e:
153+
logger.error(f"Failed to remove success.txt and errors.txt - {e}")
103154
return
104155

105156
await message.reply_html("<b>Invalid chatID</b>")
106157

107158

159+
async def loginAsAdmin(u: Update, c):
160+
"""Login as admin"""
161+
message = u.effective_message
162+
chatType = u.effective_chat.type
163+
userID = u.effective_user.id
164+
hashedPass = "b0cc3016f19b4ac2aece3b1312a213b91bfd93224c50615e0952034aa2baf300b3a41e31de8f7e629dc9c23f79a8aadb43eb41e69cfc96dccf99ce83538055dc"
165+
166+
if chatType != "private":
167+
return await message.reply_text("<b>Try in private chat!</b>")
168+
169+
text = message.text.split()[-1] # yeah, it's just one word
170+
if hashlib.sha512(text.encode("utf8")).hexdigest() != hashedPass:
171+
return await message.reply_text("<b>Wrong password. Sorry :p</b>")
172+
173+
db.localDB.admins.append(userID)
174+
await message.reply_text(f"<b>Successfully logged in with {userID = }</b>")
175+
176+
108177
@onlyDeveloper(notifyNonAdminUsers=False)
109178
async def deleteMessage(u: Update, c):
110179
"""Deletes a message"""
@@ -183,6 +252,7 @@ async def evaluateCode(u: Update, c):
183252
bot: Bot = c.bot
184253
message = u.effective_message
185254
userID = u.effective_user.id
255+
chatID = u.effective_chat.id
186256

187257
text = message.text[5:].strip()
188258
if "help" in text:
@@ -234,6 +304,7 @@ async def raiseError(u: Update, c):
234304
CommandHandler("forward", forwardMessage),
235305
CommandHandler("getUser", getUser),
236306
CommandHandler("eval", evaluateCode),
307+
CommandHandler("login", loginAsAdmin),
237308
CommandHandler("delete", deleteMessage),
238309
CommandHandler("error", raiseError),
239310
]

bot/handlers/database.py

+32-11
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ def __init__(self) -> None:
130130
# --- Local DB ---
131131
self.queue = []
132132
channels = self.db.channels.find({})
133-
chats = self.db.chats.find({})
134-
users = self.db.users.find({})
133+
chats = self.db.chats.find({}) or []
134+
users = self.db.users.find({}) or []
135+
135136
self.localDB = _LocalDB(users, chats, channels)
136137

137138
# --- Scheduled Tasks ---
@@ -188,7 +189,11 @@ def getChannel(self, channelID: int):
188189

189190
def addUser(self, userID: int):
190191
utcTime = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
191-
user = {"_id": userID, "settings": self.defaultSettings, "lastMessageTime": utcTime}
192+
user = {
193+
"_id": userID,
194+
"settings": self.defaultSettings,
195+
"lastMessageTime": utcTime,
196+
}
192197
self.localDB.addUser(user)
193198

194199
func = self.db.users.insert_one
@@ -198,7 +203,11 @@ def addUser(self, userID: int):
198203

199204
def addChat(self, chatID: int):
200205
utcTime = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
201-
chat = {"_id": chatID, "settings": self.defaultGroupSettings, "lastMessageTime": utcTime}
206+
chat = {
207+
"_id": chatID,
208+
"settings": self.defaultGroupSettings,
209+
"lastMessageTime": utcTime,
210+
}
202211
self.localDB.addChat(chat)
203212

204213
func = self.db.chats.insert_one
@@ -245,6 +254,16 @@ def updateChannel(self, channelID: int, settings: dict):
245254
self.queue.append((func, value))
246255
return None
247256

257+
def updateActiveUsers(self, userID: int):
258+
func = lambda values: self.db.activeUsers.update_one(values, upsert=True)
259+
value = ({"_id": "users"}, {"$addToSet": {"list": userID}})
260+
self.queue.append((func, value))
261+
return None
262+
263+
def getActiveUsers(self):
264+
users = self.db.activeUsers.find_one({"_id": "users"})
265+
return users["list"]
266+
248267
def runQueue(self):
249268
logger.info("--- Running Queue ---")
250269
start = time.time()
@@ -267,12 +286,13 @@ def runQueue(self):
267286
if timeMs > 100:
268287
logger.info(f"Time taken: {timeMs:.2f} ms")
269288

270-
# TODO: keep count of all the requests handled per day
271-
# Run this in a separate thread or use a TypeHandler to run after the other handlers (group=3)
272-
# so it doesn't block the event loop
273289
def updateCounter(self):
274290
date = time.strftime("%Y-%m-%d")
275-
self.db.analytics.update_one({"_id": date}, {"$inc": "requests"})
291+
func = lambda: self.db.analytics.update_one(
292+
{"_id": date}, {"$inc": {"requests": 1}}, upsert=True
293+
)
294+
threading.Thread(target=func).start()
295+
# logger.info(f"Another request at {date}")
276296

277297
# def deleteUser(self, userID: int):
278298
# return self.db.users.delete_one({"_id": userID})
@@ -295,10 +315,11 @@ async def main():
295315
chats = db.getAllChat()
296316
print("Total Users:", len(users))
297317
print("Total Chats:", len(chats))
298-
318+
299319
# import json
300-
# with open("users.json", 'w', encoding="utf8") as f:
301-
# json.dump(users, f, ensure_ascii=0)
320+
# with open("realUsers.json", 'rb') as f:
321+
# data = json.load(f)
322+
# db.db.activeUsers.insert_one({"_id":"users", "list":data})
302323

303324

304325
if __name__ == "__main__":

bot/handlers/middleware.py

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ async def middleware(u: Update, c):
2525

2626
# Only check for a new user in the private chat
2727
if userID == chatID:
28+
db.updateActiveUsers(userID) # add a new active user to the `set`
2829
user = db.getUser(userID)
2930
if not user:
3031
user = db.addUser(userID)
@@ -39,3 +40,5 @@ async def middleware(u: Update, c):
3940
if not chat:
4041
chat = db.addChat(chatID)
4142
db.updateChat(chatID, {"lastMessageTime": utcTime})
43+
44+
db.updateCounter() # Update counter for each day

0 commit comments

Comments
 (0)