Merge Beta with Stable releases #1

Merged
profitroll merged 52 commits from dev into master 2022-12-16 16:14:41 +02:00
31 changed files with 931 additions and 537 deletions

7
.gitignore vendored
View File

@ -157,11 +157,8 @@ config.json
config_debug.json config_debug.json
*.session *.session
*.session-journal *.session-journal
users data
!users/.gitkeep
TASK.md TASK.md
inline_bot.py 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 * Give one-time links to join group
* Track down users that were not allowed to join * Track down users that were not allowed to join
* Show applications to other users * Show applications to other users
* Manage YouTube sponsorships [WIP]
* Send and receive messages to users using bot [WIP]
## Installation ## Installation
@ -32,8 +34,6 @@ You can see config file with all the comments below:
"owner": 0, "owner": 0,
"bot_id": 0, "bot_id": 0,
"age_allowed": 0, "age_allowed": 0,
"birthdays_notify": true,
"birthdays_time": "09:00",
"api": "http://example.com", "api": "http://example.com",
"inline_preview_count": 7, "inline_preview_count": 7,
"admin_group": 0, "admin_group": 0,
@ -45,22 +45,43 @@ You can see config file with all the comments below:
"api_hash": "", "api_hash": "",
"bot_token": "" "bot_token": ""
}, },
"database": {
"user": null,
"password": null,
"host": "127.0.0.1",
"port": 27017,
"name": "holochecker"
},
"geocoding": {
"username": "demo"
},
"logging": { "logging": {
"size": 512, "size": 512,
"location": "logs" "location": "logs"
}, },
"scheduler": {
"birthdays": {
"time": 9,
"enabled": true
},
"sponsorships": {
"time": 9,
"enabled": true
}
},
"locations": { "locations": {
"data": "data",
"cache": "cache", "cache": "cache",
"locale": "locale" "locale": "locale"
}, },
"commands": { "commands": {
"rules": "Check out the rules", "rules": "Check out the rules",
"reapply": "Resubmit the application" "reapply": "Resubmit the application",
"sponsorship": "Apply for sponsor role"
}, },
"commands_admin": { "commands_admin": {
"reboot": "Restart the bot", "reboot": "Restart the bot",
"message": "Send a message", "message": "Send a message",
"label": "Set user's nickname",
"warnings": "Check user's warnings", "warnings": "Check user's warnings",
"application": "Check user's application", "application": "Check user's application",
"applications": "Retrieve all applications as a JSON" "applications": "Retrieve all applications as a JSON"
@ -68,6 +89,7 @@ You can see config file with all the comments below:
"commands_group_admin": { "commands_group_admin": {
"reboot": "Restart the bot", "reboot": "Restart the bot",
"message": "Send a message", "message": "Send a message",
"label": "Set user's nickname",
"warnings": "Check user's warnings", "warnings": "Check user's warnings",
"application": "Check user's application", "application": "Check user's application",
"applications": "Retrieve all applications as a JSON" "applications": "Retrieve all applications as a JSON"
@ -82,6 +104,6 @@ After all of that you're good to go! Happy using :)
## To-Do ## To-Do
* [ ] Complete messenger between user and admins * [x] Complete messenger between user and admins
* [ ] Check sponsorship on Holo girls * [ ] Check sponsorship on Holo girls
* [ ] Get application by id and user_id * [ ] 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 modules.utils import configGet
from pyrogram.client import Client 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")) 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): async def isAnAdmin(admin_id):
if (admin_id == configGet("owner")) or (admin_id in configGet("admins")): if (admin_id == configGet("owner")) or (admin_id in configGet("admins")):
return True return True
async for member in app.get_chat_members(configGet("admin_group")): try:
if member.user.id == admin_id: async for member in app.get_chat_members(configGet("admin_group")):
return True 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 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 app import app, isAnAdmin
from typing import Any, List, Union from typing import Any, List, Literal, Union
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup
from pyrogram.client import Client
from pyrogram.errors import bad_request_400 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.logging import logWrite
from modules.utils import configGet, locale, should_quote 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): class UserNotFoundError(Exception):
"""HoloUser could not find user with such an ID in database""" """HoloUser could not find user with such an ID in database"""
def __init__(self, user, user_id): 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") super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type")
class HoloUser(): 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 # Determine input object class and extract id
if isinstance(user, list) and len(user) != 0: if isinstance(user, list) and len(user) != 0:
@ -33,13 +74,14 @@ class HoloUser():
self.id = user.user.id self.id = user.user.id
elif isinstance(user, int): elif isinstance(user, int):
self.id = user self.id = user
elif isinstance(user, str): # elif isinstance(user, str):
try: # try:
self.id = (app.get_users(user)).id # this line requires testing though # get_users = async_to_sync(app.get_users)
except bad_request_400.UsernameNotOccupied: # self.id = get_users(user).id # this line requires testing though
raise UserInvalidError(user) # except bad_request_400.UsernameNotOccupied:
except bad_request_400.PeerIdInvalid: # raise UserInvalidError(user)
raise UserInvalidError(user) # except bad_request_400.PeerIdInvalid:
# raise UserInvalidError(user)
else: else:
raise UserInvalidError(user) raise UserInvalidError(user)
@ -71,35 +113,268 @@ class HoloUser():
col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { key: value } }, upsert=True) 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}") 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): async def message(self,
new_message = await app.send_message(self.id, text+locale("message_reply_notice", "message")) context: Message,
await origin.reply_text(locale("message_sent", "message"), quote=should_quote(origin)) origin: Union[Message, None] = None,
logWrite(f"Admin {origin.from_user.id} sent message '{' '.join(origin.command[2:])}' to {self.id}") text: Union[str, None] = None,
col_messages.insert_one({"origin": {"chat": origin.chat.id, "id": origin.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}}) 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 """Set label in destination group
### Args: ### Args:
* app (`Client`): Pyrogram client * chat (`Chat`): Telegram chat
* label (`str`): Label you want to set * label (`str`): Label you want to set
""" """
self.label = label self.label = label
self.set("label", label) self.set("label", label)
await app.promote_chat_member(configGet("destination_group"), self.id) 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) 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 """Reset label in destination group
### Args: ### Args:
* app (`Client`): Pyrogram client * chat (`Chat`): Telegram chat
""" """
self.label = "" self.label = ""
self.set("label", "") self.set("label", "")
await app.set_administrator_title(configGet("destination_group"), self.id, "") 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( await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges(
can_manage_chat=False 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, "port": 27017,
"name": "holochecker" "name": "holochecker"
}, },
"geocoding": {
"username": "demo"
},
"logging": { "logging": {
"size": 512, "size": 512,
"location": "logs" "location": "logs"
@ -42,6 +45,7 @@
}, },
"commands": { "commands": {
"rules": "Check out the rules", "rules": "Check out the rules",
"nearby": "Show users near the area",
"reapply": "Resubmit the application", "reapply": "Resubmit the application",
"sponsorship": "Apply for sponsor role" "sponsorship": "Apply for sponsor role"
}, },
@ -57,11 +61,13 @@
"reboot": "Restart the bot", "reboot": "Restart the bot",
"message": "Send a message", "message": "Send a message",
"label": "Set user's nickname", "label": "Set user's nickname",
"nearby": "Show users near the area",
"warnings": "Check user's warnings", "warnings": "Check user's warnings",
"application": "Check user's application", "application": "Check user's application",
"applications": "Retrieve all applications as a JSON" "applications": "Retrieve all applications as a JSON"
}, },
"commands_group_destination": { "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.applications import *
from modules.commands.label import * from modules.commands.label import *
from modules.commands.message import * from modules.commands.message import *
from modules.commands.nearby import *
from modules.commands.reapply import * from modules.commands.reapply import *
from modules.commands.reboot import * from modules.commands.reboot import *
from modules.commands.rules import * from modules.commands.rules import *

View File

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

View File

@ -1,93 +1,82 @@
from os import sep from datetime import datetime
from time import time
from app import app from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove
from pyrogram import filters 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.confirmation import confirm_yes
from modules.handlers.welcome import welcome_pass from modules.handlers.welcome import welcome_pass
from modules.database import col_tmp, col_applications
# Callbacks reapply ============================================================================================================ # Callbacks reapply ============================================================================================================
@app.on_callback_query(filters.regex("reapply_yes_[\s\S]*")) @app.on_callback_query(filters.regex("reapply_yes_[\s\S]*"))
async def callback_reapply_query_accept(app, clb): async def callback_reapply_query_accept(app, clb):
fullclb = clb.data.split("_") 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) 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 {fullclb[2]} got their reapplication approved by {clb.from_user.id}") 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]) col_applications.delete_one({"user": {"$eq": holo_user.id}})
configSet(["sent"], False, file=fullclb[2]) 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}})
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")
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] 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.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 need_link = True
async for member in app.get_chat_members(configGet("destination_group")): 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 need_link = False
if need_link: 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"): 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) InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]] ]]
)) ))
configSet(["link"], link.invite_link, file=fullclb[2]) holo_user.set("link", link.invite_link)
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}") logWrite(f"User {holo_user.id} got an invite link {link.invite_link}")
else: 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]*")) @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("_") 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(configGet("admin_group"), locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
await app.send_message(int(fullclb[2]), locale("refused", "message")) await app.send_message(holo_user.id, locale("rejected", "message"))
logWrite(f"User {fullclb[2]} got their reapplication refused by {clb.from_user.id}") logWrite(f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}")
configSet(["refused"], True, file=fullclb[2]) col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
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")
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]] 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.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 # Use old application when user reapplies after leaving the chat
@app.on_callback_query(filters.regex("reapply_old_[\s\S]*")) @app.on_callback_query(filters.regex("reapply_old_[\s\S]*"))
async def callback_query_reapply_old(app, clb): async def callback_query_reapply_old(app, clb):
fullclb = clb.data.split("_") fullclb = clb.data.split("_")
message = await app.get_messages(clb.from_user.id, int(fullclb[2])) 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 confirm_yes(app, message)
await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button"), "nothing")]])) 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("_") 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")) await clb.answer(locale("reapply_stopped", "callback"))
message = await app.get_messages(clb.from_user.id, int(fullclb[2])) message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
await welcome_pass(app, message, once_again=True) 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): async def callback_query_reapply_stop(app, clb):
fullclb = clb.data.split("_") 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") holo_user.application_restart()
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")) await clb.answer(locale("reapply_stopped", "callback"))
message = await app.get_messages(clb.from_user.id, int(fullclb[2])) message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
await welcome_pass(app, message, once_again=True) await welcome_pass(app, message, once_again=True)

