Merge branch 'dev'
This commit is contained in:
commit
09e5048d7f
1
.gitignore
vendored
1
.gitignore
vendored
@ -164,3 +164,4 @@ inline_bot.py
|
|||||||
data/applications.json
|
data/applications.json
|
||||||
!data/cache/avatars/.gitkeep
|
!data/cache/avatars/.gitkeep
|
||||||
data/cache/avatars/*
|
data/cache/avatars/*
|
||||||
|
.vscode
|
@ -1,9 +1,11 @@
|
|||||||
from os import path, sep
|
from os import makedirs, path, sep
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from fastapi.responses import FileResponse, JSONResponse
|
from fastapi.responses import FileResponse, JSONResponse
|
||||||
from starlette.status import HTTP_404_NOT_FOUND
|
from starlette.status import HTTP_404_NOT_FOUND
|
||||||
from modules.utils import configGet
|
from modules.utils import configGet
|
||||||
|
|
||||||
|
makedirs(f'{configGet("cache", "locations")}{sep}avatars', exist_ok=True)
|
||||||
|
|
||||||
app = FastAPI(title="HoloUA Avatars API", docs_url=None, redoc_url=None, version="1.0")
|
app = FastAPI(title="HoloUA Avatars API", docs_url=None, redoc_url=None, version="1.0")
|
||||||
|
|
||||||
@app.get("/check", response_class=JSONResponse, include_in_schema=False)
|
@app.get("/check", response_class=JSONResponse, include_in_schema=False)
|
||||||
|
2
app.py
2
app.py
@ -4,7 +4,7 @@ from pyrogram.client import Client
|
|||||||
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")):
|
async for member in app.get_chat_members(configGet("admin_group")):
|
||||||
if member.user.id == admin_id:
|
if member.user.id == admin_id:
|
||||||
|
0
cache/.gitkeep
vendored
0
cache/.gitkeep
vendored
0
cache/avatars/.gitkeep
vendored
0
cache/avatars/.gitkeep
vendored
105
classes/holo_user.py
Normal file
105
classes/holo_user.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
from app import app, isAnAdmin
|
||||||
|
from typing import Any, List, Union
|
||||||
|
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.errors import bad_request_400
|
||||||
|
from modules.database import col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages
|
||||||
|
from modules.logging import logWrite
|
||||||
|
from modules.utils import configGet, locale, should_quote
|
||||||
|
|
||||||
|
class UserNotFoundError(Exception):
|
||||||
|
"""HoloUser could not find user with such an ID in database"""
|
||||||
|
def __init__(self, user, user_id):
|
||||||
|
self.user = user
|
||||||
|
self.user_id = user_id
|
||||||
|
super().__init__(f"User of type {type(self.user)} with id {self.user_id} was not found")
|
||||||
|
|
||||||
|
class UserInvalidError(Exception):
|
||||||
|
"""Provided to HoloUser object is not supported"""
|
||||||
|
def __init__(self, user):
|
||||||
|
self.user = user
|
||||||
|
super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type")
|
||||||
|
|
||||||
|
class HoloUser():
|
||||||
|
|
||||||
|
def __init__(self, user: Union[List[User], User, ChatMember, int, str]) -> None:
|
||||||
|
|
||||||
|
# Determine input object class and extract id
|
||||||
|
if isinstance(user, list) and len(user) != 0:
|
||||||
|
self.id = user[0].id
|
||||||
|
elif isinstance(user, User):
|
||||||
|
self.id = user.id
|
||||||
|
elif isinstance(user, ChatMember):
|
||||||
|
self.id = user.user.id
|
||||||
|
elif isinstance(user, int):
|
||||||
|
self.id = user
|
||||||
|
elif isinstance(user, str):
|
||||||
|
try:
|
||||||
|
self.id = (app.get_users(user)).id # this line requires testing though
|
||||||
|
except bad_request_400.UsernameNotOccupied:
|
||||||
|
raise UserInvalidError(user)
|
||||||
|
except bad_request_400.PeerIdInvalid:
|
||||||
|
raise UserInvalidError(user)
|
||||||
|
else:
|
||||||
|
raise UserInvalidError(user)
|
||||||
|
|
||||||
|
# Find user record in DB
|
||||||
|
holo_user = col_users.find_one({"user": self.id})
|
||||||
|
|
||||||
|
if holo_user is None:
|
||||||
|
raise UserNotFoundError(user=user, user_id=self.id)
|
||||||
|
|
||||||
|
self.db_id = holo_user["_id"]
|
||||||
|
|
||||||
|
self.link = holo_user["link"]
|
||||||
|
self.label = holo_user["label"]
|
||||||
|
self.name = holo_user["tg_name"]
|
||||||
|
self.phone = holo_user["tg_phone"]
|
||||||
|
self.locale = holo_user["tg_locale"]
|
||||||
|
self.username = holo_user["tg_username"]
|
||||||
|
|
||||||
|
def set(self, key: str, value: Any) -> None:
|
||||||
|
"""Set attribute data and save it into database
|
||||||
|
|
||||||
|
### Args:
|
||||||
|
* `key` (`str`): Attribute to be changed
|
||||||
|
* `value` (`Any`): Value to set
|
||||||
|
"""
|
||||||
|
if not hasattr(self, key):
|
||||||
|
raise AttributeError()
|
||||||
|
setattr(self, key, value)
|
||||||
|
col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { key: value } }, upsert=True)
|
||||||
|
logWrite(f"Set attribute {key} of user {self.id} to {value}")
|
||||||
|
|
||||||
|
async def message(self, origin: Message, text: Union[str, None] = None, photo: Union[str, None] = None, video: Union[str, None] = None, file: Union[str, None] = None):
|
||||||
|
new_message = await app.send_message(self.id, text+locale("message_reply_notice", "message"))
|
||||||
|
await origin.reply_text(locale("message_sent", "message"), quote=should_quote(origin))
|
||||||
|
logWrite(f"Admin {origin.from_user.id} sent message '{' '.join(origin.command[2:])}' to {self.id}")
|
||||||
|
col_messages.insert_one({"origin": {"chat": origin.chat.id, "id": origin.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
||||||
|
|
||||||
|
async def set_label(self, chat: Chat, label: str):
|
||||||
|
"""Set label in destination group
|
||||||
|
|
||||||
|
### Args:
|
||||||
|
* app (`Client`): Pyrogram client
|
||||||
|
* label (`str`): Label you want to set
|
||||||
|
"""
|
||||||
|
self.label = label
|
||||||
|
self.set("label", label)
|
||||||
|
await app.promote_chat_member(configGet("destination_group"), self.id)
|
||||||
|
if (not await isAnAdmin(self.id)) and (chat.id == configGet("admin_group")):
|
||||||
|
await app.set_administrator_title(configGet("destination_group"), self.id, label)
|
||||||
|
|
||||||
|
async def reset_label(self, chat: Chat):
|
||||||
|
"""Reset label in destination group
|
||||||
|
|
||||||
|
### Args:
|
||||||
|
* app (`Client`): Pyrogram client
|
||||||
|
"""
|
||||||
|
self.label = ""
|
||||||
|
self.set("label", "")
|
||||||
|
await app.set_administrator_title(configGet("destination_group"), self.id, "")
|
||||||
|
if (not await isAnAdmin(self.id)) and (chat.id == configGet("admin_group")):
|
||||||
|
await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges(
|
||||||
|
can_manage_chat=False
|
||||||
|
))
|
@ -4,8 +4,6 @@
|
|||||||
"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,
|
||||||
@ -17,12 +15,28 @@
|
|||||||
"api_hash": "",
|
"api_hash": "",
|
||||||
"bot_token": ""
|
"bot_token": ""
|
||||||
},
|
},
|
||||||
|
"database": {
|
||||||
|
"user": null,
|
||||||
|
"password": null,
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 27017,
|
||||||
|
"name": "holochecker"
|
||||||
|
},
|
||||||
"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"
|
||||||
},
|
},
|
||||||
@ -34,6 +48,7 @@
|
|||||||
"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"
|
||||||
@ -41,6 +56,7 @@
|
|||||||
"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"
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"filling": false,
|
|
||||||
"applied": false,
|
|
||||||
"approved": false,
|
|
||||||
"stage": 0,
|
|
||||||
"paid": null,
|
|
||||||
"expires": null,
|
|
||||||
"nickname": null
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"stage": 0,
|
|
||||||
"reapply": false,
|
|
||||||
"link": null,
|
|
||||||
"sent": false,
|
|
||||||
"confirmed": false,
|
|
||||||
"approved": false,
|
|
||||||
"refused": false,
|
|
||||||
"telegram_id": null,
|
|
||||||
"telegram_name": null,
|
|
||||||
"telegram_phone": null,
|
|
||||||
"telegram_locale": null,
|
|
||||||
"application": {
|
|
||||||
"1": null,
|
|
||||||
"2": null,
|
|
||||||
"3": null,
|
|
||||||
"4": null,
|
|
||||||
"5": null,
|
|
||||||
"6": null,
|
|
||||||
"7": null,
|
|
||||||
"8": null,
|
|
||||||
"9": null,
|
|
||||||
"10": null
|
|
||||||
}
|
|
||||||
}
|
|
86
holochecker.py
Normal file
86
holochecker.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
from os import getpid, makedirs
|
||||||
|
from modules.utils import *
|
||||||
|
from modules.inline import *
|
||||||
|
from app import app
|
||||||
|
|
||||||
|
from modules.commands_register import commands_register
|
||||||
|
from pyrogram import idle
|
||||||
|
|
||||||
|
pid = getpid()
|
||||||
|
|
||||||
|
makedirs(f'{configGet("cache", "locations")}{sep}avatars', exist_ok=True)
|
||||||
|
|
||||||
|
# Importing
|
||||||
|
from modules.commands.application import *
|
||||||
|
from modules.commands.applications import *
|
||||||
|
from modules.commands.label import *
|
||||||
|
from modules.commands.message import *
|
||||||
|
from modules.commands.reapply import *
|
||||||
|
from modules.commands.reboot import *
|
||||||
|
from modules.commands.rules import *
|
||||||
|
from modules.commands.sponsorship import *
|
||||||
|
from modules.commands.start import *
|
||||||
|
from modules.commands.warn import *
|
||||||
|
from modules.commands.warnings import *
|
||||||
|
|
||||||
|
from modules.callbacks.nothing import *
|
||||||
|
from modules.callbacks.reapply import *
|
||||||
|
from modules.callbacks.rules import *
|
||||||
|
from modules.callbacks.sub import *
|
||||||
|
from modules.callbacks.sus import *
|
||||||
|
|
||||||
|
from modules.handlers.confirmation import *
|
||||||
|
from modules.handlers.contact import *
|
||||||
|
from modules.handlers.group_join import *
|
||||||
|
from modules.handlers.welcome import *
|
||||||
|
from modules.handlers.everything import *
|
||||||
|
|
||||||
|
from modules.scheduled import *
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
logWrite(f"Starting up with pid {pid}")
|
||||||
|
|
||||||
|
# Yes, it should be in some kind of async main() function but I don't give a shit.
|
||||||
|
# I did compare performance, almost no difference and it's much more useful this way. Change my mind.
|
||||||
|
app.start()
|
||||||
|
|
||||||
|
# if configGet("birthdays_notify"):
|
||||||
|
|
||||||
|
# every().day.at(configGet("birthdays_time")).do(check_birthdays, app)
|
||||||
|
|
||||||
|
# # Background tasks checker
|
||||||
|
# def background_task():
|
||||||
|
# try:
|
||||||
|
# while True:
|
||||||
|
# try:
|
||||||
|
# run_pending()
|
||||||
|
# #print('Checked')
|
||||||
|
# time.sleep(1)
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
# except KeyboardInterrupt:
|
||||||
|
# print('\nShutting down')
|
||||||
|
# killProc(pid)
|
||||||
|
# t = Thread(target=background_task)
|
||||||
|
# t.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
app.send_message(configGet("owner"), f"Starting up with pid `{pid}`")
|
||||||
|
except bad_request_400.PeerIdInvalid:
|
||||||
|
logWrite(f"Could not send startup message to bot owner. Perhaps user has not started the bot yet.")
|
||||||
|
|
||||||
|
commands_register(app)
|
||||||
|
|
||||||
|
scheduler.start()
|
||||||
|
|
||||||
|
idle()
|
||||||
|
|
||||||
|
try:
|
||||||
|
app.send_message(configGet("owner"), f"Shutting with pid `{pid}`")
|
||||||
|
except bad_request_400.PeerIdInvalid:
|
||||||
|
logWrite(f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet.")
|
||||||
|
|
||||||
|
app.stop()
|
||||||
|
|
||||||
|
killProc(pid)
|
95
main.py
95
main.py
@ -1,95 +0,0 @@
|
|||||||
from threading import Thread
|
|
||||||
from time import time
|
|
||||||
from os import getpid, path
|
|
||||||
from modules.birthdays import check_birthdays
|
|
||||||
from modules.utils import *
|
|
||||||
from modules.inline import *
|
|
||||||
from schedule import run_pending, every
|
|
||||||
from app import app
|
|
||||||
|
|
||||||
from modules.commands_register import commands_register
|
|
||||||
from pyrogram import idle
|
|
||||||
|
|
||||||
|
|
||||||
pid = getpid()
|
|
||||||
|
|
||||||
|
|
||||||
for entry in [f"{configGet('data', 'locations')}{sep}applications.json", f"{configGet('data', 'locations')}{sep}warnings.json"]:
|
|
||||||
mode = 'r' if path.exists(entry) else 'w'
|
|
||||||
with open(entry, mode) as f:
|
|
||||||
try:
|
|
||||||
f.write("{}")
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for entry in [f"{configGet('data', 'locations')}{sep}messages.json"]:
|
|
||||||
mode = 'r' if path.exists(entry) else 'w'
|
|
||||||
with open(entry, mode) as f:
|
|
||||||
try:
|
|
||||||
f.write("[]")
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Importing
|
|
||||||
from modules.commands.application import *
|
|
||||||
from modules.commands.applications import *
|
|
||||||
from modules.commands.message import *
|
|
||||||
from modules.commands.reapply import *
|
|
||||||
from modules.commands.reboot import *
|
|
||||||
from modules.commands.rules import *
|
|
||||||
from modules.commands.sponsorship import *
|
|
||||||
from modules.commands.start import *
|
|
||||||
from modules.commands.warn import *
|
|
||||||
from modules.commands.warnings import *
|
|
||||||
|
|
||||||
from modules.callbacks.nothing import *
|
|
||||||
from modules.callbacks.reapply import *
|
|
||||||
from modules.callbacks.rules import *
|
|
||||||
from modules.callbacks.sub import *
|
|
||||||
from modules.callbacks.sus import *
|
|
||||||
|
|
||||||
from modules.handlers.confirmation import *
|
|
||||||
from modules.handlers.contact import *
|
|
||||||
from modules.handlers.group_join import *
|
|
||||||
from modules.handlers.welcome import *
|
|
||||||
from modules.handlers.everything import *
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
logWrite(f"Starting up with pid {pid}")
|
|
||||||
|
|
||||||
# Yes, it should be in some kind of async main() function but I don't give a shit.
|
|
||||||
# I did compare performance, almost no difference and it's much more useful this way. Change my mind.
|
|
||||||
app.start()
|
|
||||||
|
|
||||||
if configGet("birthdays_notify"):
|
|
||||||
|
|
||||||
every().day.at(configGet("birthdays_time")).do(check_birthdays, app)
|
|
||||||
|
|
||||||
# Background tasks checker
|
|
||||||
def background_task():
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
run_pending()
|
|
||||||
#print('Checked')
|
|
||||||
time.sleep(1)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\nShutting down')
|
|
||||||
killProc(pid)
|
|
||||||
t = Thread(target=background_task)
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
app.send_message(configGet("owner"), f"Starting up with pid `{pid}`")
|
|
||||||
|
|
||||||
commands_register(app)
|
|
||||||
|
|
||||||
idle()
|
|
||||||
|
|
||||||
app.send_message(configGet("owner"), f"Shutting with pid `{pid}`")
|
|
||||||
|
|
||||||
app.stop()
|
|
||||||
|
|
||||||
killProc(pid)
|
|
@ -1,18 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from os import fsdecode, listdir, sep
|
|
||||||
from modules.utils import configGet, jsonLoad, locale
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
|
|
||||||
|
|
||||||
def check_birthdays(app):
|
|
||||||
for user_file in listdir(f"{configGet('data', 'locations')}{sep}users{sep}"):
|
|
||||||
filename = fsdecode(f"{configGet('data', 'locations')}{sep}users{sep}{user_file}")
|
|
||||||
if filename.endswith(".json"):
|
|
||||||
user = jsonLoad(filename)
|
|
||||||
if isinstance(user["application"]["2"], str):
|
|
||||||
try:
|
|
||||||
if ".".join([((user["application"]["2"]).split("."))[0], ((user["application"]["2"]).split("."))[1]]) == datetime.now().strftime("%d.%m"):
|
|
||||||
tg_user = app.get_users(int(user_file.replace(".json", "")))
|
|
||||||
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(user["application"]["2"], '%d.%m.%Y')).years)) )
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
@ -1,8 +1,10 @@
|
|||||||
from os import sep
|
from os import sep, makedirs, remove
|
||||||
|
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
|
from modules.utils import configGet, should_quote, jsonSave
|
||||||
|
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=["/"]))
|
||||||
@ -10,5 +12,12 @@ 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)) or (msg.chat.id == configGet("admin_group")):
|
||||||
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
|
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
|
||||||
await msg.reply_document(document=f"{configGet('data', 'locations')}{sep}applications.json", quote=should_quote(msg))
|
filename = uuid1()
|
||||||
|
output = []
|
||||||
|
for entry in col_applications.find():
|
||||||
|
output.append(entry)
|
||||||
|
makedirs("tmp", exist_ok=True)
|
||||||
|
jsonSave(output, f"tmp{sep}{filename}.json")
|
||||||
|
await msg.reply_document(document=f"tmp{sep}{filename}.json", file_name="applications", quote=should_quote(msg))
|
||||||
|
remove(f"tmp{sep}{filename}.json")
|
||||||
# ==============================================================================================================================
|
# ==============================================================================================================================
|
33
modules/commands/label.py
Normal file
33
modules/commands/label.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from app import app, isAnAdmin
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.types import ChatPrivileges
|
||||||
|
from modules.utils import should_quote, find_user, configGet
|
||||||
|
from classes.holo_user import HoloUser
|
||||||
|
|
||||||
|
@app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"]))
|
||||||
|
async def cmd_label(app, msg):
|
||||||
|
|
||||||
|
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
||||||
|
|
||||||
|
if len(msg.command) < 3:
|
||||||
|
await msg.reply_text("Invalid syntax:\n`/label USER LABEL`")
|
||||||
|
return
|
||||||
|
|
||||||
|
target = await find_user(app, msg.command[1])
|
||||||
|
|
||||||
|
if target is not None:
|
||||||
|
|
||||||
|
target = HoloUser(target)
|
||||||
|
|
||||||
|
label = " ".join(msg.command[2:])
|
||||||
|
|
||||||
|
if label.lower() == "reset":
|
||||||
|
await target.reset_label(msg.chat)
|
||||||
|
await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg))
|
||||||
|
|
||||||
|
else:
|
||||||
|
await target.set_label(msg.chat, label)
|
||||||
|
await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg))
|
||||||
|
|
||||||
|
else:
|
||||||
|
await msg.reply_text(f"User not found")
|
@ -2,7 +2,9 @@ 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 pyrogram.errors import bad_request_400
|
||||||
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import jsonLoad, jsonSave, logWrite, locale, configGet, should_quote
|
from modules.utils import jsonLoad, jsonSave, logWrite, locale, configGet, 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=["/"]))
|
||||||
@ -11,36 +13,25 @@ async def cmd_message(app, msg):
|
|||||||
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
destination = await app.get_users(int(msg.command[1]))
|
destination = HoloUser(int(msg.command[1]))
|
||||||
if destination == [] or destination == None:
|
|
||||||
raise TypeError
|
|
||||||
except TypeError:
|
|
||||||
try:
|
|
||||||
destination = await app.get_users(msg.command[1])
|
|
||||||
except bad_request_400.UsernameNotOccupied:
|
|
||||||
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 '{msg.command[1]}' but 'UsernameNotOccupied'")
|
|
||||||
return
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
try:
|
destination = HoloUser(msg.command[1])
|
||||||
destination = await app.get_users(msg.command[1])
|
|
||||||
except bad_request_400.UsernameNotOccupied:
|
|
||||||
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 '{msg.command[1]}' but 'UsernameNotOccupied'")
|
|
||||||
return
|
|
||||||
void = msg.command[2]
|
void = msg.command[2]
|
||||||
message = " ".join(msg.command[2:])
|
message = " ".join(msg.command[2:])
|
||||||
try:
|
|
||||||
new_message = await app.send_message(destination.id, message+locale("message_reply_notice", "message"))
|
await destination.message(msg, msg.command[2:])
|
||||||
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}")
|
# try:
|
||||||
messages = jsonLoad(f"{configGet('data', 'locations')}{sep}messages.json")
|
# new_message = await app.send_message(destination.id, message+locale("message_reply_notice", "message"))
|
||||||
messages.append({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
|
||||||
jsonSave(messages, f"{configGet('data', 'locations')}{sep}messages.json")
|
# logWrite(f"Admin {msg.from_user.id} sent message '{' '.join(msg.command[2:])}' to {destination.id}")
|
||||||
except bad_request_400.PeerIdInvalid:
|
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
||||||
await msg.reply_text(locale("message_no_user", "message"), quote=should_quote(msg))
|
# except bad_request_400.PeerIdInvalid:
|
||||||
logWrite(f"Admin {msg.from_user.id} tried to send message '{' '.join(msg.command[2:])}' to {destination.id} but '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'")
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
from app import app, isAnAdmin
|
from app import app, isAnAdmin
|
||||||
from os import getpid
|
from os import getpid
|
||||||
|
from sys import exit
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from modules.utils import configGet, logWrite, killProc, should_quote
|
from modules.utils import configGet, logWrite, should_quote
|
||||||
|
from modules.scheduled import scheduler
|
||||||
|
|
||||||
pid = getpid()
|
pid = getpid()
|
||||||
|
|
||||||
@ -12,5 +14,6 @@ async def cmd_kill(app, msg):
|
|||||||
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
||||||
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))
|
||||||
killProc(pid)
|
scheduler.shutdown()
|
||||||
|
exit()
|
||||||
# ==============================================================================================================================
|
# ==============================================================================================================================
|
@ -2,24 +2,27 @@ from app import app
|
|||||||
from os import sep
|
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 jsonLoad, jsonSave, configGet, configSet, locale, logWrite
|
from modules.utils import locale, logWrite
|
||||||
|
from modules.database import col_users
|
||||||
|
|
||||||
# Start command ================================================================================================================
|
# Start command ================================================================================================================
|
||||||
@app.on_message(~ filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"]))
|
@app.on_message(~ filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"]))
|
||||||
async def cmd_start(app, msg):
|
async def cmd_start(app, msg):
|
||||||
|
|
||||||
try:
|
user = col_users.find_one({"user": msg.from_user.id})
|
||||||
user_stage = configGet("stage", file=str(msg.from_user.id))
|
|
||||||
if user_stage != 0:
|
|
||||||
return
|
|
||||||
except FileNotFoundError:
|
|
||||||
jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}user_default.json"), f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json")
|
|
||||||
user_stage = configGet("stage", file=str(msg.from_user.id))
|
|
||||||
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))
|
|
||||||
|
|
||||||
logWrite(f"User {msg.from_user.id} started bot interaction")
|
if user is None:
|
||||||
await msg.reply_text(locale("start", "message"), reply_markup=ReplyKeyboardMarkup(locale("welcome", "keyboard"), resize_keyboard=True))
|
|
||||||
|
col_users.insert_one({
|
||||||
|
"user": msg.from_user.id,
|
||||||
|
"link": None,
|
||||||
|
"label": "",
|
||||||
|
"tg_name": msg.from_user.first_name,
|
||||||
|
"tg_phone": msg.from_user.phone_number,
|
||||||
|
"tg_locale": msg.from_user.language_code,
|
||||||
|
"tg_username": msg.from_user.username
|
||||||
|
})
|
||||||
|
|
||||||
|
logWrite(f"User {msg.from_user.id} started bot interaction")
|
||||||
|
await msg.reply_text(locale("start", "message"), reply_markup=ReplyKeyboardMarkup(locale("welcome", "keyboard"), resize_keyboard=True))
|
||||||
# ==============================================================================================================================
|
# ==============================================================================================================================
|
@ -1,3 +1,4 @@
|
|||||||
|
from modules.logging import logWrite
|
||||||
from modules.utils import configGet
|
from modules.utils import configGet
|
||||||
from pyrogram.types import BotCommand, BotCommandScopeChat
|
from pyrogram.types import BotCommand, BotCommandScopeChat
|
||||||
from pyrogram.errors import bad_request_400
|
from pyrogram.errors import bad_request_400
|
||||||
@ -24,16 +25,25 @@ def commands_register(app):
|
|||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=configGet("owner")))
|
try:
|
||||||
|
app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=configGet("owner")))
|
||||||
|
except bad_request_400.PeerIdInvalid:
|
||||||
|
logWrite(f"Could not register commands for bot owner. Perhaps user has not started the bot yet.")
|
||||||
|
|
||||||
# Registering admin group commands
|
# Registering admin group commands
|
||||||
commands_group_admin_list = []
|
commands_group_admin_list = []
|
||||||
for command in configGet("commands_group_admin"):
|
for command in configGet("commands_group_admin"):
|
||||||
commands_group_admin_list.append(BotCommand(command, configGet("commands_group_admin")[command]))
|
commands_group_admin_list.append(BotCommand(command, configGet("commands_group_admin")[command]))
|
||||||
app.set_bot_commands(commands_group_admin_list, scope=BotCommandScopeChat(chat_id=configGet("admin_group")))
|
try:
|
||||||
|
app.set_bot_commands(commands_group_admin_list, scope=BotCommandScopeChat(chat_id=configGet("admin_group")))
|
||||||
|
except bad_request_400.ChannelInvalid:
|
||||||
|
logWrite(f"Could not register commands for admin group. Bot is likely not in the group.")
|
||||||
|
|
||||||
# Registering destination group commands
|
# Registering destination group commands
|
||||||
commands_group_destination_list = []
|
commands_group_destination_list = []
|
||||||
for command in configGet("commands_group_destination"):
|
for command in configGet("commands_group_destination"):
|
||||||
commands_group_destination_list.append(BotCommand(command, configGet("commands_group_destination")[command]))
|
commands_group_destination_list.append(BotCommand(command, configGet("commands_group_destination")[command]))
|
||||||
app.set_bot_commands(commands_group_destination_list, scope=BotCommandScopeChat(chat_id=configGet("destination_group")))
|
try:
|
||||||
|
app.set_bot_commands(commands_group_destination_list, scope=BotCommandScopeChat(chat_id=configGet("destination_group")))
|
||||||
|
except bad_request_400.ChannelInvalid:
|
||||||
|
logWrite(f"Could not register commands for destination group. Bot is likely not in the group.")
|
37
modules/database.py
Normal file
37
modules/database.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from pymongo import MongoClient
|
||||||
|
from ujson import loads
|
||||||
|
|
||||||
|
with open("config.json", "r", encoding="utf-8") as f:
|
||||||
|
db_config = loads(f.read())["database"]
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if db_config["user"] is not None and db_config["password"] is not None:
|
||||||
|
con_string = 'mongodb://{0}:{1}@{2}:{3}/{4}'.format(
|
||||||
|
db_config["user"],
|
||||||
|
db_config["password"],
|
||||||
|
db_config["host"],
|
||||||
|
db_config["port"],
|
||||||
|
db_config["name"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
con_string = 'mongodb://{0}:{1}/{2}'.format(
|
||||||
|
db_config["host"],
|
||||||
|
db_config["port"],
|
||||||
|
db_config["name"]
|
||||||
|
)
|
||||||
|
|
||||||
|
db_client = MongoClient(con_string)
|
||||||
|
db = db_client.get_database(name=db_config["name"])
|
||||||
|
|
||||||
|
collections = db.list_collection_names()
|
||||||
|
|
||||||
|
for collection in ["users", "context", "messages", "warnings", "applications", "sponsorships"]:
|
||||||
|
if not collection in collections:
|
||||||
|
db.create_collection(collection)
|
||||||
|
|
||||||
|
col_users = db.get_collection("users")
|
||||||
|
col_context = db.get_collection("context")
|
||||||
|
col_messages = db.get_collection("messages")
|
||||||
|
col_warnings = db.get_collection("warnings")
|
||||||
|
col_applications = db.get_collection("applications")
|
||||||
|
col_sponsorships = db.get_collection("sponsorships")
|
@ -5,95 +5,93 @@ import asyncio
|
|||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import ForceReply, ReplyKeyboardMarkup, Message
|
from pyrogram.types import ForceReply, ReplyKeyboardMarkup, Message
|
||||||
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite, should_quote
|
from modules.utils import configGet, configSet, jsonLoad, jsonSave, locale, logWrite, should_quote
|
||||||
|
from modules.database import col_messages
|
||||||
|
|
||||||
async def message_involved(msg: Message):
|
async def message_involved(msg: Message) -> bool:
|
||||||
messages = jsonLoad(f"{configGet('data', 'locations')}{sep}messages.json")
|
message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id})
|
||||||
for message in messages:
|
if message is not None:
|
||||||
if (message["destination"]["id"] == msg.reply_to_message.id) and (message["destination"]["chat"] == msg.reply_to_message.chat.id):
|
return True
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def message_context(msg: Message):
|
async def message_context(msg: Message) -> tuple:
|
||||||
messages = jsonLoad(f"{configGet('data', 'locations')}{sep}messages.json")
|
message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id})
|
||||||
for message in messages:
|
if message is not None:
|
||||||
if (message["destination"]["id"] == msg.reply_to_message.id) and (message["destination"]["chat"] == msg.reply_to_message.chat.id):
|
return message["origin"]["chat"], message["origin"]["id"]
|
||||||
return message["origin"]["chat"], message["origin"]["id"]
|
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)):
|
# if (msg.reply_to_message != None) and (await message_involved(msg)):
|
||||||
context = await message_context(msg)
|
# context = await message_context(msg)
|
||||||
if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id):
|
# 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)
|
# new_message = await (await app.get_messages(context[0], context[1])).reply_text(msg.text+locale("message_reply_notice", "message"), quote=True)
|
||||||
else:
|
# 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)
|
# 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))
|
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
|
||||||
messages = jsonLoad(f"{configGet('data', 'locations')}{sep}messages.json")
|
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
||||||
messages.append({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
# return
|
||||||
jsonSave(messages, f"{configGet('data', 'locations')}{sep}messages.json")
|
|
||||||
return
|
|
||||||
|
|
||||||
user_stage = configGet("stage", file=str(msg.from_user.id))
|
# user_stage = configGet("stage", file=str(msg.from_user.id))
|
||||||
|
|
||||||
if user_stage == 1:
|
# if user_stage == 1:
|
||||||
await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
|
# 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")
|
# 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(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
||||||
configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
||||||
|
|
||||||
elif user_stage == 2:
|
# elif user_stage == 2:
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
|
|
||||||
configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
||||||
|
|
||||||
input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
|
# input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
|
||||||
|
|
||||||
if datetime.now() <= input_dt:
|
# if datetime.now() <= input_dt:
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
|
# 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"))))
|
# 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):
|
# elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
|
# 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"))))
|
# await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
|
# 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"))))
|
||||||
configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
||||||
|
|
||||||
except ValueError:
|
# except ValueError:
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
|
# 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"))))
|
# await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
if user_stage <= 9:
|
# if user_stage <= 9:
|
||||||
logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
|
# 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"))))
|
||||||
configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
||||||
configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
|
||||||
else:
|
# else:
|
||||||
if not configGet("sent", file=str(msg.from_user.id)):
|
# if not configGet("sent", file=str(msg.from_user.id)):
|
||||||
if not configGet("confirmed", 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))
|
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
|
||||||
application_content = []
|
# application_content = []
|
||||||
i = 1
|
# i = 1
|
||||||
for question in configGet("application", file=str(msg.from_user.id)):
|
# 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]}")
|
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
|
||||||
i += 1
|
# i += 1
|
||||||
await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True))
|
# 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("sent", True, file=str(msg.from_user.id))
|
||||||
#configSet("application_date", int(time()), file=str(msg.from_user.id))
|
# #configSet("application_date", int(time()), file=str(msg.from_user.id))
|
||||||
else:
|
# else:
|
||||||
if not configGet("approved", file=str(msg.from_user.id)) and not configGet("refused", file=str(msg.from_user.id)):
|
# 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"))
|
# await msg.reply_text(locale("already_sent", "message"))
|
||||||
else:
|
# else:
|
||||||
if not configGet("approved", file=str(msg.from_user.id)) and not configGet("refused", file=str(msg.from_user.id)):
|
# 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"))
|
# 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):
|
||||||
|
@ -1,6 +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 configGet, configSet, locale, logWrite
|
from modules.utils import configGet, configSet, locale, logWrite
|
||||||
|
|
||||||
# Welcome check ================================================================================================================
|
# Welcome check ================================================================================================================
|
||||||
@ -14,6 +15,8 @@ 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"))
|
||||||
|
|
||||||
|
35
modules/scheduled.py
Normal file
35
modules/scheduled.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
|
from datetime import datetime
|
||||||
|
from os import fsdecode, listdir, sep
|
||||||
|
from app import app
|
||||||
|
from modules.utils import configGet, jsonLoad, locale, logWrite
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from modules.database import col_applications
|
||||||
|
|
||||||
|
scheduler = AsyncIOScheduler()
|
||||||
|
|
||||||
|
# for user_file in listdir(f"{configGet('data', 'locations')}{sep}users{sep}"):
|
||||||
|
# filename = fsdecode(f"{configGet('data', 'locations')}{sep}users{sep}{user_file}")
|
||||||
|
# if filename.endswith(".json"):
|
||||||
|
# user = jsonLoad(filename)
|
||||||
|
# if isinstance(user["application"]["2"], str):
|
||||||
|
# try:
|
||||||
|
# if ".".join([((user["application"]["2"]).split("."))[0], ((user["application"]["2"]).split("."))[1]]) == datetime.now().strftime("%d.%m"):
|
||||||
|
# tg_user = await app.get_users(int(user_file.replace(".json", "")))
|
||||||
|
# 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(user["application"]["2"], '%d.%m.%Y')).years)) )
|
||||||
|
# except AttributeError:
|
||||||
|
# continue
|
||||||
|
|
||||||
|
if configGet("enabled", "scheduler", "birthdays"):
|
||||||
|
@scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "birthdays"))
|
||||||
|
async def check_birthdays():
|
||||||
|
for entry in col_applications.find({"2": datetime.now().strftime("%d.%m.%Y")}):
|
||||||
|
tg_user = await app.get_users(entry["user"])
|
||||||
|
await app.send_message( configGet("admin_group"), locale("birthday", "message").format(str(tg_user.first_name), str(tg_user.username), str(relativedelta(datetime.now(), datetime.strptime(entry["2"], '%d.%m.%Y')).years)) ) # type: ignore
|
||||||
|
logWrite(f"Notified admins about {entry['user']}'s birthday")
|
||||||
|
logWrite("Birthdays check performed")
|
||||||
|
|
||||||
|
if configGet("enabled", "scheduler", "sponsorships"):
|
||||||
|
@scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "sponsorships"))
|
||||||
|
async def check_sponsors():
|
||||||
|
logWrite("Sponsorships check performed")
|
@ -1,5 +1,8 @@
|
|||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
from pyrogram.enums.chat_type import ChatType
|
from pyrogram.enums.chat_type import ChatType
|
||||||
|
from pyrogram.types import User
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.errors import bad_request_400
|
||||||
from ujson import JSONDecodeError as JSONDecodeError
|
from ujson import JSONDecodeError as JSONDecodeError
|
||||||
from ujson import loads, dumps
|
from ujson import loads, dumps
|
||||||
|
|
||||||
@ -49,11 +52,11 @@ def nested_set(dic, keys, value, create_missing=True):
|
|||||||
def configSet(keys: list, value: Any, file: str = "config", create_missing=True):
|
def configSet(keys: list, value: Any, file: str = "config", create_missing=True):
|
||||||
"""Set config's value to provided one
|
"""Set config's value to provided one
|
||||||
|
|
||||||
Args:
|
### Args:
|
||||||
* keys (list): List of keys from the highest one to target
|
* keys (`list`): List of keys from the highest one to target
|
||||||
* value (Any): Needed value
|
* value (`Any`): Needed value
|
||||||
* file (str, optional): File (if not config). Defaults to "config".
|
* file (`str`, optional): File (if not config). Defaults to "config".
|
||||||
* create_missing (bool, optional): Create missing items on the way. Defaults to True.
|
* create_missing (`bool`, optional): Create missing items on the way. Defaults to True.
|
||||||
"""
|
"""
|
||||||
if file == "config":
|
if file == "config":
|
||||||
filepath = ""
|
filepath = ""
|
||||||
@ -74,11 +77,11 @@ def configSet(keys: list, value: Any, file: str = "config", create_missing=True)
|
|||||||
|
|
||||||
def configGet(key: str, *args: str, file: str = "config"):
|
def configGet(key: str, *args: str, file: str = "config"):
|
||||||
"""Get value of the config key
|
"""Get value of the config key
|
||||||
Args:
|
### Args:
|
||||||
* key (str): The last key of the keys path.
|
* key (`str`): The last key of the keys path.
|
||||||
* *args (str): Path to key like: dict[args][key].
|
* *args (`str`): Path to key like: dict[args][key].
|
||||||
* file (str): User ID to load. Loads config if not provided. Defaults to "config".
|
* file (`str`): User ID to load. Loads config if not provided. Defaults to "config".
|
||||||
Returns:
|
### Returns:
|
||||||
* any: Value of provided key
|
* any: Value of provided key
|
||||||
"""
|
"""
|
||||||
if file == "config":
|
if file == "config":
|
||||||
@ -99,16 +102,19 @@ def configGet(key: str, *args: str, file: str = "config"):
|
|||||||
this_key = this_key[dict_key]
|
this_key = this_key[dict_key]
|
||||||
return this_key[key]
|
return this_key[key]
|
||||||
|
|
||||||
def locale(key: str, *args: str, locale=configGet("locale")) -> Union[str, list, dict]:
|
def locale(key: str, *args: str, locale: Union[str, User] = configGet("locale")) -> Any:
|
||||||
"""Get value of locale string
|
"""Get value of locale string
|
||||||
Args:
|
### Args:
|
||||||
* key (str): The last key of the locale's keys path.
|
* key (`str`): The last key of the locale's keys path.
|
||||||
* *args (list): Path to key like: dict[args][key].
|
* *args (`list`): Path to key like: dict[args][key].
|
||||||
* locale (str): Locale to looked up in. Defaults to config's locale value.
|
* locale (`Union[str, User]`): Locale to looked up in. Provide User to get his `.language_code`. Defaults to config's locale value.
|
||||||
Returns:
|
### Returns:
|
||||||
* any: Value of provided locale key
|
* any: Value of provided locale key. In normal case must be `str`, `dict` or `list`.
|
||||||
"""
|
"""
|
||||||
if (locale == None):
|
if isinstance(locale, User):
|
||||||
|
locale = locale.language_code
|
||||||
|
|
||||||
|
if locale is None:
|
||||||
locale = configGet("locale")
|
locale = configGet("locale")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -145,3 +151,19 @@ def killProc(pid):
|
|||||||
|
|
||||||
def should_quote(msg):
|
def should_quote(msg):
|
||||||
return True if msg.chat.type is not ChatType.PRIVATE else False
|
return True if msg.chat.type is not ChatType.PRIVATE else False
|
||||||
|
|
||||||
|
async def find_user(app: Client, query: Union[str, int]):
|
||||||
|
try:
|
||||||
|
result = await app.get_users(int(query))
|
||||||
|
if result == [] or result == None:
|
||||||
|
raise TypeError
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
try:
|
||||||
|
result = await app.get_users(query)
|
||||||
|
except bad_request_400.UsernameNotOccupied:
|
||||||
|
return None
|
||||||
|
except bad_request_400.UsernameInvalid:
|
||||||
|
return None
|
||||||
|
except bad_request_400.PeerIdInvalid:
|
||||||
|
return None
|
||||||
|
return result
|
@ -1,7 +1,9 @@
|
|||||||
pyrogram>=2.0.59
|
APScheduler==3.9.1.post1
|
||||||
tgcrypto>=1.2.4
|
fastapi==0.88.0
|
||||||
ujson>=5.5.0
|
psutil==5.9.4
|
||||||
psutil>=5.9.2
|
pymongo==4.3.3
|
||||||
schedule
|
Pyrogram==2.0.69
|
||||||
fastapi
|
tgcrypto==1.2.5
|
||||||
uvicorn[standard]
|
python_dateutil==2.8.2
|
||||||
|
starlette==0.22.0
|
||||||
|
ujson==5.6.0
|
6
validation/applications.json
Normal file
6
validation/applications.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [],
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
6
validation/context.json
Normal file
6
validation/context.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [],
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
36
validation/messages.json
Normal file
36
validation/messages.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [
|
||||||
|
"origin",
|
||||||
|
"origin.chat",
|
||||||
|
"origin.id",
|
||||||
|
"destination",
|
||||||
|
"destination.chat",
|
||||||
|
"destination.id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"origin": {
|
||||||
|
"bsonType": "object"
|
||||||
|
},
|
||||||
|
"origin.chat": {
|
||||||
|
"bsonType": ["int", "long"],
|
||||||
|
"description": "Telegram ID of message's origin chat"
|
||||||
|
},
|
||||||
|
"origin.id": {
|
||||||
|
"bsonType": ["int", "long"],
|
||||||
|
"description": "ID of message in origin chat"
|
||||||
|
},
|
||||||
|
"destination": {
|
||||||
|
"bsonType": "object"
|
||||||
|
},
|
||||||
|
"destination.chat": {
|
||||||
|
"bsonType": ["int", "long"],
|
||||||
|
"description": "Telegram ID of message's destination chat"
|
||||||
|
},
|
||||||
|
"destination.id": {
|
||||||
|
"bsonType": ["int", "long"],
|
||||||
|
"description": "ID of message in destination chat"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
validation/sponsorships.json
Normal file
6
validation/sponsorships.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [],
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
43
validation/users.json
Normal file
43
validation/users.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [
|
||||||
|
"user",
|
||||||
|
"link",
|
||||||
|
"label",
|
||||||
|
"tg_name",
|
||||||
|
"tg_phone",
|
||||||
|
"tg_locale",
|
||||||
|
"tg_username"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"user": {
|
||||||
|
"bsonType": ["int", "long"],
|
||||||
|
"description": "Telegram ID of user"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"bsonType": ["string", "null"],
|
||||||
|
"description": "Invite link to destination group"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"bsonType": "string",
|
||||||
|
"description": "Label given by admins"
|
||||||
|
},
|
||||||
|
"tg_name": {
|
||||||
|
"bsonType": "string",
|
||||||
|
"description": "Telegram first name"
|
||||||
|
},
|
||||||
|
"tg_phone": {
|
||||||
|
"bsonType": ["string", "null"],
|
||||||
|
"description": "Telegram phone number"
|
||||||
|
},
|
||||||
|
"tg_locale": {
|
||||||
|
"bsonType": ["string", "null"],
|
||||||
|
"description": "Telegram locale"
|
||||||
|
},
|
||||||
|
"tg_username": {
|
||||||
|
"bsonType": ["string", "null"],
|
||||||
|
"description": "Telegram username"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
validation/warnings.json
Normal file
6
validation/warnings.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [],
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user