Merge pull request 'Merge Beta with Stable releases' (#1) from dev into master

Reviewed-on: profitroll/HoloCheckerBot#1
This commit is contained in:
Profitroll 2022-12-16 16:14:40 +02:00
commit 3b71cb3d85
31 changed files with 931 additions and 537 deletions

9
.gitignore vendored
View File

@ -157,11 +157,8 @@ config.json
config_debug.json
*.session
*.session-journal
users
!users/.gitkeep
data
TASK.md
inline_bot.py
data/applications.json
!data/cache/avatars/.gitkeep
data/cache/avatars/*
.vscode
.vscode
migrate.py

View File

@ -9,6 +9,8 @@ Small Telegram bot made on Pyrogram
* Give one-time links to join group
* Track down users that were not allowed to join
* Show applications to other users
* Manage YouTube sponsorships [WIP]
* Send and receive messages to users using bot [WIP]
## Installation
@ -32,8 +34,6 @@ You can see config file with all the comments below:
"owner": 0,
"bot_id": 0,
"age_allowed": 0,
"birthdays_notify": true,
"birthdays_time": "09:00",
"api": "http://example.com",
"inline_preview_count": 7,
"admin_group": 0,
@ -45,29 +45,51 @@ You can see config file with all the comments below:
"api_hash": "",
"bot_token": ""
},
"database": {
"user": null,
"password": null,
"host": "127.0.0.1",
"port": 27017,
"name": "holochecker"
},
"geocoding": {
"username": "demo"
},
"logging": {
"size": 512,
"location": "logs"
},
"scheduler": {
"birthdays": {
"time": 9,
"enabled": true
},
"sponsorships": {
"time": 9,
"enabled": true
}
},
"locations": {
"data": "data",
"cache": "cache",
"locale": "locale"
},
"commands": {
"rules": "Check out the rules",
"reapply": "Resubmit the application"
"reapply": "Resubmit the application",
"sponsorship": "Apply for sponsor role"
},
"commands_admin": {
"reboot": "Restart the bot",
"message": "Send a message",
"message": "Send a message",
"label": "Set user's nickname",
"warnings": "Check user's warnings",
"application": "Check user's application",
"applications": "Retrieve all applications as a JSON"
},
"commands_group_admin": {
"reboot": "Restart the bot",
"message": "Send a message",
"message": "Send a message",
"label": "Set user's nickname",
"warnings": "Check user's warnings",
"application": "Check user's application",
"applications": "Retrieve all applications as a JSON"
@ -82,6 +104,6 @@ After all of that you're good to go! Happy using :)
## To-Do
* [ ] Complete messenger between user and admins
* [x] Complete messenger between user and admins
* [ ] Check sponsorship on Holo girls
* [ ] Get application by id and user_id

12
app.py
View File

@ -1,12 +1,18 @@
from modules.logging import logWrite
from modules.utils import configGet
from pyrogram.client import Client
from pyrogram.errors import bad_request_400
app = Client("holochecker", bot_token=configGet("bot_token", "bot"), api_id=configGet("api_id", "bot"), api_hash=configGet("api_hash", "bot"))
async def isAnAdmin(admin_id):
if (admin_id == configGet("owner")) or (admin_id in configGet("admins")):
return True
async for member in app.get_chat_members(configGet("admin_group")):
if member.user.id == admin_id:
return True
try:
async for member in app.get_chat_members(configGet("admin_group")):
if member.user.id == admin_id:
return True
except bad_request_400.ChannelInvalid:
logWrite(f"Could not get users in admin group to answer isAnAdmin(). Bot is likely not in the group.")
return False
return False

View File

@ -1,12 +1,40 @@
from datetime import datetime
from requests import get
from traceback import print_exc
from app import app, isAnAdmin
from typing import Any, List, Union
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message
from pyrogram.client import Client
from typing import Any, List, Literal, Union
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup
from pyrogram.errors import bad_request_400
from modules.database import col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages
from dateutil.relativedelta import relativedelta
from modules.database import col_tmp, col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages
from modules.logging import logWrite
from modules.utils import configGet, locale, should_quote
class DefaultApplicationTemp(dict):
def __init__(self, user: int):
super().__init__({})
self.dict = {
"user": user,
"type": "application",
"complete": False,
"sent": False,
"state": "fill",
"reapply": False,
"stage": 1,
"application": {
"1": None,
"2": None,
"3": None,
"4": None,
"5": None,
"6": None,
"7": None,
"8": None,
"9": None,
"10": None
}
}
class UserNotFoundError(Exception):
"""HoloUser could not find user with such an ID in database"""
def __init__(self, user, user_id):
@ -21,8 +49,21 @@ class UserInvalidError(Exception):
super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type")
class HoloUser():
"""This object represents a user of HoloChecker bot.
It is primarily used to interact with a database in a more python-friendly way,
as well as provide better programming experience in case of adding new features, etc.
"""
def __init__(self, user: Union[List[User], User, ChatMember, int, str]) -> None:
def __init__(self, user: Union[User, List[User], ChatMember, int]) -> None:
"""A user of Holo bot. Used to simplify DB interaction.
### Args:
* user (`Union[User, List[User], ChatMember, int]`): Any possible way to identify the user. Pass `User` object, user's telegram ID, etc...
### Raises:
* UserInvalidError: Provided to `HoloUser` object is not supported
* UserNotFoundError: `HoloUser` could not find user with such an ID in database
"""
# Determine input object class and extract id
if isinstance(user, list) and len(user) != 0:
@ -33,13 +74,14 @@ class HoloUser():
self.id = user.user.id
elif isinstance(user, int):
self.id = user
elif isinstance(user, str):
try:
self.id = (app.get_users(user)).id # this line requires testing though
except bad_request_400.UsernameNotOccupied:
raise UserInvalidError(user)
except bad_request_400.PeerIdInvalid:
raise UserInvalidError(user)
# elif isinstance(user, str):
# try:
# get_users = async_to_sync(app.get_users)
# self.id = get_users(user).id # this line requires testing though
# except bad_request_400.UsernameNotOccupied:
# raise UserInvalidError(user)
# except bad_request_400.PeerIdInvalid:
# raise UserInvalidError(user)
else:
raise UserInvalidError(user)
@ -71,35 +113,268 @@ class HoloUser():
col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { key: value } }, upsert=True)
logWrite(f"Set attribute {key} of user {self.id} to {value}")
async def message(self, origin: Message, text: Union[str, None] = None, photo: Union[str, None] = None, video: Union[str, None] = None, file: Union[str, None] = None):
new_message = await app.send_message(self.id, text+locale("message_reply_notice", "message"))
await origin.reply_text(locale("message_sent", "message"), quote=should_quote(origin))
logWrite(f"Admin {origin.from_user.id} sent message '{' '.join(origin.command[2:])}' to {self.id}")
col_messages.insert_one({"origin": {"chat": origin.chat.id, "id": origin.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
async def message(self,
context: Message,
origin: Union[Message, None] = None,
text: Union[str, None] = None,
caption: Union[str, None] = None,
photo: Union[str, Photo, None] = None,
video: Union[str, Video, None] = None,
file: Union[str, Document, None] = None,
animation: Union[str, Animation, None] = None,
voice: Union[str, Voice, None] = None,
adm_origin: bool = False,
adm_context: bool = False
) -> None:
"""Send a message to user
async def set_label(self, chat: Chat, label: str):
### Args:
* context (`Message`): Context (mostly the message where this method is called)
* origin (`Union[Message, None]`, *optional*): Origin message where to refer. None if called in a command. Defaults to None.
* text (`Union[str, None]`, *optional*): Text if this is a simple text message. Defaults to None.
* caption (`Union[str, None]`, *optional*): Text if this is a media message. Defaults to None.
* photo (`Union[str, Photo, None]`, *optional*): Photo as a photo object or file_id as a string. Defaults to None.
* video (`Union[str, Video, None]`, *optional*): Video as a video object or file_id as a string. Defaults to None.
* file (`Union[str, Document, None]`, *optional*): File as a document object or file_id as a string. Defaults to None.
* animation (`Union[str, Animation, None]`, *optional*): Animation as an animation object or file_id as a string. Defaults to None.
* voice (`Union[str, Voice, None]`, *optional*): Voice as a voice object or file_id as a string. Defaults to None.
* adm_origin (`bool`, *optional*): Whether origin sender is an admin. Defaults to False.
* adm_context (`bool`, *optional*): Whether context sender is an admin. Defaults to False.
"""
# Check if any text available and log message sending
if text is not None:
logWrite(f"{context.from_user.id} sent message '{text}' to {self.id}")
elif caption is not None:
logWrite(f"{context.from_user.id} sent message '{caption}' to {self.id}")
else:
logWrite(f"{context.from_user.id} sent message to {self.id}")
# Add notices for admin or user
if text is not None:
if adm_context:
text += locale("message_reply_notice", "message")
elif adm_origin:
text = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + text + locale("message_reply_notice", "message")
else:
text = locale("message_reply_notice", "message")
if caption is not None:
if adm_context:
caption += locale("message_reply_notice", "message")
elif adm_origin:
caption = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + caption + locale("message_reply_notice", "message")
else:
caption = locale("message_reply_notice", "message")
# Try sending the message
try:
# Check if origin message exists
# This check decides whether we send_ a message or reply_ to one
if origin is not None:
if photo is not None:
if isinstance(photo, Photo):
photo = photo.file_id
new_message = await origin.reply_photo(photo, caption=caption, quote=True)
elif video is not None:
if isinstance(video, Video):
video = video.file_id
new_message = await origin.reply_video(video, caption=caption, quote=True)
elif file is not None:
if isinstance(file, Document):
file = file.file_id
new_message = await origin.reply_document(file, caption=caption, quote=True)
elif animation is not None:
if isinstance(animation, Animation):
animation = animation.file_id
new_message = await origin.reply_animation(animation, caption=caption, quote=True)
elif voice is not None:
if isinstance(voice, Voice):
voice = voice.file_id
new_message = await origin.reply_voice(voice, caption=caption, quote=True)
else:
new_message = await origin.reply_text(text, quote=True)
else:
if photo is not None:
if isinstance(photo, Photo):
photo = photo.file_id
new_message = await app.send_photo(self.id, photo, caption=caption)
elif video is not None:
if isinstance(video, Video):
video = video.file_id
new_message = await app.send_video(self.id, video, caption=caption)
elif file is not None:
if isinstance(file, Document):
file = file.file_id
new_message = await app.send_document(self.id, file, caption=caption)
elif animation is not None:
if isinstance(animation, Animation):
animation = animation.file_id
new_message = await app.send_animation(animation, caption=caption, quote=True)
elif voice is not None:
if isinstance(voice, Voice):
voice = voice.file_id
new_message = await app.send_voice(voice, caption=caption, quote=True)
else:
new_message = await app.send_message(self.id, text)
# Acknowledge sending a message and save entry into DB
await context.reply_text(locale("message_sent", "message"), quote=should_quote(context))
col_messages.insert_one({"origin": {"chat": context.chat.id, "id": context.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
# Report to admin and to sender about message sending failure
except Exception as exp:
logWrite(f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{print_exc()}")
try:
await app.send_message(configGet("owner"), locale("message_traceback", "message").format(context.from_user.id, self.id, exp, print_exc()))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
await context.reply_text(locale("message_error", "message"), quote=should_quote(context))
async def set_label(self, chat: Chat, label: str) -> None:
"""Set label in destination group
### Args:
* app (`Client`): Pyrogram client
* chat (`Chat`): Telegram chat
* label (`str`): Label you want to set
"""
self.label = label
self.set("label", label)
await app.promote_chat_member(configGet("destination_group"), self.id)
if (not await isAnAdmin(self.id)) and (chat.id == configGet("admin_group")):
if not await isAnAdmin(self.id):
await app.set_administrator_title(configGet("destination_group"), self.id, label)
async def reset_label(self, chat: Chat):
async def reset_label(self, chat: Chat) -> None:
"""Reset label in destination group
### Args:
* app (`Client`): Pyrogram client
* chat (`Chat`): Telegram chat
"""
self.label = ""
self.set("label", "")
await app.set_administrator_title(configGet("destination_group"), self.id, "")
if (not await isAnAdmin(self.id)) and (chat.id == configGet("admin_group")):
if not await isAnAdmin(self.id):
await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges(
can_manage_chat=False
))
))
def application_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]:
"""Check the current state of application in tmp collection
### Returns:
* `tuple[Literal["none", "fill", "approved", "rejected"], bool]`: First element is an enum of a state and the second one is whether application is complete.
"""
tmp_application = col_tmp.find_one({"user": self.id, "type": "application"})
if tmp_application is None:
return "none", False
else:
return tmp_application["state"], tmp_application["complete"]
def application_approved(self) -> bool:
"""Check whether user has a completed application and it got approved
### Returns:
* `bool`: `True` if yes and `False` if no
"""
return True if col_applications.find_one({"user": self.id}) is not None else False
def application_restart(self) -> None:
"""Reset application of a user in tmp collection and replace it with an empty one
"""
if col_tmp.find_one({"user": self.id, "type": "application"}) is None:
col_tmp.insert_one(document=DefaultApplicationTemp(self.id).dict)
else:
col_tmp.delete_one({"user": self.id, "type": "application"})
col_tmp.insert_one(document=DefaultApplicationTemp(self.id).dict)
async def application_next(self, query: str, msg: Message) -> None:
"""Move on filling application of user
### Args:
* query (`str`): Some kind of input
* msg (`Message`): Message that should receive replies
"""
if col_tmp.find_one({"user": self.id, "type": "application"}) is None:
col_tmp.insert_one(
document=DefaultApplicationTemp(self.id).dict
)
progress = col_tmp.find_one({"user": self.id, "type": "application"})
stage = progress["stage"]
if progress["state"] == "fill":
if stage == 2:
try:
input_dt = datetime.strptime(query, "%d.%m.%Y")
except ValueError:
logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format")
await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply"))))
return
if datetime.now() <= input_dt:
logWrite(f"User {msg.from_user.id} failed stage {stage} due to joking")
await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
return
elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
logWrite(f"User {msg.from_user.id} failed stage {stage} due to being underage")
await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
return
else:
print(f'Look: {((datetime.now() - input_dt).days)} > {(datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days}')
progress["application"][str(stage)] = input_dt
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply"))))
elif stage == 3:
try:
result = (get(f"http://api.geonames.org/searchJSON?q={query}&maxRows=1&countryBias=UA&lang=uk&orderby=relevance&featureClass=P&featureClass=A&username={configGet('username', 'geocoding')}")).json()
progress["application"][str(stage)] = result["geonames"][0]
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"question3_found", "message").format(result["geonames"][0]["name"], result["geonames"][0]["adminName1"]))
await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply"))))
except (ValueError, KeyError, IndexError):
await msg.reply_text(locale(f"question3_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply"))))
return
except Exception as exp:
await msg.reply_text(locale("question3_error", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply"))))
try:
await app.send_message(configGet("owner"), locale("question3_traceback", "message").format(query, exp, print_exc()))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
return
elif stage == 10:
progress["application"][str(stage)] = query
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "complete": True}})
application_content = []
i = 1
for question in progress["application"]:
if i == 2:
age = relativedelta(datetime.now(), progress['application']['2'])
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
elif i == 3:
if progress['application']['3']['countryCode'] == "UA":
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application'][question]}")
i += 1
await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True))
else:
progress["application"][str(stage)] = query
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply"))))
logWrite(f"User {self.id} completed stage {stage} of application")

View File

@ -22,6 +22,9 @@
"port": 27017,
"name": "holochecker"
},
"geocoding": {
"username": "demo"
},
"logging": {
"size": 512,
"location": "logs"
@ -42,6 +45,7 @@
},
"commands": {
"rules": "Check out the rules",
"nearby": "Show users near the area",
"reapply": "Resubmit the application",
"sponsorship": "Apply for sponsor role"
},
@ -57,11 +61,13 @@
"reboot": "Restart the bot",
"message": "Send a message",
"label": "Set user's nickname",
"nearby": "Show users near the area",
"warnings": "Check user's warnings",
"application": "Check user's application",
"applications": "Retrieve all applications as a JSON"
},
"commands_group_destination": {
"warn": "Warn a user"
"warn": "Warn a user",
"nearby": "Show users near the area"
}
}

View File

@ -15,6 +15,7 @@ from modules.commands.application import *
from modules.commands.applications import *
from modules.commands.label import *
from modules.commands.message import *
from modules.commands.nearby import *
from modules.commands.reapply import *
from modules.commands.reboot import *
from modules.commands.rules import *

View File

@ -5,7 +5,7 @@
"privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.",
"question1": "Як до тебе можна звертатись?",
"question2": "Коли в тебе день народження?",
"question3": "З якого ти міста та де проживаєш зараз?\n\n⚠ Будь ласка, не вказуйте точних адрес! \"Київщина\" може бути достатньою конкретизацією.",
"question3": "З якого ти міста або де проживаєш зараз?\n\n⚠ Будь ласка, не вказуйте точних адрес! \"Київ\" або \"Київська Область\" є достатньою конкретизацією.\n\nПриклади:\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
"question4": "Коли вперше довелось дізнатись про Хололайв?",
"question5": "Чим тебе зацікавив Хололайв?",
"question6": "Контент якої дівчини тобі подобається найбільше?",
@ -16,6 +16,10 @@
"question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.",
"question2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
"question2_joke": "Шутнік, ми так і поняли. Але будь ласка, введи реальне значення.",
"question3_invalid": "Місто/населений пункт не знайдено. Користуйтесь прикладами нижче щоб вказати де ви проживаєте та спробуйте ще раз:\n\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
"question3_found": "Використовую наступний результат:\n• {0} ({1})",
"question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.",
"question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```",
"confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?",
"application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)",
"application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`, `{2}`\nЮзернейм: @{3}\n\n**Дані анкети:**\n{4}",
@ -26,30 +30,32 @@
"approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ. Скористайся кнопкою під повідомленням щоб вступити до нашої лампової спільноти!",
"approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!",
"read_rules": "Будь ласка, прочитай ці правила перш ніж натискати на кнопку та приєднуватись до чату.",
"refused": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!",
"refused_russian": "русский военньій корабль, иди нахуй!",
"rejected": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!\n\nТи можеш спробувати повторно заповнити анкету командою /reapply",
"rejected_aggressive": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти.",
"rejected_russian": "русский военньій корабль, иди нахуй!",
"approved_by": "✅ **Анкету схвалено**\nАдмін **{0}** переглянув та схвалив анкету `{1}`.",
"refused_by": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`.",
"refused_by_agr": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: агресивна/токсична анкета.",
"refused_by_rus": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: русня.",
"rejected_by": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`.",
"rejected_by_agr": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: агресивна/токсична анкета.",
"rejected_by_rus": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: русня.",
"contact": "Анкета `{0}`\n\n**Дані анкети:**\n{1}\n\n{2}",
"application_status_accepted": "Прийнята `{0}` від {1}",
"application_status_refused": "Відхилена `{0}` від {1}",
"application_status_rejected": "Відхилена `{0}` від {1}",
"application_status_on_hold": "Анкета все ще на розгляді",
"application_status_not_send": "Анкета ще не була відправлена",
"contact_invalid": "Надісланий контакт не має розпочатої анкети.",
"contact_invalid": "Надісланий контакт не має завершеної анкети.",
"contact_not_member": "Надісланий контакт не є користувачем Telegram.",
"already_sent": "Анкету вже надіслано, просто почекай. Тобі одразу повідомлять, яке рішення буде прийнято.",
"sus_joined": "Користувач **{0}** (`{1}`) зайшов до групи не за своїм персональним запрошенням.",
"sus_allowed_by": "✅ **Доступ дозволено**\nАдмін **{0}** дозволив `{1}` вступити до спільноти не за персональним посиланням.",
"sus_refused_by": "❌ **Доступ заборонено**\nАдмін **{0}** заборонив `{1}` доступ до спільноти не за персональним посиланням.",
"sus_rejected_by": "❌ **Доступ заборонено**\nАдмін **{0}** заборонив `{1}` доступ до спільноти не за персональним посиланням.",
"reapply_forbidden": "❌ **Дія неможлива**\nТвоя минула анкета ще не була схвалена або відхилена.",
"reapply_in_progress": "❌ **Дія неможлива**\nТи прямо зараз вже заповнюєш анкету. Якщо в ній є помилка - просто натисни кнопку нижче щоб почати заповнювати спочатку.",
"reapply_restarted": "🔁 **Перезапущено**\nРозпочате заповнення анкети спочатку.",
"reapply_left_chat": "⚠️ **Нагадування**\nЗдається, ти залишив чат у минулому, проте твоя анкета все ще доступна до використання. Подати запит на вступ користуючись старою анкетою?",
"birthday": "У користувача **{0}** (@{1}) сьогодні день народження! Виповнилось {2} років",
"application_invalid_syntax": "Неправильний синтаксис!\nТреба: `/application ID/NAME/USERNAME`",
"warned": "Попереджено користувача **{0}** (`{1}`) про порушення правил",
"warned": "Попереджено **{0}** (`{1}`) про порушення правил",
"warned_reason": "Попереджено **{0}** (`{1}`)\n\n**Причина:**\n{2}",
"warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження",
"warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень",
"no_warnings": "Користувач **{0}** (`{1}`) не має попереджень",
@ -60,6 +66,11 @@
"message_invalid_syntax": "Неправильний синтаксис!\nТреба: `/message ID ПОВІДОМЛЕННЯ`",
"message_from": "Повідомлення від **{0}** (`{1}`):\n\n",
"message_reply_notice": "\n\n**Щоб надіслати відповідь на це повідомлення, тегніть його.**",
"message_error": "⚠️ **Сталась помилка**\nНе вдалось надіслати ваше повідомлення. Розробника повідомлено про цю помилку.",
"message_traceback": "⚠️ **Сталась помилка**\nПомилка повідомлень: `{0}` -> `{1}`\nПомилка: `{2}`\n\nTraceback:\n```\n{3}\n```",
"no_user_application": "Не знайдено користувачів за запитом **{0}**",
"user_invalid": "Надісланий користувач не має завершеної анкети.",
"joined_false_link": "Користувач **{0}** (`{1}`) приєднався до групи не за своїм посиланням",
"question_titles": {
"question1": "Ім'я/звертання:",
"question2": "День народження:",
@ -111,15 +122,15 @@
"button": {
"sub_yes": "✅ Прийняти",
"sub_no": "❌ Відхилити",
"sub_no_aggressive": "🤡 Відхилити (Токс)",
"sub_no_russian": "🇷🇺 Відхилити (Русак)",
"sub_aggressive": "🤡 Відхилити (Токс)",
"sub_russian": "🇷🇺 Відхилити (Русак)",
"accepted": "✅ Прийнято",
"declined": "❌ Відхилено",
"join": "Приєднатись",
"sus_allow": "✅ Підтвердити дозвіл",
"sus_refuse": "❌ Перманентно заблокувати",
"sus_reject": "❌ Перманентно заблокувати",
"sus_allowed": "✅ Дозвіл надано",
"sus_refused": "❌ Користувача заблоковано",
"sus_rejected": "❌ Користувача заблоковано",
"reapply_yes": "✅ Прийняти",
"reapply_no": "❌ Відхилити",
"reapply_old_one": "✅ Надіслати стару",
@ -133,11 +144,11 @@
},
"callback": {
"sub_accepted": "✅ Анкету {0} схвалено",
"sub_refused": "❌ Анкету {0} відхилено",
"sub_no_aggressive": "🤡 Анкету {0} відхилено",
"sub_no_russian": "🇷🇺 Анкету {0} відхилено",
"sub_rejected": "❌ Анкету {0} відхилено",
"sub_aggressive": "🤡 Анкету {0} відхилено",
"sub_russian": "🇷🇺 Анкету {0} відхилено",
"sus_allowed": "✅ Доступ {0} дозволено",
"sus_refused": "❌ Доступ {0} заборонено",
"sus_rejected": "❌ Доступ {0} заборонено",
"nothing": "🔔 Дія вже виконана",
"rules_page": " Показано правило {0}",
"rules_home": " Показано головну правил",

View File

@ -1,93 +1,82 @@
from os import sep
from time import time
from datetime import datetime
from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove
from pyrogram import filters
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite
from classes.holo_user import HoloUser
from modules.utils import configGet, locale, logWrite
from modules.handlers.confirmation import confirm_yes
from modules.handlers.welcome import welcome_pass
from modules.database import col_tmp, col_applications
# Callbacks reapply ============================================================================================================
@app.on_callback_query(filters.regex("reapply_yes_[\s\S]*"))
async def callback_reapply_query_accept(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("approved_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
logWrite(f"User {fullclb[2]} got their reapplication approved by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
logWrite(f"User {holo_user.id} got their reapplication approved by {clb.from_user.id}")
await app.send_message(int(fullclb[2]), locale("approved_joined", "message"))
await app.send_message(holo_user.id, locale("approved_joined", "message"))
configSet(["approved"], True, file=fullclb[2])
configSet(["sent"], False, file=fullclb[2])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[2]]["approved"] = True
application[fullclb[2]]["approved_by"] = clb.from_user.id
application[fullclb[2]]["approval_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
col_applications.delete_one({"user": {"$eq": holo_user.id}})
col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]})
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_accepted", "callback").format(fullclb[2]), show_alert=True)
await clb.answer(text=locale("sub_accepted", "callback").format(holo_user.id), show_alert=True)
need_link = True
async for member in app.get_chat_members(configGet("destination_group")):
if member.user.id == int(fullclb[2]):
if member.user.id == holo_user.id:
need_link = False
if need_link:
link = await app.create_chat_invite_link(configGet("destination_group"), name=f"Invite for {fullclb[2]}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
link = await app.create_chat_invite_link(configGet("destination_group"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
await app.send_message(int(fullclb[2]), locale("read_rules", "message"))
await app.send_message(holo_user.id, locale("read_rules", "message"))
for rule_msg in locale("rules"):
await app.send_message(int(fullclb[2]), rule_msg)
await app.send_message(holo_user.id, rule_msg)
await app.send_message(int(fullclb[2]), locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
await app.send_message(holo_user.id, locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
[[
InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]]
))
configSet(["link"], link.invite_link, file=fullclb[2])
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}")
holo_user.set("link", link.invite_link)
logWrite(f"User {holo_user.id} got an invite link {link.invite_link}")
else:
await app.send_message(int(fullclb[2]), locale("approved_joined", "message"))
await app.send_message(holo_user.id, locale("approved_joined", "message"))
@app.on_callback_query(filters.regex("reapply_no_[\s\S]*"))
async def callback_query_reapply_refuse(app, clb):
async def callback_query_reapply_reject(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("refused_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
await app.send_message(int(fullclb[2]), locale("refused", "message"))
logWrite(f"User {fullclb[2]} got their reapplication refused by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
await app.send_message(holo_user.id, locale("rejected", "message"))
logWrite(f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}")
configSet(["refused"], True, file=fullclb[2])
configSet(["sent"], False, file=fullclb[2])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[2]]["refused"] = True
application[fullclb[2]]["refused_by"] = clb.from_user.id
application[fullclb[2]]["refusal_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_refused", "callback").format(fullclb[2]), show_alert=True)
await clb.answer(text=locale("sub_rejected", "callback").format(fullclb[2]), show_alert=True)
# Use old application when user reapplies after leaving the chat
@app.on_callback_query(filters.regex("reapply_old_[\s\S]*"))
async def callback_query_reapply_old(app, clb):
fullclb = clb.data.split("_")
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
configSet(["approved"], False, file=str(clb.from_user.id))
configSet(["refused"], False, file=str(clb.from_user.id))
await confirm_yes(app, message)
await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button"), "nothing")]]))
@ -97,11 +86,6 @@ async def callback_query_reapply_new(app, clb):
fullclb = clb.data.split("_")
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{clb.from_user.id}.json")
configSet(["telegram_id"], str(clb.from_user.username), file=str(clb.from_user.id))
configSet(["telegram_name"], f"{clb.from_user.first_name} {clb.from_user.last_name}", file=str(clb.from_user.id))
configSet(["telegram_phone"], str(clb.from_user.phone_number), file=str(clb.from_user.id))
configSet(["telegram_locale"], str(clb.from_user.language_code), file=str(clb.from_user.id))
await clb.answer(locale("reapply_stopped", "callback"))
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
await welcome_pass(app, message, once_again=True)
@ -113,12 +97,9 @@ async def callback_query_reapply_new(app, clb):
async def callback_query_reapply_stop(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(clb.from_user)
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{clb.from_user.id}.json")
configSet(["telegram_id"], str(clb.from_user.username), file=str(clb.from_user.id))
configSet(["telegram_name"], f"{clb.from_user.first_name} {clb.from_user.last_name}", file=str(clb.from_user.id))
configSet(["telegram_phone"], str(clb.from_user.phone_number), file=str(clb.from_user.id))
configSet(["telegram_locale"], str(clb.from_user.language_code), file=str(clb.from_user.id))
holo_user.application_restart()
await clb.answer(locale("reapply_stopped", "callback"))
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
await welcome_pass(app, message, once_again=True)

View File

@ -1,126 +1,103 @@
from os import sep
from time import time
from datetime import datetime
from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram import filters
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite
from classes.holo_user import HoloUser
from modules.utils import configGet, locale, logWrite
from modules.database import col_tmp, col_applications
from modules.commands.rules import default_rules_markup
# Callbacks application ========================================================================================================
@app.on_callback_query(filters.regex("sub_yes_[\s\S]*"))
async def callback_query_accept(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("approved_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
logWrite(f"User {fullclb[2]} got approved by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}")
need_link = True
async for member in app.get_chat_members(configGet("destination_group")):
if member.user.id == int(fullclb[2]):
if member.user.id == holo_user.id:
need_link = False
if need_link:
link = await app.create_chat_invite_link(configGet("destination_group"), name=f"Invite for {fullclb[2]}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
link = await app.create_chat_invite_link(configGet("destination_group"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
await app.send_message(int(fullclb[2]), locale("read_rules", "message"))
await app.send_message(holo_user.id, locale("read_rules", "message"))
for rule_msg in locale("rules"):
await app.send_message(int(fullclb[2]), rule_msg)
await app.send_message(holo_user.id, locale("rules_msg"), disable_web_page_preview=True, reply_markup=default_rules_markup)
await app.send_message(int(fullclb[2]), locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
await app.send_message(holo_user.id, locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
[[
InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]]
))
configSet(["link"], link.invite_link, file=fullclb[2])
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}")
holo_user.set("link", link.invite_link)
logWrite(f"User {holo_user.id} got an invite link {link.invite_link}")
else:
await app.send_message(int(fullclb[2]), locale("approved_joined", "message"))
await app.send_message(holo_user.id, locale("approved_joined", "message"))
configSet(["approved"], True, file=fullclb[2])
configSet(["sent"], False, file=fullclb[2])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[2]]["approved"] = True
application[fullclb[2]]["approved_by"] = clb.from_user.id
application[fullclb[2]]["approval_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]})
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_accepted", "callback").format(fullclb[2]), show_alert=True)
@app.on_callback_query(filters.regex("sub_no_aggressive_[\s\S]*"))
async def callback_query_refuse_aggressive(app, clb):
fullclb = clb.data.split("_")
await app.send_message(configGet("admin_group"), locale("refused_by_agr", "message").format(clb.from_user.first_name, fullclb[3]), disable_notification=True)
await app.send_message(int(fullclb[3]), locale("refused", "message"))
logWrite(f"User {fullclb[3]} got refused by {clb.from_user.id} due to being aggressive")
configSet(["refused"], True, file=fullclb[3])
configSet(["sent"], False, file=fullclb[3])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[3]]["refused"] = True
application[fullclb[3]]["refused_by"] = clb.from_user.id
application[fullclb[3]]["refusal_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_no_aggressive", "callback").format(fullclb[3]), show_alert=True)
@app.on_callback_query(filters.regex("sub_no_russian_[\s\S]*"))
async def callback_query_refuse_russian(app, clb):
fullclb = clb.data.split("_")
await app.send_message(configGet("admin_group"), locale("refused_by_rus", "message").format(clb.from_user.first_name, fullclb[3]), disable_notification=True)
await app.send_message(int(fullclb[3]), locale("refused", "message"))
await app.send_message(int(fullclb[3]), locale("refused_russian", "message"))
logWrite(f"User {fullclb[3]} got refused by {clb.from_user.id} due to being russian")
configSet(["refused"], True, file=fullclb[3])
configSet(["sent"], False, file=fullclb[3])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[3]]["refused"] = True
application[fullclb[3]]["refused_by"] = clb.from_user.id
application[fullclb[3]]["refusal_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_no_russian", "callback").format(fullclb[3]), show_alert=True)
await clb.answer(text=locale("sub_accepted", "callback").format(holo_user.id), show_alert=True)
@app.on_callback_query(filters.regex("sub_no_[\s\S]*"))
async def callback_query_refuse(app, clb):
async def callback_query_reject(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("refused_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
await app.send_message(int(fullclb[2]), locale("refused", "message"))
logWrite(f"User {fullclb[2]} got refused by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
await app.send_message(holo_user.id, locale("rejected", "message"))
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id}")
configSet(["refused"], True, file=fullclb[2])
configSet(["sent"], False, file=fullclb[2])
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[2]]["refused"] = True
application[fullclb[2]]["refused_by"] = clb.from_user.id
application[fullclb[2]]["refusal_date"] = int(time())
jsonSave(application, f"{configGet('data', 'locations')}{sep}applications.json")
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_refused", "callback").format(fullclb[2]), show_alert=True)
await clb.answer(text=locale("sub_rejected", "callback").format(holo_user.id), show_alert=True)
@app.on_callback_query(filters.regex("sub_aggressive_[\s\S]*"))
async def callback_query_reject_aggressive(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("rejected_by_agr", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
await app.send_message(holo_user.id, locale("rejected_aggressive", "message"))
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id} due to being aggressive")
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_aggressive", "callback").format(holo_user.id), show_alert=True)
@app.on_callback_query(filters.regex("sub_russian_[\s\S]*"))
async def callback_query_reject_russian(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("rejected_by_rus", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
await app.send_message(holo_user.id, locale("rejected_russian", "message"))
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id} due to being russian")
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sub_russian", "callback").format(holo_user.id), show_alert=True)
# ==============================================================================================================================

View File

@ -1,24 +1,26 @@
from os import sep
from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions
from pyrogram import filters
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite
from classes.holo_user import HoloUser
from modules.utils import configGet, locale, logWrite
from modules.database import col_tmp
# Callbacks sus users ==========================================================================================================
@app.on_callback_query(filters.regex("sus_allow_[\s\S]*"))
async def callback_query_sus_allow(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("sus_allowed_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
logWrite(f"User {fullclb[2]} was allowed to join with another link by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("sus_allowed_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
logWrite(f"User {holo_user.id} was allowed to join with another link by {clb.from_user.id}")
edited_markup = [[InlineKeyboardButton(text=str(locale("sus_allowed", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sus_allowed", "callback").format(fullclb[2]), show_alert=True)
await clb.answer(text=locale("sus_allowed", "callback").format(holo_user.id), show_alert=True)
await app.restrict_chat_member(configGet("destination_group"), int(fullclb[2]), permissions=ChatPermissions(
await app.restrict_chat_member(configGet("destination_group"), holo_user.id, permissions=ChatPermissions(
can_send_messages=True,
can_send_media_messages=True,
can_send_other_messages=True,
@ -26,23 +28,21 @@ async def callback_query_sus_allow(app, clb):
)
)
@app.on_callback_query(filters.regex("sus_refuse_[\s\S]*"))
async def callback_query_sus_refuse(app, clb):
@app.on_callback_query(filters.regex("sus_reject_[\s\S]*"))
async def callback_query_sus_reject(app, clb):
fullclb = clb.data.split("_")
holo_user = HoloUser(int(fullclb[2]))
await app.send_message(configGet("admin_group"), locale("sus_refused_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
logWrite(f"User {fullclb[2]} was refused to join with another link by {clb.from_user.id}")
await app.send_message(configGet("admin_group"), locale("sus_rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
logWrite(f"User {holo_user.id} was rejected to join with another link by {clb.from_user.id}")
edited_markup = [[InlineKeyboardButton(text=str(locale("sus_refused", "button")), callback_data="nothing")]]
edited_markup = [[InlineKeyboardButton(text=str(locale("sus_rejected", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.answer(text=locale("sus_refused", "callback").format(fullclb[2]), show_alert=True)
await clb.answer(text=locale("sus_rejected", "callback").format(holo_user.id), show_alert=True)
await app.ban_chat_member(configGet("destination_group"), int(fullclb[2]))
await app.ban_chat_member(configGet("destination_group"), holo_user.id)
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{fullclb[2]}.json")
configSet(["stage"], 10, file=fullclb[2])
configSet(["refused"], True, file=fullclb[2])
configSet(["refused_by"], clb.from_user.id, file=fullclb[2])
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
# ==============================================================================================================================

View File

@ -1,55 +1,95 @@
from os import sep, path
from datetime import datetime
from app import app, isAnAdmin
from pyrogram import filters
from pyrogram.enums.chat_members_filter import ChatMembersFilter
from modules.utils import configGet, jsonLoad, logWrite, locale, should_quote
from pyrogram.enums.parse_mode import ParseMode
from pyrogram.errors import bad_request_400
from classes.holo_user import HoloUser, UserNotFoundError
from modules.utils import logWrite, locale, should_quote
from dateutil.relativedelta import relativedelta
from modules.database import col_applications
# Applications command =========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"]))
async def cmd_application(app, msg):
if (await isAnAdmin(msg.from_user.id)) or (msg.chat.id == configGet("admin_group")):
if await isAnAdmin(msg.from_user.id) is True:
try:
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]):
user_id = int(msg.command[1])
else:
list_of_users = []
async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
list_of_users.append(m)
user_id = list_of_users[0].user.id
try:
user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json")
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)]
application_content = []
i = 1
for question in configGet("application", file=str(msg.from_user.id)):
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)")
holo_user = HoloUser(int(msg.command[1]))
except (ValueError, UserNotFoundError):
try:
holo_user = HoloUser((await app.get_users(msg.command[1])).id)
except (bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid):
await msg.reply_text(locale("no_user_application", "message").format(msg.command[1]), quote=should_quote(msg))
return
application = col_applications.find_one({"user": holo_user.id})
if application is None:
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id} but user does not exists")
await msg.reply_text(locale("user_invalid", "message"), quote=should_quote(msg))
return
application_content = []
i = 1
for question in application['application']:
if i == 2:
age = relativedelta(datetime.now(), application['application']['2'])
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
elif i == 3:
if application['application']['3']['countryCode'] == "UA":
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}")
i += 1
if user_data["sent"]:
if user_data["approved"]:
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
elif application["refused"]:
application_status = locale("application_status_refused", "message").format((await app.get_users(application["refused_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
else:
application_status = locale("application_status_on_hold", "message")
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
else:
if user_data["approved"]:
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
elif application["refused"]:
application_status = locale("application_status_refused", "message").format((await app.get_users(application["refused_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
else:
application_status = locale("application_status_not_send", "message")
logWrite(f"User {msg.from_user.id} requested application of {user_id}")
await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), quote=should_quote(msg))
except FileNotFoundError:
logWrite(f"User {msg.from_user.id} requested application of {user_id} but user does not exists")
await msg.reply_text(locale("contact_invalid", "message"), quote=should_quote(msg))
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}")
i += 1
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M"))
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}")
await msg.reply_text(locale("contact", "message").format(holo_user.id, "\n".join(application_content), application_status), parse_mode=ParseMode.MARKDOWN, quote=should_quote(msg))
# if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]):
# user_id = int(msg.command[1])
# else:
# list_of_users = []
# async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
# list_of_users.append(m)
# user_id = list_of_users[0].user.id
# try:
# user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json")
# application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)]
# application_content = []
# i = 1
# for question in configGet("application", file=str(msg.from_user.id)):
# if i == 2:
# age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y'))
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)")
# else:
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}")
# i += 1
# if user_data["sent"]:
# if user_data["approved"]:
# application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
# elif application["rejected"]:
# application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
# else:
# application_status = locale("application_status_on_hold", "message")
# else:
# if user_data["approved"]:
# application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
# elif application["rejected"]:
# application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
# else:
# application_status = locale("application_status_not_send", "message")
# logWrite(f"User {msg.from_user.id} requested application of {user_id}")
# await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), quote=should_quote(msg))
except IndexError:
await msg.reply_text(locale("application_invalid_syntax", "message"), quote=should_quote(msg))

View File

@ -3,18 +3,23 @@ from uuid import uuid1
from app import app, isAnAdmin
from pyrogram import filters
from pyrogram.enums.chat_action import ChatAction
from modules.utils import configGet, should_quote, jsonSave
from modules.logging import logWrite
from modules.utils import should_quote, jsonSave
from modules.database import col_applications
# Applications command =========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"]))
async def cmd_applications(app, msg):
if (await isAnAdmin(msg.from_user.id)) or (msg.chat.id == configGet("admin_group")):
if await isAnAdmin(msg.from_user.id) is True:
logWrite(f"Admin {msg.from_user.id} requested export of a database")
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
filename = uuid1()
output = []
for entry in col_applications.find():
del entry["_id"]
entry["date"] = entry["date"].strftime("%d.%m.%Y, %H:%M")
entry["application"]["2"] = entry["application"]["2"].strftime("%d.%m.%Y, %H:%M")
output.append(entry)
makedirs("tmp", exist_ok=True)
jsonSave(output, f"tmp{sep}{filename}.json")

View File

@ -1,13 +1,12 @@
from app import app, isAnAdmin
from pyrogram import filters
from pyrogram.types import ChatPrivileges
from modules.utils import should_quote, find_user, configGet
from modules.utils import should_quote, find_user
from classes.holo_user import HoloUser
@app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"]))
async def cmd_label(app, msg):
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
if await isAnAdmin(msg.from_user.id) is True:
if len(msg.command) < 3:
await msg.reply_text("Invalid syntax:\n`/label USER LABEL`")

View File

@ -1,16 +1,13 @@
from os import sep
from app import app, isAnAdmin
from pyrogram import filters
from pyrogram.errors import bad_request_400
from classes.holo_user import HoloUser
from modules.utils import jsonLoad, jsonSave, logWrite, locale, configGet, should_quote
from modules.database import col_messages
from modules.utils import logWrite, locale, should_quote
# Message command ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"]))
async def cmd_message(app, msg):
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
if await isAnAdmin(msg.from_user.id) is True:
try:
@ -19,19 +16,13 @@ async def cmd_message(app, msg):
except ValueError:
destination = HoloUser(msg.command[1])
void = msg.command[2]
message = " ".join(msg.command[2:])
await destination.message(msg, msg.command[2:])
# try:
# new_message = await app.send_message(destination.id, message+locale("message_reply_notice", "message"))
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
# logWrite(f"Admin {msg.from_user.id} sent message '{' '.join(msg.command[2:])}' to {destination.id}")
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
# except bad_request_400.PeerIdInvalid:
# await msg.reply_text(locale("message_no_user", "message"), quote=should_quote(msg))
# logWrite(f"Admin {msg.from_user.id} tried to send message '{' '.join(msg.command[2:])}' to {destination.id} but 'PeerIdInvalid'")
if ((msg.text is not None) and (len(msg.text.split()) > 2)):
await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)):
await destination.message(context=msg, text=msg.text, caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
else:
await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
except IndexError:
await msg.reply_text(locale("message_invalid_syntax", "message"), quote=should_quote(msg))
logWrite(f"Admin {msg.from_user.id} tried to send message but 'IndexError'")

View File

@ -0,0 +1,24 @@
from app import app, isAnAdmin
from pyrogram import filters
from modules.utils import configGet, should_quote
from modules.database import col_applications
# Nearby command ===============================================================================================================
@app.on_message(~ filters.scheduled & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"]))
async def cmd_nearby(app, msg):
if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None):
await msg.reply_text("Yes, I exist.", quote=should_quote(msg))
# if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"):
# jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# if sponsor["approved"]:
# if sponsor["expires"] is not None:
# if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now():
# await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.")
# else:
# await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.")
# elif sponsor["approved"]:
# await msg.reply_text(f"Your sub expiration date is not valid.")
# else:
# await msg.reply_text(f"You have no active subscription.")
# ==============================================================================================================================

View File

@ -1,22 +1,25 @@
from app import app
from pyrogram import filters
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from modules.utils import configGet, configSet, locale
from classes.holo_user import HoloUser
from modules.utils import configGet, locale
from modules.handlers.welcome import welcome_pass
from modules.database import col_tmp
# Reapply command ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"]))
async def cmd_reapply(app, msg):
if configGet("approved", file=str(msg.from_user.id)) or configGet("refused", file=str(msg.from_user.id)):
if (configGet("stage", file=str(msg.from_user.id)) == 10) and not (configGet("sent", file=str(msg.from_user.id))):
holo_user = HoloUser(msg.from_user)
if holo_user.application_state()[0] in ["approved", "rejected"]:
if (holo_user.application_state()[1] is True) and (not col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"]):
left_chat = True
async for member in app.get_chat_members(configGet("destination_group")):
if member.user.id == msg.from_user.id:
left_chat = False
if not left_chat:
configSet(["reapply"], True, file=str(msg.from_user.id))
configSet(["confirmed"], False, file=str(msg.from_user.id))
holo_user.application_restart()
await welcome_pass(app, msg, once_again=True)
else:
await msg.reply_text(locale("reapply_left_chat", "message"), reply_markup=InlineKeyboardMarkup([
@ -34,7 +37,7 @@ async def cmd_reapply(app, msg):
]
]))
else:
if configGet("sent", file=str(msg.from_user.id)):
if (holo_user.application_state()[0] == "fill") and (col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"] is True):
await msg.reply_text(locale("reapply_forbidden", "message"))
else:
await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0]), reply_markup=InlineKeyboardMarkup([

View File

@ -2,7 +2,7 @@ from app import app, isAnAdmin
from os import getpid
from sys import exit
from pyrogram import filters
from modules.utils import configGet, logWrite, should_quote
from modules.utils import logWrite, should_quote
from modules.scheduled import scheduler
pid = getpid()
@ -11,7 +11,7 @@ pid = getpid()
@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"]))
async def cmd_kill(app, msg):
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
if await isAnAdmin(msg.from_user.id) is True:
logWrite(f"Shutting down bot with pid {pid}")
await msg.reply_text(f"Вимкнення бота з підом `{pid}`", quote=should_quote(msg))
scheduler.shutdown()

View File

@ -1,23 +1,25 @@
from datetime import datetime
from os import path, sep
from app import app
from app import app, isAnAdmin
from pyrogram import filters
from modules.utils import configGet, jsonLoad, jsonSave
from modules.utils import should_quote
from modules.database import col_applications
# Sponsorship command ==========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]))
async def cmd_sponsorship(app, msg):
if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"):
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
if sponsor["approved"]:
if sponsor["expires"] is not None:
if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now():
await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.")
else:
await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.")
elif sponsor["approved"]:
await msg.reply_text(f"Your sub expiration date is not valid.")
else:
await msg.reply_text(f"You have no active subscription.")
if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None):
await msg.reply_text("Yes, I exist.", quote=should_quote(msg))
# if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"):
# jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# if sponsor["approved"]:
# if sponsor["expires"] is not None:
# if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now():
# await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.")
# else:
# await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.")
# elif sponsor["approved"]:
# await msg.reply_text(f"Your sub expiration date is not valid.")
# else:
# await msg.reply_text(f"You have no active subscription.")
# ==============================================================================================================================

View File

@ -1,5 +1,4 @@
from app import app
from os import sep
from pyrogram import filters
from pyrogram.types import ReplyKeyboardMarkup
from modules.utils import locale, logWrite

View File

@ -1,7 +1,8 @@
from os import sep
from datetime import datetime
from app import app, isAnAdmin
from pyrogram import filters
from modules.utils import jsonLoad, jsonSave, configGet, locale
from modules.utils import configGet, locale
from modules.database import col_warnings
# Warn command =================================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"]))
@ -9,12 +10,11 @@ async def cmd_warn(app, msg):
if msg.chat.id == configGet("destination_group"):
if msg.reply_to_message_id != None:
if isAnAdmin(msg.from_user.id):
warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json")
if str(msg.reply_to_message.from_user.id) not in warnings:
warnings[str(msg.reply_to_message.from_user.id)] = 1
if await isAnAdmin(msg.from_user.id) is True:
message = " ".join(msg.command[1:]) if len(msg.command) > 1 else ""
col_warnings.insert_one({"user": msg.reply_to_message.from_user.id, "admin": msg.from_user.id, "date": datetime.now(), "reason": message})
if message == "":
await msg.reply_text(locale("warned", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id))
else:
warnings[str(msg.reply_to_message.from_user.id)] += 1
jsonSave(warnings, f"{configGet('data', 'locations')}{sep}warnings.json")
await msg.reply_text(locale("warned", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id))
await msg.reply_text(locale("warned_reason", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id, message))
# ==============================================================================================================================

View File

@ -1,24 +1,23 @@
from os import path, sep
from app import app, isAnAdmin
from pyrogram import filters
from pyrogram.enums.chat_members_filter import ChatMembersFilter
from modules.utils import configGet, jsonLoad, locale, should_quote
from modules.utils import configGet, locale, should_quote
from modules.database import col_users, col_warnings
# Warnings command =============================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"]))
async def cmd_warnings(app, msg):
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json")
if await isAnAdmin(msg.from_user.id) is True:
if len(msg.command) <= 1:
await msg.reply_text(locale("syntax_warnings", "message"), quote=should_quote(msg))
if path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json"):
target_id = str(int(msg.command[1]))
target_name = "N/A"
else:
try:
user_db = col_users.find_one({"user": int(msg.command[1])})
target_id = user_db["user"]
target_name = user_db["tg_name"]
except:
list_of_users = []
async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
list_of_users.append(m)
@ -31,11 +30,13 @@ async def cmd_warnings(app, msg):
await msg.reply_text(locale("no_user_warnings", "message").format(msg.command[1]))
return
if target_id not in warnings:
warns = len(list(col_warnings.find({"user": target_id})))
if warns == 0:
await msg.reply_text(locale("no_warnings", "message").format(target_name, target_id), quote=should_quote(msg))
else:
if warnings[target_id] <= 5:
await msg.reply_text(locale("warnings_1", "message").format(target_name, target_id, warnings[target_id]), quote=should_quote(msg))
if warns <= 5:
await msg.reply_text(locale("warnings_1", "message").format(target_name, target_id, warns), quote=should_quote(msg))
else:
await msg.reply_text(locale("warnings_2", "message").format(target_name, target_id, warnings[target_id]), quote=should_quote(msg))
await msg.reply_text(locale("warnings_2", "message").format(target_name, target_id, warns), quote=should_quote(msg))
# ==============================================================================================================================

View File

@ -25,10 +25,11 @@ db = db_client.get_database(name=db_config["name"])
collections = db.list_collection_names()
for collection in ["users", "context", "messages", "warnings", "applications", "sponsorships"]:
for collection in ["tmp", "users", "context", "messages", "warnings", "applications", "sponsorships"]:
if not collection in collections:
db.create_collection(collection)
col_tmp = db.get_collection("tmp")
col_users = db.get_collection("users")
col_context = db.get_collection("context")
col_messages = db.get_collection("messages")

View File

@ -1,99 +1,93 @@
from os import sep
from time import time
from dateutil.relativedelta import relativedelta
from datetime import datetime
from app import app
from pyrogram import filters
from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram.enums.parse_mode import ParseMode
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite
from classes.holo_user import HoloUser
from modules.utils import configGet, locale, logWrite
from modules.handlers.welcome import welcome_pass
from modules.database import col_tmp
# Confirmation =================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("confirm", "keyboard")[0][0])))
async def confirm_yes(app, msg):
user_stage = configGet("stage", file=str(msg.from_user.id))
holo_user = HoloUser(msg.from_user)
if user_stage == 10:
if (holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True):
if not configGet("sent", file=str(msg.from_user.id)):
await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove())
await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove())
tmp_application = col_tmp.find_one({"user": holo_user.id, "type": "application"})
applications = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
if tmp_application is None:
logWrite(f"Application of {holo_user.id} is nowhere to be found.")
return
applications[str(msg.from_user.id)] = {
"approved": False,
"approved_by": None,
"approval_date": None,
"refused": False,
"refused_by": False,
"refusal_date": False,
"application_date": int(time()),
"application": configGet("application", file=str(msg.from_user.id))
}
application_content = []
i = 1
jsonSave(applications, f"{configGet('data', 'locations')}{sep}applications.json")
for question in tmp_application['application']:
application_content = []
i = 1
for question in configGet("application", file=str(msg.from_user.id)):
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(msg.from_user.id))['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))['2']} ({age.years} р.)")
if i == 2:
age = relativedelta(datetime.now(), tmp_application['application']['2'])
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
elif i == 3:
if tmp_application['application']['3']['countryCode'] == "UA":
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
i += 1
if configGet("reapply", file=str(msg.from_user.id)):
await app.send_message(chat_id=configGet("admin_group"), text=(locale("reapply_got", "message")).format(str(msg.from_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
[
[
InlineKeyboardButton(text=str(locale("reapply_yes", "button")), callback_data=f"reapply_yes_{msg.from_user.id}")
],
[
InlineKeyboardButton(text=str(locale("reapply_no", "button")), callback_data=f"reapply_no_{msg.from_user.id}")
]
]
)
)
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']} ({tmp_application['application']['3']['adminName1']}, {tmp_application['application']['3']['countryName']})")
else:
await app.send_message(chat_id=configGet("admin_group"), text=(locale("application_got", "message")).format(str(msg.from_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application'][question]}")
i += 1
if tmp_application["reapply"]:
await app.send_message(chat_id=configGet("admin_group"), text=(locale("reapply_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
[
[
[
InlineKeyboardButton(text=str(locale("sub_yes", "button")), callback_data=f"sub_yes_{msg.from_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_no", "button")), callback_data=f"sub_no_{msg.from_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_no_aggressive", "button")), callback_data=f"sub_no_aggresive_{msg.from_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_no_russian", "button")), callback_data=f"sub_no_russian_{msg.from_user.id}")
]
InlineKeyboardButton(text=str(locale("reapply_yes", "button")), callback_data=f"reapply_yes_{holo_user.id}")
],
[
InlineKeyboardButton(text=str(locale("reapply_no", "button")), callback_data=f"reapply_no_{holo_user.id}")
]
)
]
)
)
else:
await app.send_message(chat_id=configGet("admin_group"), text=(locale("application_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
[
[
InlineKeyboardButton(text=str(locale("sub_yes", "button")), callback_data=f"sub_yes_{holo_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_no", "button")), callback_data=f"sub_no_{holo_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_aggressive", "button")), callback_data=f"sub_aggressive_{holo_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sub_russian", "button")), callback_data=f"sub_russian_{holo_user.id}")
]
]
)
)
logWrite(f"User {msg.from_user.id} sent his application and it will now be reviewed")
logWrite(f"User {holo_user.id} sent his application and it will now be reviewed")
configSet(["sent"], True, file=str(msg.from_user.id))
configSet(["confirmed"], True, file=str(msg.from_user.id))
col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}})
# configSet(["sent"], True, file=str(holo_user.id))
# configSet(["confirmed"], True, file=str(holo_user.id))
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("confirm", "keyboard")[1][0])))
async def confirm_no(app, msg):
user_stage = configGet("stage", file=str(msg.from_user.id))
holo_user = HoloUser(msg.from_user)
if user_stage == 10:
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json")
configSet(["telegram_id"], str(msg.from_user.username), file=str(msg.from_user.id))
configSet(["telegram_name"], f"{msg.from_user.first_name} {msg.from_user.last_name}", file=str(msg.from_user.id))
configSet(["telegram_phone"], str(msg.from_user.phone_number), file=str(msg.from_user.id))
configSet(["telegram_locale"], str(msg.from_user.language_code), file=str(msg.from_user.id))
if (holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True):
holo_user.application_restart()
await welcome_pass(app, msg, once_again=True)
logWrite(f"User {msg.from_user.id} restarted the application due to typo in it")
# ==============================================================================================================================

View File

@ -1,47 +1,53 @@
from os import sep, path
from dateutil.relativedelta import relativedelta
from datetime import datetime
from app import app, isAnAdmin
from pyrogram import filters
from modules.utils import configGet, jsonLoad, locale, logWrite
from modules.utils import locale, logWrite
from modules.database import col_applications
from classes.holo_user import HoloUser
# Contact getting ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.contact & filters.private)
async def get_contact(app, msg):
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json")["approved"]) or (await isAnAdmin(msg.from_user.id)):
holo_user = HoloUser(msg.from_user)
if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True):
if msg.contact.user_id != None:
try:
user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.contact.user_id}.json")
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(msg.contact.user_id)]
application_content = []
i = 1
for question in application["application"]:
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}")
i += 1
if user_data["sent"]:
if user_data["approved"]:
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
elif application["refused"]:
application_status = locale("application_status_refused", "message").format((await app.get_users(application["refused_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
else:
application_status = locale("application_status_on_hold", "message")
else:
if user_data["approved"]:
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
elif application["refused"]:
application_status = locale("application_status_refused", "message").format((await app.get_users(application["refused_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
else:
application_status = locale("application_status_not_send", "message")
logWrite(f"User {msg.from_user.id} requested application of {msg.contact.user_id}")
await msg.reply_text(locale("contact", "message").format(str(msg.contact.user_id), "\n".join(application_content), application_status))
except FileNotFoundError:
logWrite(f"User {msg.from_user.id} requested application of {msg.contact.user_id} but user does not exists")
application = col_applications.find_one({"user": msg.contact.user_id})
if application is None:
logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists")
await msg.reply_text(locale("contact_invalid", "message"))
return
application_content = []
i = 1
for question in application['application']:
if i == 2:
age = relativedelta(datetime.now(), application['application']['2'])
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
elif i == 3:
if application['application']['3']['countryCode'] == "UA":
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}")
else:
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
else:
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}")
i += 1
application_status = locale("application_status_accepted", "message").format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M"))
logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id}")
await msg.reply_text(locale("contact", "message").format(str(msg.contact.user_id), "\n".join(application_content), application_status))
else:
logWrite(f"User {msg.from_user.id} requested application of someone but user is not telegram user")
logWrite(f"User {holo_user.id} requested application of someone but user is not telegram user")
await msg.reply_text(locale("contact_not_member", "message"))
# ==============================================================================================================================

View File

@ -1,10 +1,9 @@
from datetime import datetime
from os import sep
from app import app, isAnAdmin
import asyncio
from pyrogram import filters
from pyrogram.types import ForceReply, ReplyKeyboardMarkup, Message
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite, should_quote
from pyrogram.types import Message
from classes.holo_user import HoloUser
from modules.utils import configGet, logWrite
from modules.database import col_messages
async def message_involved(msg: Message) -> bool:
@ -20,78 +19,96 @@ async def message_context(msg: Message) -> tuple:
return 0, 0
# Any other input ==============================================================================================================
# @app.on_message(~ filters.scheduled & filters.private)
# async def any_stage(app, msg):
@app.on_message(~ filters.scheduled & filters.private)
async def any_stage(app, msg):
# if msg.via_bot is None:
if msg.via_bot is None:
# if (msg.reply_to_message != None) and (await message_involved(msg)):
# context = await message_context(msg)
# if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
# new_message = await (await app.get_messages(context[0], context[1])).reply_text(msg.text+locale("message_reply_notice", "message"), quote=True)
# else:
# new_message = await (await app.get_messages(context[0], context[1])).reply_text(locale("message_from", "message").format(msg.from_user.first_name, msg.from_user.id)+msg.text+locale("message_reply_notice", "message"), quote=True)
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
# return
holo_user = HoloUser(msg.from_user)
# user_stage = configGet("stage", file=str(msg.from_user.id))
if (msg.reply_to_message is not None) and (await message_involved(msg)):
context = await message_context(msg)
context_message = await app.get_messages(context[0], context[1])
destination_user = HoloUser(context_message.from_user)
await destination_user.message(
origin=context_message,
context=msg,
text=msg.text,
caption=msg.caption,
photo=msg.photo,
video=msg.video,
file=msg.document,
adm_origin=await isAnAdmin(context_message.from_user.id),
adm_context=await isAnAdmin(msg.from_user.id)
)
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
return
await holo_user.application_next(msg.text, msg=msg)
# user_stage = configGet("stage", file=str(msg.from_user.id))
# if user_stage == 1:
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# if user_stage == 1:
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# elif user_stage == 2:
# elif user_stage == 2:
# try:
# try:
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
# input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
# if datetime.now() <= input_dt:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
# await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# if datetime.now() <= input_dt:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
# await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
# await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
# await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# else:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# else:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# except ValueError:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
# await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
# except ValueError:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
# await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
# else:
# if user_stage <= 9:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# else:
# if not configGet("sent", file=str(msg.from_user.id)):
# if not configGet("confirmed", file=str(msg.from_user.id)):
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# application_content = []
# i = 1
# for question in configGet("application", file=str(msg.from_user.id)):
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
# i += 1
# await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True))
# #configSet("sent", True, file=str(msg.from_user.id))
# #configSet("application_date", int(time()), file=str(msg.from_user.id))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("refused", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("refused", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
# else:
# if user_stage <= 9:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# else:
# if not configGet("sent", file=str(msg.from_user.id)):
# if not configGet("confirmed", file=str(msg.from_user.id)):
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# application_content = []
# i = 1
# for question in configGet("application", file=str(msg.from_user.id)):
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
# i += 1
# await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True))
# #configSet("sent", True, file=str(msg.from_user.id))
# #configSet("application_date", int(time()), file=str(msg.from_user.id))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("rejected", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("rejected", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
@app.on_message(~ filters.scheduled & filters.group)
async def message_in_group(app, msg):

View File

@ -1,25 +1,35 @@
from os import sep, path
from app import app, isAnAdmin
from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton
from modules.utils import configGet, jsonLoad, locale
from modules.utils import configGet, locale
from modules.logging import logWrite
from classes.holo_user import HoloUser
# Filter users on join =========================================================================================================
@app.on_chat_member_updated(group=configGet("destination_group"))
#@app.on_message(filters.new_chat_members, group=configGet("destination_group"))
async def filter_join(app, member):
if member.invite_link != None:
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json")["approved"]) or (await isAnAdmin(member.from_user.id)):
if configGet("link", file=str(member.from_user.id)) == member.invite_link.invite_link:
return
if await isAnAdmin(member.invite_link.creator.id):
holo_user = HoloUser(member.from_user)
if (holo_user.link is not None) and (holo_user.link == member.invite_link.invite_link):
logWrite(f"User {holo_user.id} joined destination group with correct link {holo_user.link}")
return
await app.send_message(configGet("admin_group"), f"User **{member.from_user.first_name}** (`{member.from_user.id}`) joined the chat not with his personal link", reply_markup=InlineKeyboardMarkup(
if await isAnAdmin(member.invite_link.creator.id):
logWrite(f"User {holo_user.id} joined destination group with link {holo_user.link} of an admin {member.invite_link.creator.id}")
return
logWrite(f"User {holo_user.id} joined destination group with stolen/unapproved link {holo_user.link}")
await app.send_message(configGet("admin_group"), locale("joined_false_link", "message").format(member.from_user.first_name, member.from_user.id), reply_markup=InlineKeyboardMarkup(
[
[
InlineKeyboardButton(text=str(locale("sus_allow", "button")), callback_data=f"sus_allow_{member.from_user.id}")
],
[
InlineKeyboardButton(text=str(locale("sus_refuse", "button")), callback_data=f"sus_refuse_{member.from_user.id}")
InlineKeyboardButton(text=str(locale("sus_reject", "button")), callback_data=f"sus_reject_{member.from_user.id}")
]
]
))

View File

@ -1,8 +1,7 @@
from app import app
from pyrogram import filters
from pyrogram.types import ForceReply, ReplyKeyboardMarkup
from classes.holo_user import HoloUser
from modules.utils import configGet, configSet, locale, logWrite
from modules.utils import locale, logWrite
# Welcome check ================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("welcome", "keyboard")[0][0]) | filters.regex(locale("return", "keyboard")[0][0])))
@ -15,19 +14,17 @@ async def welcome_pass(app, msg, once_again: bool = True) -> None:
* once_again (bool, optional): Set to False if it's the first time as user applies. Defaults to True.
"""
holo_user = HoloUser(msg.from_user)
if not once_again:
await msg.reply_text(locale("privacy_notice", "message"))
logWrite(f"User {msg.from_user.id} confirmed starting the application")
await msg.reply_text(locale("question1", "message"), reply_markup=ForceReply(placeholder=locale("question1", "force_reply")))
configSet(["stage"], 1, file=str(msg.from_user.id))
configSet(["sent"], False, file=str(msg.from_user.id))
# configSet(["stage"], 1, file=str(msg.from_user.id))
# configSet(["sent"], False, file=str(msg.from_user.id))
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("welcome", "keyboard")[1][0])))
async def welcome_reject(app, msg):
logWrite(f"User {msg.from_user.id} refused to start the application")
logWrite(f"User {msg.from_user.id} rejected to start the application")
await msg.reply_text(locale("goodbye", "message"), reply_markup=ReplyKeyboardMarkup(locale("return", "keyboard"), resize_keyboard=True))
# ==============================================================================================================================

View File

@ -1,12 +1,13 @@
from datetime import datetime
from os import path, sep
from app import app, isAnAdmin
from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent
from pyrogram.enums.chat_type import ChatType
from pyrogram.enums.chat_members_filter import ChatMembersFilter
from dateutil.relativedelta import relativedelta
from app import app, isAnAdmin
from modules.utils import configGet, jsonLoad, locale
from classes.holo_user import HoloUser, UserInvalidError, UserNotFoundError
from modules.utils import configGet, locale
from modules.database import col_applications
@app.on_inline_query()
async def inline_answer(client, inline_query):
@ -25,7 +26,23 @@ async def inline_answer(client, inline_query):
)
return
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{inline_query.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{inline_query.from_user.id}.json")["approved"]) or (await isAnAdmin(inline_query.from_user.id)):
try:
holo_user = HoloUser(inline_query.from_user)
except (UserNotFoundError, UserInvalidError):
await inline_query.answer(
results=[
InlineQueryResultArticle(
title=locale("title", "inline", "forbidden"),
input_message_content=InputTextMessageContent(
locale("message_content", "inline", "forbidden")
),
description=locale("description", "inline", "forbidden")
)
]
)
return
if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True):
list_of_users = []
async for m in app.get_chat_members(configGet("destination_group"), limit=configGet("inline_preview_count"), filter=ChatMembersFilter.SEARCH, query=inline_query.query):
@ -33,26 +50,30 @@ async def inline_answer(client, inline_query):
results = []
applications = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
for match in list_of_users:
try:
application_content = []
i = 1
for question in applications[str(match.user.id)]["application"]:
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(applications[str(match.user.id)]['application']['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {applications[str(match.user.id)]['application']['2']} ({age.years} р.)")
application = col_applications.find_one({"user": match.user.id})
if application is None:
continue
application_content = []
i = 1
for question in application['application']:
if i == 2:
age = relativedelta(datetime.now(), application['application']['2'])
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
elif i == 3:
if application['application']['3']['countryCode'] == "UA":
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {applications[str(match.user.id)]['application'][question]}")
i += 1
except KeyError:
continue
except FileNotFoundError:
continue
except TypeError:
continue
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
else:
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}")
i += 1
if match.user.photo != None:
try:
@ -104,17 +125,3 @@ async def inline_answer(client, inline_query):
results=results,
cache_time=10
)
else:
await inline_query.answer(
results=[
InlineQueryResultArticle(
title=locale("title", "inline", "forbidden"),
input_message_content=InputTextMessageContent(
locale("message_content", "inline", "forbidden")
),
description=locale("description", "inline", "forbidden")
)
]
)
return

View File

@ -13,6 +13,11 @@ with open(getcwd()+path.sep+"config.json", "r", encoding='utf8') as file:
# Check latest log size
def checkSize(debug=False):
"""Check size of latest.log file and rotate it if needed
### Args:
* debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`.
"""
global log_folder
@ -35,7 +40,13 @@ def checkSize(debug=False):
pass
# Append string to log
def logAppend(message, debug=False):
def logAppend(message: str, debug=False):
"""Write message to log file
### Args:
* message (`str`): Message to write
* debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`.
"""
global log_folder
@ -52,7 +63,13 @@ def logAppend(message, debug=False):
log.close()
# Print to stdout and then to log
def logWrite(message, debug=False):
def logWrite(message: str, debug=False):
"""Write message to stdout and log file
### Args:
* message (`str`): Message to print and write
* debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`.
"""
# save to log file and rotation is to be done
logAppend(f'{message}', debug=debug)
print(f"{message}", flush=True)

View File

@ -1,8 +1,7 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from datetime import datetime
from os import fsdecode, listdir, sep
from app import app
from modules.utils import configGet, jsonLoad, locale, logWrite
from modules.utils import configGet, locale, logWrite
from dateutil.relativedelta import relativedelta
from modules.database import col_applications
@ -23,10 +22,15 @@ scheduler = AsyncIOScheduler()
if configGet("enabled", "scheduler", "birthdays"):
@scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "birthdays"))
async def check_birthdays():
for entry in col_applications.find({"2": datetime.now().strftime("%d.%m.%Y")}):
tg_user = await app.get_users(entry["user"])
await app.send_message( configGet("admin_group"), locale("birthday", "message").format(str(tg_user.first_name), str(tg_user.username), str(relativedelta(datetime.now(), datetime.strptime(entry["2"], '%d.%m.%Y')).years)) ) # type: ignore
logWrite(f"Notified admins about {entry['user']}'s birthday")
for entry in col_applications.find():
if entry["application"]["2"].strftime("%d.%m") == datetime.now().strftime("%d.%m"):
try:
tg_user = await app.get_users(entry["user"])
await app.send_message( configGet("admin_group"), locale("birthday", "message").format(str(tg_user.first_name), str(tg_user.username), str(relativedelta(datetime.now(), entry["application"]["2"], '%d.%m.%Y').years)) ) # type: ignore
logWrite(f"Notified admins about {entry['user']}'s birthday")
except Exception as exp:
logWrite(f"Could not find user {entry['user']} to send a message about birthday due to '{exp}'")
continue
logWrite("Birthdays check performed")
if configGet("enabled", "scheduler", "sponsorships"):

View File

@ -3,6 +3,7 @@ fastapi==0.88.0
psutil==5.9.4
pymongo==4.3.3
Pyrogram==2.0.69
requests==2.28.1
tgcrypto==1.2.5
python_dateutil==2.8.2
starlette==0.22.0