View File

@ -1,126 +1,103 @@
from os import sep from datetime import datetime
from time import time
from app import app from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram import filters 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 ======================================================================================================== # Callbacks application ========================================================================================================
@app.on_callback_query(filters.regex("sub_yes_[\s\S]*")) @app.on_callback_query(filters.regex("sub_yes_[\s\S]*"))
async def callback_query_accept(app, clb): async def callback_query_accept(app, clb):
fullclb = clb.data.split("_") 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) 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 {fullclb[2]} got approved by {clb.from_user.id}") logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}")
need_link = True need_link = True
async for member in app.get_chat_members(configGet("destination_group")): 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 need_link = False
if need_link: 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(holo_user.id, locale("rules_msg"), disable_web_page_preview=True, reply_markup=default_rules_markup)
await app.send_message(int(fullclb[2]), 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) InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]] ]]
)) ))
configSet(["link"], link.invite_link, file=fullclb[2]) holo_user.set("link", link.invite_link)
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}") logWrite(f"User {holo_user.id} got an invite link {link.invite_link}")
else: 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]) 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"]})
configSet(["sent"], False, file=fullclb[2]) col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}})
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")
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] 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.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)
@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)
@app.on_callback_query(filters.regex("sub_no_[\s\S]*")) @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("_") 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(configGet("admin_group"), locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
await app.send_message(int(fullclb[2]), locale("refused", "message")) await app.send_message(holo_user.id, locale("rejected", "message"))
logWrite(f"User {fullclb[2]} got refused by {clb.from_user.id}") logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id}")
configSet(["refused"], True, file=fullclb[2]) col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
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")
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]] 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.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 app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions
from pyrogram import filters 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 ========================================================================================================== # Callbacks sus users ==========================================================================================================
@app.on_callback_query(filters.regex("sus_allow_[\s\S]*")) @app.on_callback_query(filters.regex("sus_allow_[\s\S]*"))
async def callback_query_sus_allow(app, clb): async def callback_query_sus_allow(app, clb):
fullclb = clb.data.split("_") 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) 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 {fullclb[2]} was allowed to join with another link by {clb.from_user.id}") 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")]] 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.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_messages=True,
can_send_media_messages=True, can_send_media_messages=True,
can_send_other_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]*")) @app.on_callback_query(filters.regex("sus_reject_[\s\S]*"))
async def callback_query_sus_refuse(app, clb): async def callback_query_sus_reject(app, clb):
fullclb = clb.data.split("_") 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) 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 {fullclb[2]} was refused to join with another link by {clb.from_user.id}") 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.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") col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
configSet(["stage"], 10, file=fullclb[2])
configSet(["refused"], True, file=fullclb[2])
configSet(["refused_by"], clb.from_user.id, file=fullclb[2])
# ============================================================================================================================== # ==============================================================================================================================

