Compare commits

...

4 Commits

Author SHA1 Message Date
b52c69b281 Small refactoring 2022-10-24 14:34:18 +02:00
915569ceca New messages added 2022-10-24 14:34:13 +02:00
162e2bc484 New command added 2022-10-24 14:34:05 +02:00
f69ca41781 Improved To-Do 2022-10-24 14:33:54 +02:00
4 changed files with 85 additions and 33 deletions

@ -59,11 +59,11 @@ After all of that you're good to go! Happy using :)
## To-Do
[ ] Check if link belongs to admin
[ ] Inline query user's application
[ ] Get applications .json
[ ] Get application by id and user_id
[ ] Age as a DD.MM.YYYY
[ ] Notify about upcoming birthdays
[ ] Change the application data
[ ] Check if user is already in group
[x] Check if link belongs to admin
[ ] Inline query user's application
[x] Get applications .json
[ ] Get application by id and user_id
[x] Age as a DD.MM.YYYY
[ ] Notify about upcoming birthdays
[ ] Change the application data
[x] Check if user is already in group

@ -22,6 +22,7 @@
"start": "Start using the bot"
},
"commands_admin": {
"reboot": "Restart the bot"
"reboot": "Restart the bot",
"applications": "Get all applications as JSON"
}
}

@ -12,7 +12,7 @@
"goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.",
"privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.",
"question1": "Як до тебе можна звертатись?",
"question2": "Скільки тобі років?",
"question2": "Коли в тебе день народження?",
"question3": "З якого ти міста та де проживаєш зараз?\n\n⚠ Будь ласка, не вказуйте точних адрес! \"Київщина\" може бути достатньою конкретизацією.",
"question4": "Коли вперше довелось дізнатись про Хололайв?",
"question5": "Чим тебе зацікавив Хололайв?",
@ -22,7 +22,7 @@
"question9": "Чиї пісні з Хололайву тобі подобаються найбільше?",
"question10": "Ну і нарешті, розкажи трохи про себе. Про хобі, чим тобі подобається займатись. Одним повідомленням, будь ласка.",
"question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.",
"question2_invalid": "Будь ласка, введи ціле число.",
"question2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
"question2_joke": "Шутнік, ми так і поняли. Але будь ласка, введи реальне значення.",
"confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?",
"application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)",
@ -33,6 +33,7 @@
"sub_yes": "✅ Подання схвалено та прийнято",
"sub_no": "❌ Подання розглянуто та відхилено",
"approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ. Скористайся кнопкою під повідомленням щоб вступити до нашої лампової спільноти!",
"approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!",
"refused": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!",
"refused_russian": "русский военньій корабль, иди нахуй!",
"approved_by": "✅ **Анкету схвалено**\nАдмін **{0}** переглянув та схвалив анкету `{1}`, дозволивши вступ до спільноти.",
@ -52,7 +53,7 @@
"sus_refused_by": "❌ **Доступ заборонено**\nАдмін **{0}** заборонив `{1}` доступ до спільноти не за персональним посиланням.",
"question_titles": {
"question1": "Ім'я/звертання:",
"question2": "Вік:",
"question2": "День народження:",
"question3": "Проживаня:",
"question4": "Дізнався(лась) про холо:",
"question5": "Хололайв зацікавив:",
@ -88,7 +89,7 @@
},
"force_reply": {
"question1": "Ім'я або звертання",
"question2": "Твій вік",
"question2": "День народження",
"question3": "Місто або область",
"question4": "Орієнтовний час",
"question5": "Риси, особливості",

90
main.py

@ -1,4 +1,5 @@
from datetime import datetime, timedelta
from datetime import datetime
from dateutil.relativedelta import relativedelta
from time import time
from os import getpid, path
from modules.utils import *
@ -6,6 +7,7 @@ from modules.utils import *
from pyrogram.client import Client
from pyrogram import filters
from pyrogram.enums.parse_mode import ParseMode
from pyrogram.enums.chat_action import ChatAction
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, BotCommand, BotCommandScopeChat, ReplyKeyboardMarkup, ForceReply, ReplyKeyboardRemove, ChatPermissions
from pyrogram import idle # type: ignore
from pyrogram.errors.exceptions import bad_request_400
@ -15,6 +17,15 @@ pid = getpid()
app = Client("holochecker", bot_token=configGet("bot_token", "bot"), api_id=configGet("api_id", "bot"), api_hash=configGet("api_hash", "bot"))
async def isAnAdmin(admin_id):
if admin_id == configGet("owner") or admin_id in configGet("admins"):
return True
async for member in app.get_chat_members(configGet("admin_group")):
if member.user.id == admin_id:
return True
return False
# Start command ================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"]))
async def cmd_start(app, msg):
@ -40,13 +51,23 @@ async def cmd_start(app, msg):
@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["", "/"]))
async def cmd_kill(app, msg):
if (msg.from_user.id == configGet("owner")) or (msg.from_user.id in configGet("admins")):
if await isAnAdmin(msg.from_user.id):
logWrite(f"Shutting down bot with pid {pid}")
await msg.reply_text(f"Вимкнення бота з підом `{pid}`")
killProc(pid)
# ==============================================================================================================================
# Applications command =========================================================================================================
@app.on_message(~ filters.scheduled & filters.private & filters.command(["applications"], prefixes=["", "/"]))
async def cmd_applications(app, msg):
if await isAnAdmin(msg.from_user.id):
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
await msg.reply_document(document=f"{configGet('data', 'locations')}{sep}applications.json")
# ==============================================================================================================================
# Welcome check ================================================================================================================
@app.on_message(~ filters.scheduled & filters.private & (filters.regex(locale("welcome", "keyboard")[0][0]) | filters.regex(locale("return", "keyboard")[0][0])))
async def welcome_pass(app, msg, once_again: bool = True):
@ -97,7 +118,11 @@ async def confirm_yes(app, msg):
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]}")
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(msg.from_user.id))['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))['2']} ({age.years} р.)")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
i += 1
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( # type: ignore
@ -148,18 +173,27 @@ async def callback_query_accept(app, clb):
await app.send_message(configGet("admin_group"), locale("approved_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True) # type: ignore
logWrite(f"User {fullclb[2]} got approved by {clb.from_user.id}")
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))
need_link = True
await app.send_message(int(fullclb[2]), locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
[[
InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]]
))
async for member in app.get_chat_members(configGet("destination_group")):
if member.user.id == int(fullclb[2]):
need_link = False
if need_link:
link = await app.create_chat_invite_link(configGet("destination_group"), name=f"Invite for {fullclb[2]}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
await app.send_message(int(fullclb[2]), locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
[[
InlineKeyboardButton(str(locale("join", "button")), url=link.invite_link)
]]
))
configSet("link", link.invite_link, file=fullclb[2])
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}")
else:
await app.send_message(int(fullclb[2]), locale("approved_joined", "message"))
configSet("approved", True, file=fullclb[2])
configSet("link", link.invite_link, file=fullclb[2])
logWrite(f"User {fullclb[2]} got an invite link {link.invite_link}")
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")
application[fullclb[2]]["approved"] = True
@ -295,14 +329,18 @@ async def callback_query_nothing(app, clb):
# Contact getting ==============================================================================================================
@app.on_message(~ filters.scheduled & filters.contact & filters.private)
async def get_contact(app, msg):
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.from_user.id}.json")["approved"]) or (msg.from_user.id in configGet("admins")) or (msg.from_user.id == configGet("owner")):
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)):
if msg.contact.user_id != None:
try:
user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.contact.user_id}.json")
application_content = []
i = 1
for question in configGet("application", file=str(msg.contact.user_id)):
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.contact.user_id))[question]}")
for question in configGet("application", file=str(msg.from_user.id)):
if i == 2:
age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(msg.contact.user_id))['2'], '%d.%m.%Y'))
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.contact.user_id))['2']} ({age.years} р.)")
else:
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.contact.user_id))[question]}")
i += 1
if user_data["sent"]:
application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(msg.contact.user_id)]
@ -336,22 +374,32 @@ async def any_stage(app, msg):
logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
configSet(str(user_stage), str(msg.text), "application", file=str(msg.from_user.id))
configSet("stage", user_stage+1, file=str(msg.from_user.id))
elif user_stage == 2:
try:
configSet(str(user_stage), int(msg.text), "application", file=str(msg.from_user.id))
if (int(msg.text) in [-1, 0, 128, 256, 512, 1024, 2048]) or (int(msg.text) >= 100):
configSet(str(user_stage), str(msg.text), "application", file=str(msg.from_user.id))
input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
if datetime.now() <= input_dt:
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
elif int(msg.text) < configGet("age_allowed"):
elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply")))) # type: ignore
else:
logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
configSet("stage", user_stage+1, file=str(msg.from_user.id))
except ValueError:
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending not int")
logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
else:
if user_stage <= 9:
logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
@ -383,9 +431,11 @@ async def any_stage(app, msg):
#@app.on_message(filters.new_chat_members, group=configGet("destination_group"))
async def filter_join(app, member):
if member.invite_link != None:
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json")["approved"]) or (member.from_user.id in configGet("admins")) or (member.from_user.id == configGet("owner")):
if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{member.from_user.id}.json")["approved"]) or (await isAnAdmin(member.from_user.id)):
if configGet("link", file=str(member.from_user.id)) == member.invite_link.invite_link:
return
if await isAnAdmin(member.invite_link.creator.id):
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(
[
[