View File

@ -1,55 +1,95 @@
from os import sep, path
from datetime import datetime from datetime import datetime
from app import app, isAnAdmin from app import app, isAnAdmin
from pyrogram import filters from pyrogram import filters
from pyrogram.enums.chat_members_filter import ChatMembersFilter from pyrogram.enums.parse_mode import ParseMode
from modules.utils import configGet, jsonLoad, logWrite, locale, should_quote 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 dateutil.relativedelta import relativedelta
from modules.database import col_applications
# Applications command ========================================================================================================= # Applications command =========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"]))
async def cmd_application(app, msg): 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: 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: try:
user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json") holo_user = HoloUser(int(msg.command[1]))
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)] except (ValueError, UserNotFoundError):
application_content = [] try:
i = 1 holo_user = HoloUser((await app.get_users(msg.command[1])).id)
for question in configGet("application", file=str(msg.from_user.id)): except (bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid):
if i == 2: await msg.reply_text(locale("no_user_application", "message").format(msg.command[1]), quote=should_quote(msg))
age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y')) return
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)")
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: else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}") application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
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: else:
if user_data["approved"]: application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}")
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"]: i += 1
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_accepted", "message").format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M"))
application_status = locale("application_status_not_send", "message")
logWrite(f"User {msg.from_user.id} requested application of {user_id}") logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}")
await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), quote=should_quote(msg)) 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))
except FileNotFoundError:
logWrite(f"User {msg.from_user.id} requested application of {user_id} but user does not exists") # 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"]):
await msg.reply_text(locale("contact_invalid", "message"), quote=should_quote(msg)) # 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: except IndexError:
await msg.reply_text(locale("application_invalid_syntax", "message"), quote=should_quote(msg)) 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 app import app, isAnAdmin
from pyrogram import filters from pyrogram import filters
from pyrogram.enums.chat_action import ChatAction 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 from modules.database import col_applications
# Applications command ========================================================================================================= # Applications command =========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"]))
async def cmd_applications(app, msg): 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) await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
filename = uuid1() filename = uuid1()
output = [] output = []
for entry in col_applications.find(): 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) output.append(entry)
makedirs("tmp", exist_ok=True) makedirs("tmp", exist_ok=True)
jsonSave(output, f"tmp{sep}{filename}.json") jsonSave(output, f"tmp{sep}{filename}.json")

View File

@ -1,13 +1,12 @@
from app import app, isAnAdmin from app import app, isAnAdmin
from pyrogram import filters from pyrogram import filters
from pyrogram.types import ChatPrivileges from modules.utils import should_quote, find_user
from modules.utils import should_quote, find_user, configGet
from classes.holo_user import HoloUser from classes.holo_user import HoloUser
@app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"]))
async def cmd_label(app, msg): 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: if len(msg.command) < 3:
await msg.reply_text("Invalid syntax:\n`/label USER LABEL`") 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 app import app, isAnAdmin
from pyrogram import filters from pyrogram import filters
from pyrogram.errors import bad_request_400
from classes.holo_user import HoloUser from classes.holo_user import HoloUser
from modules.utils import jsonLoad, jsonSave, logWrite, locale, configGet, should_quote from modules.utils import logWrite, locale, should_quote
from modules.database import col_messages
# Message command ============================================================================================================== # Message command ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"]))
async def cmd_message(app, msg): 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: try:
@ -19,19 +16,13 @@ async def cmd_message(app, msg):
except ValueError: except ValueError:
destination = HoloUser(msg.command[1]) destination = HoloUser(msg.command[1])
void = msg.command[2] if ((msg.text is not None) and (len(msg.text.split()) > 2)):
message = " ".join(msg.command[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)
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'")
except IndexError: except IndexError:
await msg.reply_text(locale("message_invalid_syntax", "message"), quote=should_quote(msg)) 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'") 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 app import app
from pyrogram import filters from pyrogram import filters
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 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.handlers.welcome import welcome_pass
from modules.database import col_tmp
# Reapply command ============================================================================================================== # Reapply command ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"]))
async def cmd_reapply(app, msg): async def cmd_reapply(app, msg):
if configGet("approved", file=str(msg.from_user.id)) or configGet("refused", file=str(msg.from_user.id)): holo_user = HoloUser(msg.from_user)
if (configGet("stage", file=str(msg.from_user.id)) == 10) and not (configGet("sent", file=str(msg.from_user.id))):
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 left_chat = True
async for member in app.get_chat_members(configGet("destination_group")): async for member in app.get_chat_members(configGet("destination_group")):
if member.user.id == msg.from_user.id: if member.user.id == msg.from_user.id:
left_chat = False left_chat = False
if not left_chat: if not left_chat:
configSet(["reapply"], True, file=str(msg.from_user.id)) holo_user.application_restart()
configSet(["confirmed"], False, file=str(msg.from_user.id))
await welcome_pass(app, msg, once_again=True) await welcome_pass(app, msg, once_again=True)
else: else:
await msg.reply_text(locale("reapply_left_chat", "message"), reply_markup=InlineKeyboardMarkup([ await msg.reply_text(locale("reapply_left_chat", "message"), reply_markup=InlineKeyboardMarkup([
@ -34,7 +37,7 @@ async def cmd_reapply(app, msg):
] ]
])) ]))
else: 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")) await msg.reply_text(locale("reapply_forbidden", "message"))
else: else:
await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0]), reply_markup=InlineKeyboardMarkup([ 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 os import getpid
from sys import exit from sys import exit
from pyrogram import filters from pyrogram import filters
from modules.utils import configGet, logWrite, should_quote from modules.utils import logWrite, should_quote
from modules.scheduled import scheduler from modules.scheduled import scheduler
pid = getpid() pid = getpid()
@ -11,7 +11,7 @@ pid = getpid()
@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"]))
async def cmd_kill(app, msg): 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}") logWrite(f"Shutting down bot with pid {pid}")
await msg.reply_text(f"Вимкнення бота з підом `{pid}`", quote=should_quote(msg)) await msg.reply_text(f"Вимкнення бота з підом `{pid}`", quote=should_quote(msg))
scheduler.shutdown() scheduler.shutdown()

View File

@ -1,23 +1,25 @@
from datetime import datetime from datetime import datetime
from os import path, sep from app import app, isAnAdmin
from app import app
from pyrogram import filters 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 ========================================================================================================== # Sponsorship command ==========================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]))
async def cmd_sponsorship(app, msg): async def cmd_sponsorship(app, msg):
if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None):
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") await msg.reply_text("Yes, I exist.", quote=should_quote(msg))
sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"):
if sponsor["approved"]: # jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
if sponsor["expires"] is not None: # sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now(): # if sponsor["approved"]:
await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.") # if sponsor["expires"] is not None:
else: # if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now():
await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.") # await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.")
elif sponsor["approved"]: # else:
await msg.reply_text(f"Your sub expiration date is not valid.") # await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.")
else: # elif sponsor["approved"]:
await msg.reply_text(f"You have no active subscription.") # 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 app import app
from os import sep
from pyrogram import filters from pyrogram import filters
from pyrogram.types import ReplyKeyboardMarkup from pyrogram.types import ReplyKeyboardMarkup
from modules.utils import locale, logWrite 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 app import app, isAnAdmin
from pyrogram import filters 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 ================================================================================================================= # Warn command =================================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"])) @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.chat.id == configGet("destination_group"):
if msg.reply_to_message_id != None: if msg.reply_to_message_id != None:
if isAnAdmin(msg.from_user.id): if await isAnAdmin(msg.from_user.id) is True:
warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json") message = " ".join(msg.command[1:]) if len(msg.command) > 1 else ""
if str(msg.reply_to_message.from_user.id) not in warnings: col_warnings.insert_one({"user": msg.reply_to_message.from_user.id, "admin": msg.from_user.id, "date": datetime.now(), "reason": message})
warnings[str(msg.reply_to_message.from_user.id)] = 1 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: else:
warnings[str(msg.reply_to_message.from_user.id)] += 1 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))
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))
# ============================================================================================================================== # ==============================================================================================================================

View File

@ -1,24 +1,23 @@
from os import path, sep
from app import app, isAnAdmin from app import app, isAnAdmin
from pyrogram import filters from pyrogram import filters
from pyrogram.enums.chat_members_filter import ChatMembersFilter 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 ============================================================================================================= # Warnings command =============================================================================================================
@app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"])) @app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"]))
async def cmd_warnings(app, msg): async def cmd_warnings(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:
warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json")
if len(msg.command) <= 1: if len(msg.command) <= 1:
await msg.reply_text(locale("syntax_warnings", "message"), quote=should_quote(msg)) 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"): try:
target_id = str(int(msg.command[1])) user_db = col_users.find_one({"user": int(msg.command[1])})
target_name = "N/A" target_id = user_db["user"]
else: target_name = user_db["tg_name"]
except:
list_of_users = [] list_of_users = []
async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
list_of_users.append(m) 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])) await msg.reply_text(locale("no_user_warnings", "message").format(msg.command[1]))
return 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)) await msg.reply_text(locale("no_warnings", "message").format(target_name, target_id), quote=should_quote(msg))
else: else:
if warnings[target_id] <= 5: if warns <= 5:
await msg.reply_text(locale("warnings_1", "message").format(target_name, target_id, warnings[target_id]), quote=should_quote(msg)) await msg.reply_text(locale("warnings_1", "message").format(target_name, target_id, warns), quote=should_quote(msg))
else: 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() 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: if not collection in collections:
db.create_collection(collection) db.create_collection(collection)
col_tmp = db.get_collection("tmp")
col_users = db.get_collection("users") col_users = db.get_collection("users")
col_context = db.get_collection("context") col_context = db.get_collection("context")
col_messages = db.get_collection("messages") 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 dateutil.relativedelta import relativedelta
from datetime import datetime from datetime import datetime
from app import app from app import app
from pyrogram import filters from pyrogram import filters
from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram.enums.parse_mode import ParseMode 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.handlers.welcome import welcome_pass
from modules.database import col_tmp
# Confirmation ================================================================================================================= # Confirmation =================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("confirm", "keyboard")[0][0]))) @app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("confirm", "keyboard")[0][0])))
async def confirm_yes(app, msg): 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)] = { application_content = []
"approved": False, i = 1
"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))
}
jsonSave(applications, f"{configGet('data', 'locations')}{sep}applications.json") for question in tmp_application['application']:
application_content = [] if i == 2:
i = 1 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} р.)")
for question in configGet("application", file=str(msg.from_user.id)): elif i == 3:
if i == 2: if tmp_application['application']['3']['countryCode'] == "UA":
age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(msg.from_user.id))['2'], '%d.%m.%Y')) application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}")
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))['2']} ({age.years} р.)")
else: else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}") 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']})")
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}")
]
]
)
)
else: 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("reapply_yes", "button")), callback_data=f"reapply_yes_{holo_user.id}")
InlineKeyboardButton(text=str(locale("sub_yes", "button")), callback_data=f"sub_yes_{msg.from_user.id}") ],
], [
[ InlineKeyboardButton(text=str(locale("reapply_no", "button")), callback_data=f"reapply_no_{holo_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}")
]
] ]
) ]
) )
)
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)) col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}})
configSet(["confirmed"], True, file=str(msg.from_user.id))
# 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]))) @app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("confirm", "keyboard")[1][0])))
async def confirm_no(app, msg): 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: if (holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True):
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json") holo_user.application_restart()
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))
await welcome_pass(app, msg, once_again=True) await welcome_pass(app, msg, once_again=True)
logWrite(f"User {msg.from_user.id} restarted the application due to typo in it") 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 dateutil.relativedelta import relativedelta
from datetime import datetime from datetime import datetime
from app import app, isAnAdmin from app import app, isAnAdmin
from pyrogram import filters 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 ============================================================================================================== # Contact getting ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.contact & filters.private) @app.on_message(~ filters.scheduled & filters.contact & filters.private)
async def get_contact(app, msg): 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: if msg.contact.user_id != None:
try:
user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.contact.user_id}.json") application = col_applications.find_one({"user": msg.contact.user_id})
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(msg.contact.user_id)]
application_content = [] if application is None:
i = 1 logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists")
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")
await msg.reply_text(locale("contact_invalid", "message")) 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: 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")) 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 from app import app, isAnAdmin
import asyncio import asyncio
from pyrogram import filters from pyrogram import filters
from pyrogram.types import ForceReply, ReplyKeyboardMarkup, Message from pyrogram.types import Message
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite, should_quote from classes.holo_user import HoloUser
from modules.utils import configGet, logWrite
from modules.database import col_messages from modules.database import col_messages
async def message_involved(msg: Message) -> bool: async def message_involved(msg: Message) -> bool:
@ -20,78 +19,96 @@ async def message_context(msg: Message) -> tuple:
return 0, 0 return 0, 0
# Any other input ============================================================================================================== # Any other input ==============================================================================================================
# @app.on_message(~ filters.scheduled & filters.private) @app.on_message(~ filters.scheduled & filters.private)
# async def any_stage(app, msg): 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)): holo_user = HoloUser(msg.from_user)
# 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
# user_stage = configGet("stage", file=str(msg.from_user.id)) if (msg.reply_to_message is not None) and (await message_involved(msg)):
# if user_stage == 1: context = await message_context(msg)
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply")))) context_message = await app.get_messages(context[0], context[1])
# 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: destination_user = HoloUser(context_message.from_user)
# try: 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)
)
# configSet(["application", str(user_stage)], str(msg.text), file=str(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}})
# input_dt = datetime.strptime(msg.text, "%d.%m.%Y") return
# if datetime.now() <= input_dt: await holo_user.application_next(msg.text, msg=msg)
# 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): # user_stage = configGet("stage", file=str(msg.from_user.id))
# 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: # if user_stage == 1:
# 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"))))
# 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(["stage"], user_stage+1, file=str(msg.from_user.id)) # 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))
# except ValueError: # elif user_stage == 2:
# 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: # try:
# if user_stage <= 9:
# 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))
# 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)) # input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# else: # if datetime.now() <= input_dt:
# if not configGet("sent", file=str(msg.from_user.id)): # logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
# if not configGet("confirmed", file=str(msg.from_user.id)): # await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# application_content = [] # elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
# i = 1 # logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
# for question in configGet("application", file=str(msg.from_user.id)): # await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
# i += 1 # else:
# await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True)) # logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# #configSet("sent", True, file=str(msg.from_user.id)) # 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_date", int(time()), file=str(msg.from_user.id)) # configSet(["stage"], user_stage+1, 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)): # except ValueError:
# await msg.reply_text(locale("already_sent", "message")) # logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
# else: # await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
# 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) @app.on_message(~ filters.scheduled & filters.group)
async def message_in_group(app, msg): async def message_in_group(app, msg):

View File

@ -1,25 +1,35 @@
from os import sep, path
from app import app, isAnAdmin from app import app, isAnAdmin
from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton 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 ========================================================================================================= # Filter users on join =========================================================================================================
@app.on_chat_member_updated(group=configGet("destination_group")) @app.on_chat_member_updated(group=configGet("destination_group"))
#@app.on_message(filters.new_chat_members, group=configGet("destination_group")) #@app.on_message(filters.new_chat_members, group=configGet("destination_group"))
async def filter_join(app, member): async def filter_join(app, member):
if member.invite_link != None: 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: holo_user = HoloUser(member.from_user)
return
if await isAnAdmin(member.invite_link.creator.id): 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 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_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 app import app
from pyrogram import filters from pyrogram import filters
from pyrogram.types import ForceReply, ReplyKeyboardMarkup from pyrogram.types import ForceReply, ReplyKeyboardMarkup
from classes.holo_user import HoloUser from modules.utils import locale, logWrite
from modules.utils import configGet, configSet, locale, logWrite
# Welcome check ================================================================================================================ # Welcome check ================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("welcome", "keyboard")[0][0]) | filters.regex(locale("return", "keyboard")[0][0]))) @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. * 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: if not once_again:
await msg.reply_text(locale("privacy_notice", "message")) await msg.reply_text(locale("privacy_notice", "message"))
logWrite(f"User {msg.from_user.id} confirmed starting the application") 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"))) 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(["stage"], 1, file=str(msg.from_user.id))
configSet(["sent"], False, 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]))) @app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("welcome", "keyboard")[1][0])))
async def welcome_reject(app, msg): 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)) 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 datetime import datetime
from os import path, sep from os import path, sep
from app import app, isAnAdmin
from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent
from pyrogram.enums.chat_type import ChatType from pyrogram.enums.chat_type import ChatType
from pyrogram.enums.chat_members_filter import ChatMembersFilter from pyrogram.enums.chat_members_filter import ChatMembersFilter
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from classes.holo_user import HoloUser, UserInvalidError, UserNotFoundError
from app import app, isAnAdmin from modules.utils import configGet, locale
from modules.utils import configGet, jsonLoad, locale from modules.database import col_applications
@app.on_inline_query() @app.on_inline_query()
async def inline_answer(client, inline_query): async def inline_answer(client, inline_query):
@ -25,7 +26,23 @@ async def inline_answer(client, inline_query):
) )
return 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 = [] 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): 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 = [] results = []
applications = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
for match in list_of_users: for match in list_of_users:
try: application = col_applications.find_one({"user": match.user.id})
application_content = []
i = 1 if application is None:
for question in applications[str(match.user.id)]["application"]: continue
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(applications[str(match.user.id)]['application']['2'], '%d.%m.%Y')) application_content = []
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {applications[str(match.user.id)]['application']['2']} ({age.years} р.)") 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: else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {applications[str(match.user.id)]['application'][question]}") application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
i += 1 else:
except KeyError: application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}")
continue
except FileNotFoundError: i += 1
continue
except TypeError:
continue
if match.user.photo != None: if match.user.photo != None:
try: try:
@ -104,17 +125,3 @@ async def inline_answer(client, inline_query):
results=results, results=results,
cache_time=10 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 # Check latest log size
def checkSize(debug=False): 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 global log_folder
@ -35,7 +40,13 @@ def checkSize(debug=False):
pass pass
# Append string to log # 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 global log_folder
@ -52,7 +63,13 @@ def logAppend(message, debug=False):
log.close() log.close()
# Print to stdout and then to log # 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 # save to log file and rotation is to be done
logAppend(f'{message}', debug=debug) logAppend(f'{message}', debug=debug)
print(f"{message}", flush=True) print(f"{message}", flush=True)

View File

@ -1,8 +1,7 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from datetime import datetime from datetime import datetime
from os import fsdecode, listdir, sep
from app import app 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 dateutil.relativedelta import relativedelta
from modules.database import col_applications from modules.database import col_applications
@ -23,10 +22,15 @@ scheduler = AsyncIOScheduler()
if configGet("enabled", "scheduler", "birthdays"): if configGet("enabled", "scheduler", "birthdays"):
@scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "birthdays")) @scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "birthdays"))
async def check_birthdays(): async def check_birthdays():
for entry in col_applications.find({"2": datetime.now().strftime("%d.%m.%Y")}): for entry in col_applications.find():
tg_user = await app.get_users(entry["user"]) if entry["application"]["2"].strftime("%d.%m") == datetime.now().strftime("%d.%m"):
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 try:
logWrite(f"Notified admins about {entry['user']}'s birthday") 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") logWrite("Birthdays check performed")
if configGet("enabled", "scheduler", "sponsorships"): if configGet("enabled", "scheduler", "sponsorships"):

View File

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