Compare commits
142 Commits
Author | SHA1 | Date | |
---|---|---|---|
13566b2674 | |||
f9e99fa9a0 | |||
b6fe40a05b | |||
fc39383cc2 | |||
e5761ae1d0 | |||
c1261a1b0f | |||
3d7ab0654a | |||
e9da13e70f | |||
e90f5c2f90 | |||
844de7ef12 | |||
ee440eabba | |||
04f1590fb5 | |||
ad8ce9034d | |||
ad7d14f091 | |||
9940a28bd5 | |||
5571151d37 | |||
0a8a215f3e | |||
05d3a09421 | |||
20a1af3738 | |||
a0164e13c8 | |||
09e3c23c4f | |||
c7037ae246 | |||
0f88cb6059 | |||
453293e38a | |||
ea753beda1 | |||
7fd3cc061e | |||
49944b90c9 | |||
948837e45f | |||
80e62c2585 | |||
9823cccd45 | |||
3e22ad1895 | |||
fe1d44d44d | |||
0430b4d849 | |||
|
362c575d31 | ||
|
253f614559 | ||
|
ca607bb4ca | ||
|
09c93489c0 | ||
929083d2e8 | |||
4961d6ba79 | |||
1d14fd014b | |||
0c46f98225 | |||
d93b0bc07d | |||
9a028d1f79 | |||
f1897a74e8 | |||
fdddedb139 | |||
3fded13f18 | |||
aa8e77811d | |||
0bffe9cf97 | |||
177d456e79 | |||
7218d580bb | |||
e8541b5160 | |||
2e7d4aa263 | |||
79af1bce66 | |||
f66f8421c3 | |||
bd040af0cc | |||
b5c9a0783e | |||
aef4dd091d | |||
a3f75bec7c | |||
1f45398de5 | |||
|
cb2f3358b2 | ||
74ae30d841 | |||
e235fe0ed2 | |||
bf8ec39584 | |||
972827d6c2 | |||
43e71c95c4 | |||
2a2ad9f96e | |||
ddb59fdfd5 | |||
5c55af9e65 | |||
fd992e89e7 | |||
cea5338706 | |||
a4faae5b45 | |||
2dc6a54299 | |||
cb3a975303 | |||
de984c2b78 | |||
38b43c07cb | |||
3304339244 | |||
393a7584d5 | |||
e50cdd53b3 | |||
3012c3d5ae | |||
8c21ae1844 | |||
3df57f1c42 | |||
5b8951fe07 | |||
64b7a6a4ba | |||
8d18ed2126 | |||
ed2361638a | |||
0c78f21c96 | |||
3f6fb51a4f | |||
23b2925ffa | |||
82a878aa6d | |||
360bdf2c72 | |||
f98fb0b6dc | |||
eaec6f2fe8 | |||
ee738d00b5 | |||
fd19b4cb0b | |||
|
c56385a181 | ||
66a1ea17ab | |||
b10a62c63e | |||
a3c27ab4bd | |||
eeff6d40ce | |||
7be7d5ac7b | |||
1ce47b0aaf | |||
f14e80856c | |||
431b2d048f | |||
7feaa7af56 | |||
834157030c | |||
a59a42ffd9 | |||
f4c1bf9587 | |||
adc8c83102 | |||
e3fd4b3576 | |||
4019f2f376 | |||
51b943b576 | |||
de552db4c8 | |||
8beb33b7c3 | |||
05e3916478 | |||
414bfefb21 | |||
fd5e0b5b22 | |||
bd925418fd | |||
42a4a2e58e | |||
95be1e72d3 | |||
ecbf7d8b78 | |||
92386ac8ce | |||
dabfa2ecef | |||
00a408ac6c | |||
b67b1daf7c | |||
f83751c07d | |||
f5e3cd5a50 | |||
478fb174c5 | |||
30dfe4ff04 | |||
bdc775dcbd | |||
717d636497 | |||
64b0562bc4 | |||
eced1b7984 | |||
da3dd3a2fe | |||
3e166a3fca | |||
d090b18655 | |||
e2d28f442c | |||
496240c48b | |||
|
0bf5ae70eb | ||
|
bcaf80e2e1 | ||
|
21bf460b28 | ||
|
a4bbb837d7 | ||
|
1a438fc32e |
3
.gitignore
vendored
3
.gitignore
vendored
@ -162,3 +162,6 @@ TASK.md
|
|||||||
inline_bot.py
|
inline_bot.py
|
||||||
.vscode
|
.vscode
|
||||||
migrate.py
|
migrate.py
|
||||||
|
venv_linux
|
||||||
|
validation/*
|
||||||
|
!validation/*.json
|
20
.renovaterc
Normal file
20
.renovaterc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
],
|
||||||
|
"baseBranches": [
|
||||||
|
"dev"
|
||||||
|
],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchUpdateTypes": [
|
||||||
|
"minor",
|
||||||
|
"patch",
|
||||||
|
"pin",
|
||||||
|
"digest"
|
||||||
|
],
|
||||||
|
"automerge": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
233
README.md
233
README.md
@ -1,6 +1,11 @@
|
|||||||
# HoloCheckerBot
|
<h1 align="center">HoloCheckerBot</h1>
|
||||||
|
|
||||||
Small Telegram bot made on Pyrogram
|
<p align="center">Small Telegram bot made on Pyrogram</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://git.end-play.xyz/HoloUA/Telegram/src/branch/master/LICENSE"><img alt="License: GPL" src="https://img.shields.io/badge/License-GPL-blue"></a>
|
||||||
|
<a href="https://git.end-play.xyz/HoloUA/Telegram"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## What can this bot do?
|
## What can this bot do?
|
||||||
|
|
||||||
@ -14,234 +19,18 @@ Small Telegram bot made on Pyrogram
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. `git clone https://git.end-play.xyz/profitroll/HoloCheckerBot.git`
|
1. `git clone https://git.end-play.xyz/HoloUA/Telegram.git`
|
||||||
2. `cd HoloCheckerBot`
|
2. `cd Telegram`
|
||||||
3. Install Python 3.7+ (at least 3.9 is recommended) for your OS
|
3. Install Python 3.7+ (at least 3.9 is recommended) for your OS
|
||||||
4. `python3 -m pip install -r requirements.txt`
|
4. `python3 -m pip install -r requirements.txt`
|
||||||
5. Run it with `python3 main.py` after configuring
|
5. Run it with `python3 holochecker.py` after configuring
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
So bot has its "config_example.json" and it needs to be changed.
|
So bot has its "config_example.json" and it needs to be changed.
|
||||||
Copy this file to "config.json" and open it with any text editor.
|
Copy this file to "config.json" and open it with any text editor.
|
||||||
|
|
||||||
You can see config file with all the comments below:
|
You should also install [HoloCheckerAPI](https://git.end-play.xyz/HoloUA/API) for inline requests to work.
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"locale": "uk",
|
|
||||||
"debug": false,
|
|
||||||
"owner": 0,
|
|
||||||
"age_allowed": 0,
|
|
||||||
"api": "http://example.com",
|
|
||||||
"inline_preview_count": 7,
|
|
||||||
"remove_application_time": -1,
|
|
||||||
"search_radius": 50,
|
|
||||||
"admins": [],
|
|
||||||
"groups": {
|
|
||||||
"admin": 0,
|
|
||||||
"users": 0
|
|
||||||
},
|
|
||||||
"bot": {
|
|
||||||
"api_id": 0,
|
|
||||||
"api_hash": "",
|
|
||||||
"bot_token": ""
|
|
||||||
},
|
|
||||||
"database": {
|
|
||||||
"user": null,
|
|
||||||
"password": null,
|
|
||||||
"host": "127.0.0.1",
|
|
||||||
"port": 27017,
|
|
||||||
"name": "holochecker"
|
|
||||||
},
|
|
||||||
"geocoding": {
|
|
||||||
"username": "demo"
|
|
||||||
},
|
|
||||||
"logging": {
|
|
||||||
"size": 512,
|
|
||||||
"location": "logs"
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"general": {
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"applications": {
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"sponsorships": {
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"warnings": {
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"invites_check": {
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"dinovoice": {
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
"spoilers": {
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scheduler": {
|
|
||||||
"birthdays": {
|
|
||||||
"time": 9,
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"sponsorships": {
|
|
||||||
"time": 9,
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"cache_avatars": {
|
|
||||||
"interval": 6,
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"cache_members": {
|
|
||||||
"interval": 30,
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"cache_admins": {
|
|
||||||
"interval": 120,
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"locations": {
|
|
||||||
"cache": "cache",
|
|
||||||
"locale": "locale"
|
|
||||||
},
|
|
||||||
"commands": {
|
|
||||||
"rules": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"general"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"spoiler": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"spoilers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"cancel": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"spoilers",
|
|
||||||
"applications",
|
|
||||||
"sponsorships"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nearby": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins",
|
|
||||||
"group_users",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"warn": {
|
|
||||||
"permissions": [
|
|
||||||
"group_users"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"warnings"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"reapply": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sponsorship": {
|
|
||||||
"permissions": [
|
|
||||||
"users",
|
|
||||||
"admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"sponsorships"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"reboot": {
|
|
||||||
"permissions": [
|
|
||||||
"owner"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"general"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"permissions": [
|
|
||||||
"admins",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"permissions": [
|
|
||||||
"admins",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"general"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"identify": {
|
|
||||||
"permissions": [
|
|
||||||
"admins",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications",
|
|
||||||
"sponsorships"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"application": {
|
|
||||||
"permissions": [
|
|
||||||
"admins",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"applications": {
|
|
||||||
"permissions": [
|
|
||||||
"admins",
|
|
||||||
"group_admins"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"applications"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"resetcommands": {
|
|
||||||
"permissions": [
|
|
||||||
"owner"
|
|
||||||
],
|
|
||||||
"modules": [
|
|
||||||
"general"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
After all of that you're good to go! Happy using :)
|
After all of that you're good to go! Happy using :)
|
||||||
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
from os import makedirs, path, sep
|
|
||||||
from fastapi import FastAPI, HTTPException
|
|
||||||
from fastapi.responses import FileResponse, JSONResponse, Response
|
|
||||||
from starlette.status import HTTP_404_NOT_FOUND
|
|
||||||
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.get("/check", response_class=JSONResponse, include_in_schema=False)
|
|
||||||
@app.head("/check", response_class=JSONResponse, include_in_schema=False)
|
|
||||||
async def check():
|
|
||||||
return JSONResponse({"detail": "I'm alright, thank you"})
|
|
||||||
|
|
||||||
@app.get("/", response_class=FileResponse, include_in_schema=False)
|
|
||||||
async def avatar_get(avatar_id: str):
|
|
||||||
if path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}'):
|
|
||||||
return FileResponse(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}', media_type="image/jpg")
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="File not found")
|
|
||||||
|
|
||||||
@app.head("/", response_class=Response, include_in_schema=False)
|
|
||||||
async def avatar_head(avatar_id: str):
|
|
||||||
if path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}'):
|
|
||||||
return Response(headers={"Content-Length": path.getsize(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}')})
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="File not found")
|
|
16
app.py
16
app.py
@ -4,11 +4,19 @@ from modules.logging import logWrite
|
|||||||
from modules.utils import configGet, jsonLoad
|
from modules.utils import configGet, jsonLoad
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram.errors import bad_request_400
|
from pyrogram.errors import bad_request_400
|
||||||
|
from convopyro import Conversation
|
||||||
|
|
||||||
|
app = Client(
|
||||||
|
"holochecker",
|
||||||
|
bot_token=configGet("bot_token", "bot"),
|
||||||
|
api_id=configGet("api_id", "bot"),
|
||||||
|
api_hash=configGet("api_hash", "bot"),
|
||||||
|
)
|
||||||
|
|
||||||
|
Conversation(app)
|
||||||
|
|
||||||
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):
|
||||||
|
|
||||||
# Check if user is mentioned in config
|
# Check if user is mentioned in config
|
||||||
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
|
||||||
@ -26,7 +34,9 @@ async def isAnAdmin(admin_id):
|
|||||||
if member.user.id == admin_id:
|
if member.user.id == admin_id:
|
||||||
return True
|
return True
|
||||||
except bad_request_400.ChannelInvalid:
|
except bad_request_400.ChannelInvalid:
|
||||||
logWrite(f"Could not get users in admin group to answer isAnAdmin(). Bot is likely not in the group.")
|
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
|
return False
|
BIN
assets/event_easter_2023/stage_bonus.jpg
Normal file
BIN
assets/event_easter_2023/stage_bonus.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
@ -1,5 +1,8 @@
|
|||||||
class PlaceNotFoundError(Exception):
|
class PlaceNotFoundError(Exception):
|
||||||
"""Query provided did not lead to any city or populated area"""
|
"""Query provided did not lead to any city or populated area"""
|
||||||
|
|
||||||
def __init__(self, query):
|
def __init__(self, query):
|
||||||
self.query = query
|
self.query = query
|
||||||
super().__init__(f"Could not find any place on geonames.org of feature classes A and P by query '{self.query}'")
|
super().__init__(
|
||||||
|
f"Could not find any place on geonames.org of feature classes A and P by query '{self.query}'"
|
||||||
|
)
|
||||||
|
@ -1,24 +1,38 @@
|
|||||||
"""Exceptions that are meant to be used by HoloUser class
|
"""Exceptions that are meant to be used by HoloUser class
|
||||||
and other modules that handle those exceptions"""
|
and other modules that handle those exceptions"""
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.user_id = user_id
|
self.user_id = user_id
|
||||||
super().__init__(f"User of type {type(self.user)} with id {self.user_id} was not found")
|
super().__init__(
|
||||||
|
f"User of type {type(self.user)} with id {self.user_id} was not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserInvalidError(Exception):
|
class UserInvalidError(Exception):
|
||||||
"""Provided to HoloUser object is not supported"""
|
"""Provided to HoloUser object is not supported"""
|
||||||
|
|
||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
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 LabelTooLongError(Exception):
|
class LabelTooLongError(Exception):
|
||||||
def __init__(self, label: str) -> None:
|
def __init__(self, label: str) -> None:
|
||||||
self.label = label
|
self.label = label
|
||||||
super().__init__(f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)")
|
super().__init__(
|
||||||
|
f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LabelSettingError(Exception):
|
class LabelSettingError(Exception):
|
||||||
def __init__(self, exp: Exception, trace: str) -> None:
|
def __init__(self, exp: Exception, trace: str) -> None:
|
||||||
super().__init__(f"❌ **Could not set label**\n\nException: `{exp}`\n\n**Traceback:**\n```\n{trace}\n```")
|
super().__init__(
|
||||||
|
f"❌ **Could not set label**\n\nException: `{exp}`\n\n**Traceback:**\n```\n{trace}\n```"
|
||||||
|
)
|
||||||
|
@ -1,18 +1,46 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from asyncio import sleep
|
||||||
|
from ftfy import fix_text
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from app import app, isAnAdmin
|
from app import app, isAnAdmin
|
||||||
from typing import Any, List, Literal, Union
|
from typing import Any, List, Literal, Union
|
||||||
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup
|
from pyrogram.types import (
|
||||||
|
User,
|
||||||
|
ChatMember,
|
||||||
|
ChatPrivileges,
|
||||||
|
Chat,
|
||||||
|
Message,
|
||||||
|
Photo,
|
||||||
|
Video,
|
||||||
|
Document,
|
||||||
|
Animation,
|
||||||
|
Voice,
|
||||||
|
ForceReply,
|
||||||
|
ReplyKeyboardMarkup,
|
||||||
|
)
|
||||||
from pyrogram.errors import bad_request_400
|
from pyrogram.errors import bad_request_400
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from classes.errors.geo import PlaceNotFoundError
|
from classes.errors.geo import PlaceNotFoundError
|
||||||
from classes.errors.holo_user import UserInvalidError, UserNotFoundError, LabelTooLongError, LabelSettingError
|
from classes.errors.holo_user import (
|
||||||
|
UserInvalidError,
|
||||||
|
UserNotFoundError,
|
||||||
|
LabelTooLongError,
|
||||||
|
LabelSettingError,
|
||||||
|
)
|
||||||
from classes.templates import DefaultApplicationTemp, DefaultSponsorshipTemp
|
from classes.templates import DefaultApplicationTemp, DefaultSponsorshipTemp
|
||||||
from modules.database import col_tmp, col_users, col_applications, col_sponsorships, col_messages, col_spoilers
|
from modules.database import (
|
||||||
|
col_tmp,
|
||||||
|
col_users,
|
||||||
|
col_applications,
|
||||||
|
col_sponsorships,
|
||||||
|
col_messages,
|
||||||
|
col_spoilers,
|
||||||
|
)
|
||||||
from modules.logging import logWrite
|
from modules.logging import logWrite
|
||||||
from modules.utils import configGet, find_location, locale, should_quote
|
from modules.utils import configGet, find_location, locale, should_quote
|
||||||
|
|
||||||
class HoloUser():
|
|
||||||
|
class HoloUser:
|
||||||
"""This object represents a user of HoloChecker bot.
|
"""This object represents a user of HoloChecker bot.
|
||||||
It is primarily used to interact with a database in a more python-friendly way,
|
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.
|
as well as provide better programming experience in case of adding new features, etc.
|
||||||
@ -65,17 +93,32 @@ class HoloUser():
|
|||||||
self.username = holo_user["tg_username"]
|
self.username = holo_user["tg_username"]
|
||||||
|
|
||||||
if isinstance(user, User):
|
if isinstance(user, User):
|
||||||
|
if (
|
||||||
if (self.name != user.first_name) and hasattr(user, "first_name") and (user.first_name is not None):
|
(self.name != user.first_name)
|
||||||
|
and hasattr(user, "first_name")
|
||||||
|
and (user.first_name is not None)
|
||||||
|
):
|
||||||
self.set("name", user.first_name, db_key="tg_name")
|
self.set("name", user.first_name, db_key="tg_name")
|
||||||
|
|
||||||
if (self.phone != user.phone_number) and hasattr(user, "phone") and (user.phone_number is not None):
|
if (
|
||||||
|
(self.phone != user.phone_number)
|
||||||
|
and hasattr(user, "phone")
|
||||||
|
and (user.phone_number is not None)
|
||||||
|
):
|
||||||
self.set("phone", user.phone_number, db_key="tg_phone")
|
self.set("phone", user.phone_number, db_key="tg_phone")
|
||||||
|
|
||||||
if (self.locale != user.language_code) and hasattr(user, "locale") and (user.language_code is not None):
|
if (
|
||||||
|
(self.locale != user.language_code)
|
||||||
|
and hasattr(user, "locale")
|
||||||
|
and (user.language_code is not None)
|
||||||
|
):
|
||||||
self.set("locale", user.language_code, db_key="tg_locale")
|
self.set("locale", user.language_code, db_key="tg_locale")
|
||||||
|
|
||||||
if (self.username != user.username) and hasattr(user, "username") and (user.username is not None):
|
if (
|
||||||
|
(self.username != user.username)
|
||||||
|
and hasattr(user, "username")
|
||||||
|
and (user.username is not None)
|
||||||
|
):
|
||||||
self.set("username", user.username, db_key="tg_username")
|
self.set("username", user.username, db_key="tg_username")
|
||||||
|
|
||||||
def set(self, key: str, value: Any, db_key: Union[str, None] = None) -> None:
|
def set(self, key: str, value: Any, db_key: Union[str, None] = None) -> None:
|
||||||
@ -89,10 +132,13 @@ class HoloUser():
|
|||||||
raise AttributeError()
|
raise AttributeError()
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
db_key = key if db_key is None else db_key
|
db_key = key if db_key is None else db_key
|
||||||
col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { db_key: value } }, upsert=True)
|
col_users.update_one(
|
||||||
|
filter={"_id": self.db_id}, update={"$set": {db_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,
|
async def message(
|
||||||
|
self,
|
||||||
context: Message,
|
context: Message,
|
||||||
origin: Union[Message, None] = None,
|
origin: Union[Message, None] = None,
|
||||||
text: Union[str, None] = None,
|
text: Union[str, None] = None,
|
||||||
@ -103,7 +149,7 @@ class HoloUser():
|
|||||||
animation: Union[str, Animation, None] = None,
|
animation: Union[str, Animation, None] = None,
|
||||||
voice: Union[str, Voice, None] = None,
|
voice: Union[str, Voice, None] = None,
|
||||||
adm_origin: bool = False,
|
adm_origin: bool = False,
|
||||||
adm_context: bool = False
|
adm_context: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Send a message to user
|
"""Send a message to user
|
||||||
|
|
||||||
@ -121,20 +167,37 @@ class HoloUser():
|
|||||||
* adm_context (`bool`, *optional*): Whether context sender is an admin. Defaults to False.
|
* adm_context (`bool`, *optional*): Whether context sender is an admin. Defaults to False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if text is not None:
|
||||||
|
text = fix_text(text)
|
||||||
|
elif caption is not None:
|
||||||
|
caption = fix_text(caption)
|
||||||
|
|
||||||
# Check if any text available and log message sending
|
# Check if any text available and log message sending
|
||||||
if text is not None:
|
if text is not None:
|
||||||
logWrite(f"{context.from_user.id} sent message '{text}' to {self.id}")
|
logWrite(
|
||||||
|
f"{context.from_user.id} sent message '{text}' to {self.id} (source message: {context.id})"
|
||||||
|
)
|
||||||
elif caption is not None:
|
elif caption is not None:
|
||||||
logWrite(f"{context.from_user.id} sent message '{caption}' to {self.id}")
|
logWrite(
|
||||||
|
f"{context.from_user.id} sent message '{caption}' to {self.id} (source message: {context.id})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logWrite(f"{context.from_user.id} sent message to {self.id}")
|
logWrite(
|
||||||
|
f"{context.from_user.id} sent message to {self.id} (source message: {context.id})"
|
||||||
|
)
|
||||||
|
|
||||||
# Add notices for admin or user
|
# Add notices for admin or user
|
||||||
if text is not None:
|
if text is not None:
|
||||||
if adm_context:
|
if adm_context:
|
||||||
text += locale("message_reply_notice", "message")
|
text += locale("message_reply_notice", "message")
|
||||||
elif adm_origin:
|
elif adm_origin:
|
||||||
text = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + text + locale("message_reply_notice", "message")
|
text = (
|
||||||
|
locale("message_from", "message").format(
|
||||||
|
context.from_user.first_name, context.from_user.id
|
||||||
|
)
|
||||||
|
+ text
|
||||||
|
+ locale("message_reply_notice", "message")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
text = locale("message_reply_notice", "message")
|
text = locale("message_reply_notice", "message")
|
||||||
|
|
||||||
@ -142,77 +205,118 @@ class HoloUser():
|
|||||||
if adm_context:
|
if adm_context:
|
||||||
caption += locale("message_reply_notice", "message")
|
caption += locale("message_reply_notice", "message")
|
||||||
elif adm_origin:
|
elif adm_origin:
|
||||||
caption = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + caption + locale("message_reply_notice", "message")
|
caption = (
|
||||||
|
locale("message_from", "message").format(
|
||||||
|
context.from_user.first_name, context.from_user.id
|
||||||
|
)
|
||||||
|
+ caption
|
||||||
|
+ locale("message_reply_notice", "message")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
caption = locale("message_reply_notice", "message")
|
caption = locale("message_reply_notice", "message")
|
||||||
|
|
||||||
# Try sending the message
|
# Try sending the message
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# Check if origin message exists
|
# Check if origin message exists
|
||||||
# This check decides whether we send_ a message or reply_ to one
|
# This check decides whether we send_ a message or reply_ to one
|
||||||
if origin is not None:
|
if origin is not None:
|
||||||
|
|
||||||
if photo is not None:
|
if photo is not None:
|
||||||
if isinstance(photo, Photo):
|
if isinstance(photo, Photo):
|
||||||
photo = photo.file_id
|
photo = photo.file_id
|
||||||
new_message = await origin.reply_cached_media(photo, caption=caption, quote=True)
|
new_message = await origin.reply_cached_media(
|
||||||
|
photo, caption=caption, quote=True
|
||||||
|
)
|
||||||
elif video is not None:
|
elif video is not None:
|
||||||
if isinstance(video, Video):
|
if isinstance(video, Video):
|
||||||
video = video.file_id
|
video = video.file_id
|
||||||
new_message = await origin.reply_cached_media(video, caption=caption, quote=True)
|
new_message = await origin.reply_cached_media(
|
||||||
|
video, caption=caption, quote=True
|
||||||
|
)
|
||||||
elif file is not None:
|
elif file is not None:
|
||||||
if isinstance(file, Document):
|
if isinstance(file, Document):
|
||||||
file = file.file_id
|
file = file.file_id
|
||||||
new_message = await origin.reply_document(file, caption=caption, quote=True)
|
new_message = await origin.reply_cached_media(
|
||||||
|
file, caption=caption, quote=True
|
||||||
|
)
|
||||||
elif animation is not None:
|
elif animation is not None:
|
||||||
if isinstance(animation, Animation):
|
if isinstance(animation, Animation):
|
||||||
animation = animation.file_id
|
animation = animation.file_id
|
||||||
new_message = await origin.reply_cached_media(animation, caption=caption, quote=True)
|
new_message = await origin.reply_cached_media(
|
||||||
|
animation, caption=caption, quote=True
|
||||||
|
)
|
||||||
elif voice is not None:
|
elif voice is not None:
|
||||||
if isinstance(voice, Voice):
|
if isinstance(voice, Voice):
|
||||||
voice = voice.file_id
|
voice = voice.file_id
|
||||||
new_message = await origin.reply_voice(voice, caption=caption, quote=True)
|
new_message = await origin.reply_voice(
|
||||||
|
voice, caption=caption, quote=True
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
new_message = await origin.reply_text(text, quote=True)
|
new_message = await origin.reply_text(text, quote=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if photo is not None:
|
if photo is not None:
|
||||||
if isinstance(photo, Photo):
|
if isinstance(photo, Photo):
|
||||||
photo = photo.file_id
|
photo = photo.file_id
|
||||||
new_message = await app.send_cached_media(self.id, photo, caption=caption)
|
new_message = await app.send_cached_media(
|
||||||
|
self.id, photo, caption=caption
|
||||||
|
)
|
||||||
elif video is not None:
|
elif video is not None:
|
||||||
if isinstance(video, Video):
|
if isinstance(video, Video):
|
||||||
video = video.file_id
|
video = video.file_id
|
||||||
new_message = await app.send_cached_media(self.id, video, caption=caption)
|
new_message = await app.send_cached_media(
|
||||||
|
self.id, video, caption=caption
|
||||||
|
)
|
||||||
elif file is not None:
|
elif file is not None:
|
||||||
if isinstance(file, Document):
|
if isinstance(file, Document):
|
||||||
file = file.file_id
|
file = file.file_id
|
||||||
new_message = await app.send_document(self.id, file, caption=caption)
|
new_message = await app.send_cached_media(
|
||||||
|
self.id, file, caption=caption
|
||||||
|
)
|
||||||
elif animation is not None:
|
elif animation is not None:
|
||||||
if isinstance(animation, Animation):
|
if isinstance(animation, Animation):
|
||||||
animation = animation.file_id
|
animation = animation.file_id
|
||||||
new_message = await app.send_cached_media(self.id, animation, caption=caption)
|
new_message = await app.send_cached_media(
|
||||||
|
self.id, animation, caption=caption
|
||||||
|
)
|
||||||
elif voice is not None:
|
elif voice is not None:
|
||||||
if isinstance(voice, Voice):
|
if isinstance(voice, Voice):
|
||||||
voice = voice.file_id
|
voice = voice.file_id
|
||||||
new_message = await app.send_cached_media(self.id, voice, caption=caption)
|
new_message = await app.send_cached_media(
|
||||||
|
self.id, voice, caption=caption
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
new_message = await app.send_message(self.id, text)
|
new_message = await app.send_message(self.id, text)
|
||||||
|
|
||||||
# Acknowledge sending a message and save entry into DB
|
# Acknowledge sending a message and save entry into DB
|
||||||
await context.reply_text(locale("message_sent", "message"), quote=should_quote(context))
|
await context.reply_text(
|
||||||
col_messages.insert_one({"origin": {"chat": context.chat.id, "id": context.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
|
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
|
# Report to admin and to sender about message sending failure
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{format_exc()}")
|
logWrite(
|
||||||
|
f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{format_exc()}"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
await app.send_message(configGet("owner"), locale("message_traceback", "message").format(context.from_user.id, self.id, exp, format_exc()))
|
await app.send_message(
|
||||||
|
configGet("owner"),
|
||||||
|
locale("message_traceback", "message").format(
|
||||||
|
context.from_user.id, self.id, exp, format_exc()
|
||||||
|
),
|
||||||
|
)
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
|
logWrite(
|
||||||
await context.reply_text(locale("message_error", "message"), quote=should_quote(context))
|
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 label_set(self, chat: Chat, label: str) -> None:
|
async def label_set(self, chat: Chat, label: str) -> None:
|
||||||
"""Set label in destination group
|
"""Set label in destination group
|
||||||
@ -225,9 +329,18 @@ class HoloUser():
|
|||||||
raise LabelTooLongError(label)
|
raise LabelTooLongError(label)
|
||||||
self.label = label
|
self.label = label
|
||||||
try:
|
try:
|
||||||
await app.promote_chat_member(configGet("users", "groups"), self.id, privileges=ChatPrivileges(can_pin_messages=True, can_manage_video_chats=True))
|
await app.promote_chat_member(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
self.id,
|
||||||
|
privileges=ChatPrivileges(
|
||||||
|
can_pin_messages=True, can_manage_video_chats=True
|
||||||
|
),
|
||||||
|
)
|
||||||
if not await isAnAdmin(self.id):
|
if not await isAnAdmin(self.id):
|
||||||
await app.set_administrator_title(configGet("users", "groups"), self.id, label)
|
await sleep(0.5)
|
||||||
|
await app.set_administrator_title(
|
||||||
|
configGet("users", "groups"), self.id, label
|
||||||
|
)
|
||||||
self.set("label", label)
|
self.set("label", label)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not set {self.id}'s title to '{self.label}' due to {exp}")
|
logWrite(f"Could not set {self.id}'s title to '{self.label}' due to {exp}")
|
||||||
@ -243,13 +356,19 @@ class HoloUser():
|
|||||||
self.set("label", "")
|
self.set("label", "")
|
||||||
await app.set_administrator_title(configGet("users", "groups"), self.id, "")
|
await app.set_administrator_title(configGet("users", "groups"), self.id, "")
|
||||||
if not await isAnAdmin(self.id):
|
if not await isAnAdmin(self.id):
|
||||||
await app.promote_chat_member(configGet("users", "groups"), self.id, privileges=ChatPrivileges(
|
await app.promote_chat_member(
|
||||||
can_manage_chat=False,
|
configGet("users", "groups"),
|
||||||
can_pin_messages=False,
|
self.id,
|
||||||
can_manage_video_chats=False
|
privileges=ChatPrivileges(
|
||||||
))
|
can_manage_chat=False,
|
||||||
|
can_pin_messages=False,
|
||||||
|
can_manage_video_chats=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def application_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]:
|
def application_state(
|
||||||
|
self,
|
||||||
|
) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]:
|
||||||
"""Check the current state of application in tmp collection
|
"""Check the current state of application in tmp collection
|
||||||
|
|
||||||
### Returns:
|
### Returns:
|
||||||
@ -267,16 +386,21 @@ class HoloUser():
|
|||||||
### Returns:
|
### Returns:
|
||||||
* `bool`: `True` if yes and `False` if no
|
* `bool`: `True` if yes and `False` if no
|
||||||
"""
|
"""
|
||||||
return True if col_applications.find_one({"user": self.id}) is not None else False
|
return (
|
||||||
|
True if col_applications.find_one({"user": self.id}) is not None else False
|
||||||
|
)
|
||||||
|
|
||||||
def application_restart(self, reapply: bool = False) -> None:
|
def application_restart(self, reapply: bool = False) -> None:
|
||||||
"""Reset application of a user in tmp collection and replace it with an empty one
|
"""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:
|
if col_tmp.find_one({"user": self.id, "type": "application"}) is None:
|
||||||
col_tmp.insert_one(document=DefaultApplicationTemp(self.id).dict)
|
col_tmp.insert_one(
|
||||||
|
document=DefaultApplicationTemp(self.id, reapply=reapply).dict
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
col_tmp.delete_one({"user": self.id, "type": "application"})
|
col_tmp.find_one_and_replace(
|
||||||
col_tmp.insert_one(document=DefaultApplicationTemp(self.id, reapply=reapply).dict)
|
{"user": self.id, "type": "application"},
|
||||||
|
DefaultApplicationTemp(self.id, reapply=reapply).dict,
|
||||||
|
)
|
||||||
|
|
||||||
async def application_next(self, query: str, msg: Message) -> None:
|
async def application_next(self, query: str, msg: Message) -> None:
|
||||||
"""Move on filling application of user
|
"""Move on filling application of user
|
||||||
@ -310,82 +434,283 @@ class HoloUser():
|
|||||||
# return
|
# return
|
||||||
|
|
||||||
if progress["state"] == "fill" and progress["sent"] is False:
|
if progress["state"] == "fill" and progress["sent"] is False:
|
||||||
|
if msg.text is not None:
|
||||||
|
msg.text = fix_text(str(msg.text))
|
||||||
|
|
||||||
if stage == 2:
|
if stage == 2:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
input_dt = datetime.strptime(query, "%d.%m.%Y")
|
input_dt = datetime.strptime(query, "%d.%m.%Y")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format")
|
logWrite(
|
||||||
await msg.reply_text(locale(f"question2_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
|
f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"question2_invalid", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if datetime.now() <= input_dt:
|
if (datetime.now() <= input_dt) or (
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {stage} due to joking")
|
(datetime.now() - input_dt).days
|
||||||
await msg.reply_text(locale("question2_joke", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply", locale=self.locale))))
|
) > (
|
||||||
|
(
|
||||||
|
datetime.now()
|
||||||
|
- datetime.now().replace(
|
||||||
|
year=datetime.now().year - configGet("age_maximum")
|
||||||
|
)
|
||||||
|
).days
|
||||||
|
):
|
||||||
|
logWrite(
|
||||||
|
f"User {msg.from_user.id} failed stage {stage} due to joking"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("question2_joke", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale("question2", "force_reply", locale=self.locale)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
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) < (
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {stage} due to being underage")
|
(
|
||||||
await msg.reply_text(locale("question2_underage", "message", locale=self.locale).format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply", locale=self.locale))))
|
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", locale=self.locale
|
||||||
|
).format(str(configGet("age_allowed"))),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale("question2", "force_reply", locale=self.locale)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
progress["application"][str(stage)] = input_dt
|
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}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale))))
|
{"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", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage+1}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif stage == 3:
|
elif stage == 3:
|
||||||
try:
|
try:
|
||||||
progress["application"][str(stage)] = find_location(query)
|
progress["application"][str(stage)] = find_location(query)
|
||||||
if ("lat" in progress["application"][str(stage)] and "lng" in progress["application"][str(stage)]):
|
if (
|
||||||
progress["application"][str(stage)]["location"] = [float(progress["application"][str(stage)]["lng"]), float(progress["application"][str(stage)]["lat"])]
|
"lat" in progress["application"][str(stage)]
|
||||||
|
and "lng" in progress["application"][str(stage)]
|
||||||
|
):
|
||||||
|
progress["application"][str(stage)]["location"] = [
|
||||||
|
float(progress["application"][str(stage)]["lng"]),
|
||||||
|
float(progress["application"][str(stage)]["lat"]),
|
||||||
|
]
|
||||||
del progress["application"][str(stage)]["lat"]
|
del progress["application"][str(stage)]["lat"]
|
||||||
del progress["application"][str(stage)]["lng"]
|
del progress["application"][str(stage)]["lng"]
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale("question3_found", "message", locale=self.locale).format(progress["application"][str(stage)]["name"], progress["application"][str(stage)]["adminName1"]))
|
{"user": {"$eq": self.id}, "type": {"$eq": "application"}},
|
||||||
await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale))))
|
{
|
||||||
|
"$set": {
|
||||||
|
"application": progress["application"],
|
||||||
|
"stage": progress["stage"] + 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("question3_found", "message", locale=self.locale).format(
|
||||||
|
progress["application"][str(stage)]["name"],
|
||||||
|
progress["application"][str(stage)]["adminName1"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"question{stage+1}", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage+1}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
except PlaceNotFoundError:
|
except PlaceNotFoundError:
|
||||||
await msg.reply_text(locale("question3_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
|
await msg.reply_text(
|
||||||
|
locale("question3_invalid", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
await msg.reply_text(locale("question3_error", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
|
await msg.reply_text(
|
||||||
|
locale("question3_error", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
await app.send_message(configGet("owner"), locale("question3_traceback", "message", locale=self.locale).format(query, exp, format_exc()))
|
await app.send_message(
|
||||||
|
configGet("owner"),
|
||||||
|
locale(
|
||||||
|
"question3_traceback", "message", locale=self.locale
|
||||||
|
).format(query, exp, format_exc()),
|
||||||
|
)
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
|
logWrite(
|
||||||
|
f"Could not notify admin about failure when sending message! Admin has never interacted with bot!"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
elif stage == 10:
|
elif stage == 10:
|
||||||
|
if len(query) > 1024:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("question10_too_long", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
progress["application"][str(stage)] = query
|
progress["application"][str(stage)] = query
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "complete": True}})
|
col_tmp.update_one(
|
||||||
|
{"user": {"$eq": self.id}, "type": {"$eq": "application"}},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"application": progress["application"],
|
||||||
|
"complete": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
application_content = []
|
application_content = []
|
||||||
i = 1
|
i = 1
|
||||||
for question in progress["application"]:
|
for question in progress["application"]:
|
||||||
if i == 2:
|
if i == 2:
|
||||||
age = relativedelta(datetime.now(), progress['application']['2'])
|
age = relativedelta(
|
||||||
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
|
datetime.now(), progress["application"]["2"]
|
||||||
|
)
|
||||||
|
application_content.append(
|
||||||
|
f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)"
|
||||||
|
)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
if progress['application']['3']['countryCode'] == "UA":
|
if progress["application"]["3"]["countryCode"] == "UA":
|
||||||
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})")
|
application_content.append(
|
||||||
|
f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})")
|
application_content.append(
|
||||||
|
f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application'][question]}")
|
application_content.append(
|
||||||
|
f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application'][question]}"
|
||||||
|
)
|
||||||
i += 1
|
i += 1
|
||||||
await msg.reply_text(locale("confirm", "message", locale=self.locale).format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True))
|
await msg.reply_text(
|
||||||
|
locale("confirm", "message", locale=self.locale).format(
|
||||||
|
"\n".join(application_content)
|
||||||
|
),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("confirm", "keyboard", locale=self.locale),
|
||||||
|
resize_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
if len(query) > 256:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("question_too_long", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
progress["application"][str(stage)] = query
|
progress["application"][str(stage)] = query
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale))))
|
{"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", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"question{stage+1}", "force_reply", locale=self.locale
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"User {self.id} completed stage {stage} of application")
|
logWrite(f"User {self.id} completed stage {stage} of application")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
def sponsorship_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]:
|
def sponsorship_state(
|
||||||
|
self,
|
||||||
|
) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]:
|
||||||
"""Check the current state of sponsorship in tmp collection
|
"""Check the current state of sponsorship in tmp collection
|
||||||
|
|
||||||
### Returns:
|
### Returns:
|
||||||
@ -403,18 +728,26 @@ class HoloUser():
|
|||||||
### Returns:
|
### Returns:
|
||||||
* `bool`: `True` if yes and `False` if no
|
* `bool`: `True` if yes and `False` if no
|
||||||
"""
|
"""
|
||||||
return True if col_sponsorships.find_one({"user": self.id, "expires": {"$gt": datetime.now()}}) is not None else False
|
return (
|
||||||
|
True
|
||||||
|
if col_sponsorships.find_one(
|
||||||
|
{"user": self.id, "expires": {"$gt": datetime.now()}}
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
|
||||||
def sponsorship_restart(self) -> None:
|
def sponsorship_restart(self) -> None:
|
||||||
"""Reset sponsorship of a user in tmp collection and replace it with an empty one
|
"""Reset sponsorship of a user in tmp collection and replace it with an empty one"""
|
||||||
"""
|
|
||||||
if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is None:
|
if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is None:
|
||||||
col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict)
|
col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict)
|
||||||
else:
|
else:
|
||||||
col_tmp.delete_one({"user": self.id, "type": "sponsorship"})
|
col_tmp.delete_one({"user": self.id, "type": "sponsorship"})
|
||||||
col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict)
|
col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict)
|
||||||
|
|
||||||
async def sponsorship_next(self, query: str, msg: Message, photo: Union[Photo, None] = None) -> None:
|
async def sponsorship_next(
|
||||||
|
self, query: str, msg: Message, photo: Union[Photo, None] = None
|
||||||
|
) -> None:
|
||||||
"""Move on filling sponsorship of user
|
"""Move on filling sponsorship of user
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
@ -425,57 +758,179 @@ class HoloUser():
|
|||||||
progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"})
|
progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"})
|
||||||
|
|
||||||
if progress is not None:
|
if progress is not None:
|
||||||
|
|
||||||
stage = progress["stage"]
|
stage = progress["stage"]
|
||||||
|
|
||||||
if progress["state"] == "fill" and progress["sent"] is False:
|
if msg.text is not None:
|
||||||
|
msg.text = fix_text(str(msg.text))
|
||||||
|
elif msg.caption is not None:
|
||||||
|
msg.caption = fix_text(msg.caption)
|
||||||
|
|
||||||
|
if progress["state"] == "fill" and progress["sent"] is False:
|
||||||
if stage == 1:
|
if stage == 1:
|
||||||
|
if len(query) > 240:
|
||||||
|
logWrite(
|
||||||
|
f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"sponsor1_invalid", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
progress["sponsorship"]["streamer"] = query
|
progress["sponsorship"]["streamer"] = query
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale))))
|
{"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"sponsorship": progress["sponsorship"],
|
||||||
|
"stage": progress["stage"] + 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"sponsor{stage+1}", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor{stage+1}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif stage == 2:
|
elif stage == 2:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
input_dt = datetime.strptime(query, "%d.%m.%Y")
|
input_dt = datetime.strptime(query, "%d.%m.%Y")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format")
|
logWrite(
|
||||||
await msg.reply_text(locale(f"sponsor2_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage}", "force_reply", locale=self.locale))))
|
f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"sponsor2_invalid", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor{stage}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if datetime.now() >= input_dt:
|
if datetime.now() >= input_dt:
|
||||||
logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending date in the past")
|
logWrite(
|
||||||
await msg.reply_text(locale("sponsor2_past", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale("sponsor2", "force_reply", locale=self.locale))))
|
f"User {msg.from_user.id} failed stage {stage} due to sending date in the past"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsor2_past", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
"sponsor2", "force_reply", locale=self.locale
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
progress["sponsorship"]["expires"] = input_dt
|
progress["sponsorship"]["expires"] = input_dt
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale))))
|
{"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"sponsorship": progress["sponsorship"],
|
||||||
|
"stage": progress["stage"] + 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"sponsor{stage+1}", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor{stage+1}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif stage == 3:
|
elif stage == 3:
|
||||||
|
|
||||||
if photo is not None:
|
if photo is not None:
|
||||||
progress["sponsorship"]["proof"] = photo.file_id
|
progress["sponsorship"]["proof"] = photo.file_id
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}})
|
col_tmp.update_one(
|
||||||
await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale))))
|
{"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"sponsorship": progress["sponsorship"],
|
||||||
|
"stage": progress["stage"] + 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(f"sponsor{stage+1}", "message", locale=self.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor{stage+1}",
|
||||||
|
"force_reply",
|
||||||
|
locale=self.locale,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif stage == 4:
|
elif stage == 4:
|
||||||
if len(query) > 16:
|
if len(query) > 16:
|
||||||
await msg.reply_text(locale("label_too_long", "message"), reply_markup=ForceReply(placeholder=str(locale("sponsor4", "force_reply", locale=self.locale))))
|
await msg.reply_text(
|
||||||
|
locale("label_too_long", "message"),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
"sponsor4", "force_reply", locale=self.locale
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
progress["sponsorship"]["label"] = query
|
progress["sponsorship"]["label"] = query
|
||||||
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}})
|
col_tmp.update_one(
|
||||||
|
{"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"sponsorship": progress["sponsorship"],
|
||||||
|
"complete": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
await msg.reply_cached_media(
|
await msg.reply_cached_media(
|
||||||
progress["sponsorship"]["proof"],
|
progress["sponsorship"]["proof"],
|
||||||
caption=locale("sponsor_confirm", "message", locale=self.locale).format(
|
caption=locale(
|
||||||
|
"sponsor_confirm", "message", locale=self.locale
|
||||||
|
).format(
|
||||||
progress["sponsorship"]["streamer"],
|
progress["sponsorship"]["streamer"],
|
||||||
progress["sponsorship"]["expires"].strftime("%d.%m.%Y"),
|
progress["sponsorship"]["expires"].strftime("%d.%m.%Y"),
|
||||||
progress["sponsorship"]["label"]
|
progress["sponsorship"]["label"],
|
||||||
),
|
),
|
||||||
reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True))
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("confirm", "keyboard", locale=self.locale),
|
||||||
|
resize_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
@ -491,4 +946,8 @@ class HoloUser():
|
|||||||
### Returns:
|
### Returns:
|
||||||
* `bool`: `True` if any not finished spoilers available and `False` if none.
|
* `bool`: `True` if any not finished spoilers available and `False` if none.
|
||||||
"""
|
"""
|
||||||
return False if col_spoilers.find_one({"user": self.id, "completed": False}) is None else True
|
return (
|
||||||
|
False
|
||||||
|
if col_spoilers.find_one({"user": self.id, "completed": False}) is None
|
||||||
|
else True
|
||||||
|
)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class DefaultApplicationTemp(dict):
|
class DefaultApplicationTemp(dict):
|
||||||
def __init__(self, user: int, reapply: bool = False):
|
def __init__(self, user: int, reapply: bool = False):
|
||||||
super().__init__({})
|
super().__init__({})
|
||||||
@ -23,10 +24,11 @@ class DefaultApplicationTemp(dict):
|
|||||||
"7": None,
|
"7": None,
|
||||||
"8": None,
|
"8": None,
|
||||||
"9": None,
|
"9": None,
|
||||||
"10": None
|
"10": None,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DefaultSponsorshipTemp(dict):
|
class DefaultSponsorshipTemp(dict):
|
||||||
def __init__(self, user: int):
|
def __init__(self, user: int):
|
||||||
super().__init__({})
|
super().__init__({})
|
||||||
@ -41,6 +43,6 @@ class DefaultSponsorshipTemp(dict):
|
|||||||
"streamer": None,
|
"streamer": None,
|
||||||
"expires": datetime.fromtimestamp(0),
|
"expires": datetime.fromtimestamp(0),
|
||||||
"proof": None,
|
"proof": None,
|
||||||
"label": ""
|
"label": "",
|
||||||
}
|
},
|
||||||
}
|
}
|
@ -3,7 +3,9 @@
|
|||||||
"debug": false,
|
"debug": false,
|
||||||
"owner": 0,
|
"owner": 0,
|
||||||
"age_allowed": 0,
|
"age_allowed": 0,
|
||||||
|
"age_maximum": 70,
|
||||||
"api": "http://example.com",
|
"api": "http://example.com",
|
||||||
|
"issues": "https://github.com/example/test/issues/new",
|
||||||
"inline_preview_count": 7,
|
"inline_preview_count": 7,
|
||||||
"remove_application_time": -1,
|
"remove_application_time": -1,
|
||||||
"search_radius": 50,
|
"search_radius": 50,
|
||||||
@ -51,7 +53,8 @@
|
|||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
"spoilers": {
|
"spoilers": {
|
||||||
"enabled": true
|
"enabled": true,
|
||||||
|
"allow_external": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
@ -61,6 +64,7 @@
|
|||||||
},
|
},
|
||||||
"sponsorships": {
|
"sponsorships": {
|
||||||
"time": 9,
|
"time": 9,
|
||||||
|
"grayout_days": 2,
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
"cache_avatars": {
|
"cache_avatars": {
|
||||||
@ -74,6 +78,15 @@
|
|||||||
"cache_admins": {
|
"cache_admins": {
|
||||||
"interval": 120,
|
"interval": 120,
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
},
|
||||||
|
"channels_monitor": {
|
||||||
|
"interval": 5,
|
||||||
|
"enabled": true,
|
||||||
|
"channels": []
|
||||||
|
},
|
||||||
|
"warnings_revocation": {
|
||||||
|
"interval": 6,
|
||||||
|
"enabled": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"locations": {
|
"locations": {
|
||||||
@ -114,7 +127,6 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
"users",
|
"users",
|
||||||
"admins",
|
"admins",
|
||||||
"group_users",
|
|
||||||
"group_admins"
|
"group_admins"
|
||||||
],
|
],
|
||||||
"modules": [
|
"modules": [
|
||||||
@ -123,7 +135,16 @@
|
|||||||
},
|
},
|
||||||
"warn": {
|
"warn": {
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"group_users"
|
"group_users_admins"
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
"warnings"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"warnings": {
|
||||||
|
"permissions": [
|
||||||
|
"admins",
|
||||||
|
"group_admins"
|
||||||
],
|
],
|
||||||
"modules": [
|
"modules": [
|
||||||
"warnings"
|
"warnings"
|
||||||
@ -166,6 +187,7 @@
|
|||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"permissions": [
|
"permissions": [
|
||||||
|
"users",
|
||||||
"admins",
|
"admins",
|
||||||
"group_admins"
|
"group_admins"
|
||||||
],
|
],
|
||||||
@ -183,16 +205,25 @@
|
|||||||
"sponsorships"
|
"sponsorships"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"application": {
|
"issue": {
|
||||||
|
"permissions": [
|
||||||
|
"users",
|
||||||
|
"admins"
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
"general"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"admins",
|
"admins",
|
||||||
"group_admins"
|
"group_admins"
|
||||||
],
|
],
|
||||||
"modules": [
|
"modules": [
|
||||||
"applications"
|
"general"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"applications": {
|
"application": {
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"admins",
|
"admins",
|
||||||
"group_admins"
|
"group_admins"
|
||||||
|
@ -12,9 +12,11 @@ makedirs(f'{configGet("cache", "locations")}{sep}avatars', exist_ok=True)
|
|||||||
|
|
||||||
# Importing
|
# Importing
|
||||||
from modules.commands.application import *
|
from modules.commands.application import *
|
||||||
from modules.commands.applications import *
|
from modules.commands.bye import *
|
||||||
from modules.commands.cancel import *
|
from modules.commands.cancel import *
|
||||||
|
from modules.commands.export import *
|
||||||
from modules.commands.identify import *
|
from modules.commands.identify import *
|
||||||
|
from modules.commands.issue 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.nearby import *
|
||||||
@ -28,17 +30,24 @@ from modules.commands.start import *
|
|||||||
from modules.commands.warn import *
|
from modules.commands.warn import *
|
||||||
from modules.commands.warnings import *
|
from modules.commands.warnings import *
|
||||||
|
|
||||||
|
# This one is only imported during events
|
||||||
|
# and should be completely rewritten for each one.
|
||||||
|
# from modules.event import *
|
||||||
|
|
||||||
|
from modules.callbacks.ban import *
|
||||||
from modules.callbacks.nothing import *
|
from modules.callbacks.nothing import *
|
||||||
from modules.callbacks.reapply import *
|
from modules.callbacks.reapply import *
|
||||||
from modules.callbacks.rules import *
|
from modules.callbacks.rules import *
|
||||||
from modules.callbacks.sid import *
|
from modules.callbacks.spoiler import *
|
||||||
from modules.callbacks.sponsorship import *
|
from modules.callbacks.sponsorship import *
|
||||||
from modules.callbacks.sub import *
|
from modules.callbacks.sub import *
|
||||||
from modules.callbacks.sus import *
|
from modules.callbacks.sus import *
|
||||||
|
from modules.callbacks.warnings import *
|
||||||
|
|
||||||
|
from modules.handlers.analytics_group import *
|
||||||
from modules.handlers.confirmation import *
|
from modules.handlers.confirmation import *
|
||||||
from modules.handlers.contact import *
|
from modules.handlers.contact import *
|
||||||
from modules.handlers.group_join import *
|
from modules.handlers.group_member_update import *
|
||||||
from modules.handlers.voice import *
|
from modules.handlers.voice import *
|
||||||
from modules.handlers.welcome import *
|
from modules.handlers.welcome import *
|
||||||
from modules.handlers.everything import *
|
from modules.handlers.everything import *
|
||||||
@ -46,7 +55,6 @@ from modules.handlers.everything import *
|
|||||||
from modules.scheduled import *
|
from modules.scheduled import *
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
logWrite(f"Starting up with pid {pid}")
|
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.
|
# Yes, it should be in some kind of async main() function but I don't give a shit.
|
||||||
@ -55,17 +63,43 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if path.exists(path.join(configGet("cache", "locations"), "shutdown_time")):
|
if path.exists(path.join(configGet("cache", "locations"), "shutdown_time")):
|
||||||
downtime = relativedelta(datetime.now(), datetime.fromtimestamp(jsonLoad(path.join(configGet("cache", "locations"), "shutdown_time"))["timestamp"]))
|
downtime = relativedelta(
|
||||||
|
datetime.now(),
|
||||||
|
datetime.fromtimestamp(
|
||||||
|
jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "shutdown_time")
|
||||||
|
)["timestamp"]
|
||||||
|
),
|
||||||
|
)
|
||||||
if downtime.days >= 1:
|
if downtime.days >= 1:
|
||||||
app.send_message(configGet("owner"), locale("startup_downtime_days", "message").format(pid, downtime.days))
|
app.send_message(
|
||||||
|
configGet("owner"),
|
||||||
|
locale("startup_downtime_days", "message").format(
|
||||||
|
pid, downtime.days
|
||||||
|
),
|
||||||
|
)
|
||||||
elif downtime.hours >= 1:
|
elif downtime.hours >= 1:
|
||||||
app.send_message(configGet("owner"), locale("startup_downtime_hours", "message").format(pid, downtime.hours))
|
app.send_message(
|
||||||
|
configGet("owner"),
|
||||||
|
locale("startup_downtime_hours", "message").format(
|
||||||
|
pid, downtime.hours
|
||||||
|
),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
app.send_message(configGet("owner"), locale("startup_downtime_minutes", "message").format(pid, downtime.minutes))
|
app.send_message(
|
||||||
|
configGet("owner"),
|
||||||
|
locale("startup_downtime_minutes", "message").format(
|
||||||
|
pid, downtime.minutes
|
||||||
|
),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
app.send_message(configGet("owner"), locale("startup", "message").format(pid))
|
app.send_message(
|
||||||
|
configGet("owner"), locale("startup", "message").format(pid)
|
||||||
|
)
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
logWrite(f"Could not send startup message to bot owner. Perhaps user has not started the bot yet.")
|
logWrite(
|
||||||
|
f"Could not send startup message to bot owner. Perhaps user has not started the bot yet."
|
||||||
|
)
|
||||||
|
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
|
|
||||||
@ -74,11 +108,16 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
app.send_message(configGet("owner"), locale("shutdown", "message").format(pid))
|
app.send_message(configGet("owner"), locale("shutdown", "message").format(pid))
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
logWrite(f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet.")
|
logWrite(
|
||||||
|
f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet."
|
||||||
|
)
|
||||||
|
|
||||||
app.stop()
|
app.stop()
|
||||||
|
|
||||||
makedirs(configGet("cache", "locations"), exist_ok=True)
|
makedirs(configGet("cache", "locations"), exist_ok=True)
|
||||||
jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time"))
|
jsonSave(
|
||||||
|
{"timestamp": time()},
|
||||||
|
path.join(configGet("cache", "locations"), "shutdown_time"),
|
||||||
|
)
|
||||||
|
|
||||||
killProc(pid)
|
killProc(pid)
|
@ -9,7 +9,7 @@
|
|||||||
"question4": "When did you first learn about Hololive?",
|
"question4": "When did you first learn about Hololive?",
|
||||||
"question5": "What made you interested in Hololive?",
|
"question5": "What made you interested in Hololive?",
|
||||||
"question6": "Which girl's content do you like the most?",
|
"question6": "Which girl's content do you like the most?",
|
||||||
"question7": "Name the content of at least five Japanese girls you like the most.",
|
"question7": "Name the content of at least five **JAPANESE** girls you like the most.",
|
||||||
"question8": "Do you watch streams of Hololive girls?",
|
"question8": "Do you watch streams of Hololive girls?",
|
||||||
"question9": "Whose songs from Hololive do you like the most?",
|
"question9": "Whose songs from Hololive do you like the most?",
|
||||||
"question10": "And finally, tell us a little about yourself. About hobbies, what you like to do. In one message, please.",
|
"question10": "And finally, tell us a little about yourself. About hobbies, what you like to do. In one message, please.",
|
||||||
@ -31,7 +31,6 @@
|
|||||||
"approved_joined": "Congratulations! Your application has been reviewed and confirmed as correct. Thank you for your time and have a nice day!",
|
"approved_joined": "Congratulations! Your application has been reviewed and confirmed as correct. Thank you for your time and have a nice day!",
|
||||||
"read_rules": "Please read these rules before clicking the button and joining the chat.",
|
"read_rules": "Please read these rules before clicking the button and joining the chat.",
|
||||||
"rejected.": "Oh dear! Your application has been reviewed but not confirmed as eligible to join the community. Better luck next time!\n\nYou can try to reapply with the /reapply command.",
|
"rejected.": "Oh dear! Your application has been reviewed but not confirmed as eligible to join the community. Better luck next time!\n\nYou can try to reapply with the /reapply command.",
|
||||||
"rejected_aggressive": "Oh dear! Your application has been reviewed, but not confirmed as eligible to join the community.",
|
|
||||||
"rejected_russian": "Russian warship, go fuck yourself!",
|
"rejected_russian": "Russian warship, go fuck yourself!",
|
||||||
"approved_by": "✅ **Application approved**\nAdmin **{0}** has reviewed and approved application `{1}`.",
|
"approved_by": "✅ **Application approved**\nAdmin **{0}** has reviewed and approved application `{1}`.",
|
||||||
"rejected_by": "❌ **Form rejected**\nAdmin **{0}** has reviewed and rejected form `{1}`.",
|
"rejected_by": "❌ **Form rejected**\nAdmin **{0}** has reviewed and rejected form `{1}`.",
|
||||||
@ -122,7 +121,6 @@
|
|||||||
"button": {
|
"button": {
|
||||||
"sub_yes": "✅ Accept",
|
"sub_yes": "✅ Accept",
|
||||||
"sub_no": "❌ Reject",
|
"sub_no": "❌ Reject",
|
||||||
"sub_aggressive": "🤡 Reject (Toxic)",
|
|
||||||
"sub_russian": "🇷🇺 Reject (Russian)",
|
"sub_russian": "🇷🇺 Reject (Russian)",
|
||||||
"accepted": "✅ Accepted",
|
"accepted": "✅ Accepted",
|
||||||
"declined": "❌ Rejected",
|
"declined": "❌ Rejected",
|
||||||
@ -145,7 +143,6 @@
|
|||||||
"callback": {
|
"callback": {
|
||||||
"sub_accepted": "✅ Application {0} has been approved",
|
"sub_accepted": "✅ Application {0} has been approved",
|
||||||
"sub_rejected": "❌ Application {0} rejected",
|
"sub_rejected": "❌ Application {0} rejected",
|
||||||
"sub_aggressive": "🤡 Application {0} rejected",
|
|
||||||
"sub_russian": "🇷🇺 Application {0} rejected",
|
"sub_russian": "🇷🇺 Application {0} rejected",
|
||||||
"sus_allowed": "✅ Access {0} allowed",
|
"sus_allowed": "✅ Access {0} allowed",
|
||||||
"sus_rejected": "❌ Access {0} denied",
|
"sus_rejected": "❌ Access {0} denied",
|
||||||
|
316
locale/uk.json
316
locale/uk.json
@ -1,119 +1,142 @@
|
|||||||
{
|
{
|
||||||
"message": {
|
"message": {
|
||||||
"start": "Привіт і ласкаво просимо!\n\nЦей бот створено для прийому заявок на вступ до нашої спільноти. Для продовження нас цікавить відповідь на одне питання:\n\nЧи хочеш ти доєднатися до українського ком'юніті фанатів Хололайв?",
|
"already_sent": "Анкету вже надіслано, просто почекай. Тобі одразу повідомлять, яке рішення буде прийнято.",
|
||||||
|
"application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}",
|
||||||
|
"application_invalid_syntax": "Неправильний синтаксис!\nТреба: `/application ID/NAME/USERNAME`",
|
||||||
|
"application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення, як тільки її перевірять та приймуть рішення.. До тих пір від тебе більше нічого не потребується :)",
|
||||||
|
"application_status_accepted": "Прийнята `{0}` від {1}",
|
||||||
|
"application_status_not_send": "Анкета ще не була відправлена",
|
||||||
|
"application_status_on_hold": "Анкета все ще на розгляді",
|
||||||
|
"application_status_rejected": "Відхилена `{0}` від {1}",
|
||||||
|
"approved_by": "✅ **Анкету схвалено**\nАдмін **{0}** переглянув та схвалив анкету `{1}`.",
|
||||||
|
"approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!",
|
||||||
|
"approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ.\n\nПеред тим, як ти натиснеш на кнопочку під повідомленням, щоб вступити до нашої лампової спільноти, дамо тобі трішечки додаткової інформації.\nПам'ятай, що натискаючи її, ти підтверджуєш, що ознайомився із нашими правилами (/rules) та зобов'язуєшся їх дотримуватись.\n\nПісля того, як потрапиш до чату, не закидуй цього бота далеко.\nПрописавши @holoua_bot у боті, ти відкриєш список із усіх наших анкет. Ти можеш натискати на будь-яку із них та дізнаватись про кожного із нас більше інформації.\nЗавдяки команді /nearby, ти зможеш дізнатись, чи є серед нас однодумці із твого міста.\nЯкщо у тебе є спонсорська підписка на будь-кого із учасниць Гололайву, то ти маєш право отримати унікальну роль у нашому чаті (/sponsorship) та виділятись серед інших учасників. (А ще зможеш отримати декілька додаткових функцій. Але нікому про це не кажи!)",
|
||||||
|
"birthday": "У користувача **{0}** (@{1}) сьогодні день народження! Виповнилось {2} років",
|
||||||
|
"cancel_reapply": "Всі поточні операції скасовано.\nЩоб знову заповнити анкету користуйся /reapply",
|
||||||
|
"cancel": "Всі поточні операції скасовано.",
|
||||||
|
"confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?",
|
||||||
|
"contact_invalid": "Надісланий контакт не має завершеної анкети.",
|
||||||
|
"contact_not_member": "Надісланий контакт не є користувачем Telegram.",
|
||||||
|
"contact": "Анкета `{0}`\n\n**Дані анкети:**\n{1}\n\n{2}",
|
||||||
|
"finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.",
|
||||||
|
"finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора або перервати його командою /cancel.",
|
||||||
"goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.",
|
"goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.",
|
||||||
"privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.",
|
"identify_invalid_syntax": "Неправильний синтаксис!\nТреба: `/identify ID/NAME/USERNAME`",
|
||||||
|
"identify_not_found": "Не знайдено користувачів за запитом **{0}**",
|
||||||
|
"identify_success": "Користувач `{0}`\n\nІм'я: {1}\nЮзернейм: {2}\nЄ в чаті: {3}\nЄ адміном: {4}\nРоль: {5}\nНаявна анкета: {6}\nНаявне спонсорство: {7}",
|
||||||
|
"issue": "**Допоможіть боту**\nЗнайшли баг або помилку? Маєте файну ідею для нової функції? Повідомте нас, створивши нову задачу на гіті.\n\nЗа можливості, опишіть свій запит максимально детально. Якщо є змога, також додайте скріншоти або додаткову відому інформацію.",
|
||||||
|
"joined_application": "{0} (@{1})\n\n**Дані анкети:**\n{2}",
|
||||||
|
"joined_false_link": "Користувач **{0}** (`{1}`) приєднався до групи не за своїм посиланням",
|
||||||
|
"label_set_exception": "❌ **Не вдалось встановити роль**\nУ зв'язку з помилкою `{0}` не вдалось встановити роль. Власника бота повідомлено.",
|
||||||
|
"label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів",
|
||||||
|
"message_enter": "Надішліть повідомлення, яке треба переслати адмінам.\n\nЗверніть увагу, що повідомлення може містити лише одне медіа або файл.",
|
||||||
|
"message_error": "⚠️ **Сталась помилка**\nНе вдалось надіслати ваше повідомлення. Розробника повідомлено про цю помилку.",
|
||||||
|
"message_from": "Повідомлення від **{0}** (`{1}`):\n\n",
|
||||||
|
"message_invalid_syntax": "Неправильний синтаксис!\nТреба: `/message ID ПОВІДОМЛЕННЯ`",
|
||||||
|
"message_no_user": "⚠️ **Помилка надсилання**\nВказано невірний ID користувача, тому не вдалось надіслати йому повідомлення. Перевірте чи в якості ID надано те число, яке було показане в анкеті.",
|
||||||
|
"message_reply_notice": "\n\n__Для того, щоб адміністрація побачила вашу відповідь, відправте її **реплаєм на це повідомлення**__",
|
||||||
|
"message_sent": "Повідомлення надіслано",
|
||||||
|
"message_traceback": "⚠️ **Сталась помилка**\nПомилка повідомлень: `{0}` -> `{1}`\nПомилка: `{2}`\n\nTraceback:\n```\n{3}\n```",
|
||||||
|
"nearby_empty": "Здається, нікого поблизу немає.",
|
||||||
|
"nearby_error": "⚠️ **Сталась помилка**\n\nПомилка: `{0}`\n\nTraceback:\n```\n{1}\n```",
|
||||||
|
"nearby_invalid": "ℹ️ **Місце не знайдено**\nЗа наданим запитом не знайдено місце з координатами. Спробуйте ще раз формулючи запит в стилі \"Чернівці\" або \"Київська область\".",
|
||||||
|
"nearby_result": "Результати пошуку:\n\n{0}",
|
||||||
|
"no_user_application": "Не знайдено користувачів за запитом **{0}**",
|
||||||
|
"no_user_warnings": "Не знайдено користувачів за запитом **{0}**",
|
||||||
|
"no_warnings": "Користувач **{0}** (`{1}`) не має попереджень",
|
||||||
|
"not_member": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.",
|
||||||
|
"privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти та подальшої взаємодії в ній.",
|
||||||
|
"question_too_long": "Текст занадто довгий. Будь ласка, умісти відповідь у 256 символів.",
|
||||||
"question1": "Як до тебе можна звертатись?",
|
"question1": "Як до тебе можна звертатись?",
|
||||||
"question2": "Коли в тебе день народження?",
|
"question10_too_long": "Текст занадто довгий. Будь ласка, умісти відповідь у 1024 символи.",
|
||||||
|
"question10": "Ну і нарешті, розкажи трохи про себе. Про хобі, чим тобі подобається займатись. Одним повідомленням, будь ласка.",
|
||||||
|
"question2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
|
||||||
|
"question2_joke": "Шутнік, ми так і поняли. Але будь ласка, введи реальне значення.",
|
||||||
|
"question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.",
|
||||||
|
"question2": "Коли в тебе день народження?\n\nБудь ласка, у форматі ДД.ММ.РРРР",
|
||||||
|
"question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.",
|
||||||
|
"question3_found": "Використовую наступний результат:\n• {0} ({1})",
|
||||||
|
"question3_invalid": "Місто/населений пункт не знайдено. Користуйтесь прикладами нижче щоб вказати де ви проживаєте та спробуйте ще раз:\n\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
|
||||||
|
"question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```",
|
||||||
"question3": "З якого ти міста або де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київ\" або \"Київська Область\" є достатньою конкретизацією.\n\nПриклади:\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
|
"question3": "З якого ти міста або де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київ\" або \"Київська Область\" є достатньою конкретизацією.\n\nПриклади:\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
|
||||||
"question4": "Коли вперше довелось дізнатись про Хололайв?",
|
"question4": "Коли вперше довелось дізнатись про Хололайв?",
|
||||||
"question5": "Чим тебе зацікавив Хололайв?",
|
"question5": "Чим тебе зацікавив Хололайв?",
|
||||||
"question6": "Контент якої дівчини тобі подобається найбільше?",
|
"question6": "Контент якої дівчини тобі подобається найбільше?",
|
||||||
"question7": "Назви контент хоча б п'яти японських холодівчат, які тобі подобаються найбільше.",
|
"question7": "Назви контент хоча б п'яти **__--ЯПОНСЬКИХ--__** холодівчат, які тобі подобаються найбільше.",
|
||||||
"question8": "Чи дивишся ти стріми дівчат Хололайву?",
|
"question8": "Чи дивишся ти стріми дівчат Хололайву?",
|
||||||
"question9": "Чиї пісні з Хололайву тобі подобаються найбільше?",
|
"question9": "Чиї пісні з Хололайву тобі подобаються найбільше?",
|
||||||
"question10": "Ну і нарешті, розкажи трохи про себе. Про хобі, чим тобі подобається займатись. Одним повідомленням, будь ласка.",
|
|
||||||
"question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.",
|
|
||||||
"question2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
|
|
||||||
"question2_joke": "Шутнік, ми так і поняли. Але будь ласка, введи реальне значення.",
|
|
||||||
"question3_invalid": "Місто/населений пункт не знайдено. Користуйтесь прикладами нижче щоб вказати де ви проживаєте та спробуйте ще раз:\n\n• Київ\n• Одеська область\n• Макіївка (Луганська область)",
|
|
||||||
"question3_found": "Використовую наступний результат:\n• {0} ({1})",
|
|
||||||
"question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.",
|
|
||||||
"question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```",
|
|
||||||
"sponsorship_apply": "ℹ️ Оформіть платну підписку на когось з Холо, заповніть форму та отримайте особливу роль в якості винагороди!",
|
|
||||||
"sponsorship_applying": "ℹ️ Розпочато заповнення форми на отримання бонусів за платну підписку на холодівчат.",
|
|
||||||
"sponsor1": "На яку саме дівчину платна підписка?",
|
|
||||||
"sponsor2": "До якої дати (`ДД.ММ.РРРР`) підписка?",
|
|
||||||
"sponsor2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
|
|
||||||
"sponsor2_past": "Вказана дата знаходиться в минулому. Будь ласка, вкажіть правильний термін дії підписки",
|
|
||||||
"sponsor3": "Будь ласка, надішли одне фото для підтвердження дійсності підписки\n\nℹ️ **Підказка**\nПрочитай як правильно скрінити легітимне підтвердження підписки: https://telegra.ph/Pіdpiska-na-holo-dіvchinu-01-02",
|
|
||||||
"sponsor4": "Яку роль ти бажаєш отримати?\n\nℹ️ **Підказка**\nНазва ролі повинна бути якось пов'язана зі вказаною дівчиною, не повинна порушувати правила спільноти а також має бути не довше за 16 символів (обмеження Telegram).",
|
|
||||||
"sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.",
|
|
||||||
"confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?",
|
|
||||||
"sponsor_confirm": "**Дані форми:**\nСтрімер: {0}\nПідписка до: {1}\nХочу роль: {2}\n\nПеревір чи все правильно та жмакни кнопку на клавіатурі щоб продовжити.",
|
|
||||||
"application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується :)",
|
|
||||||
"sponsorship_sent": "Дякуємо! Ми надіслали форму на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення :)",
|
|
||||||
"application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}",
|
|
||||||
"reapply_got": "Отримано оновлення анкети від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}",
|
|
||||||
"sponsor_got": "Отримано форму на спонсорство від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані форми:**\n{3}",
|
|
||||||
"shutdown": "Вимкнення бота з підом `{0}`",
|
|
||||||
"startup": "Запуск бота з підом `{0}`",
|
|
||||||
"startup_downtime_minutes": "Запуск бота з підом `{0}` (лежав {1} хв.)",
|
|
||||||
"startup_downtime_hours": "Запуск бота з підом `{0}` (лежав {1} год.)",
|
|
||||||
"startup_downtime_days": "Запуск бота з підом `{0}` (лежав {1} дн.)",
|
|
||||||
"approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ. Скористайся кнопкою під повідомленням щоб вступити до нашої лампової спільноти!",
|
|
||||||
"approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!",
|
|
||||||
"read_rules": "Будь ласка, прочитай ці правила перш ніж натискати на кнопку та приєднуватись до чату.",
|
"read_rules": "Будь ласка, прочитай ці правила перш ніж натискати на кнопку та приєднуватись до чату.",
|
||||||
"rejected": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!\n\nТи можеш спробувати повторно заповнити анкету командою /reapply",
|
"reapply_forbidden": "❌ **Дія неможлива**\nТвоя минула анкета ще не була схвалена або відхилена.",
|
||||||
"rejected_aggressive": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти.",
|
"reapply_got": "Отримано оновлення анкети від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}",
|
||||||
"rejected_russian": "русский военньій корабль, иди нахуй!",
|
"reapply_in_progress": "❌ **Дія неможлива**\nТи прямо зараз вже заповнюєш анкету. Якщо в ній є помилка - просто натисни кнопку нижче щоб почати заповнювати спочатку.",
|
||||||
"approved_by": "✅ **Анкету схвалено**\nАдмін **{0}** переглянув та схвалив анкету `{1}`.",
|
"reapply_left_chat": "⚠️ **Нагадування**\nЗдається, ти залишив чат у минулому, проте твоя анкета все ще доступна до використання. Подати запит на вступ користуючись старою анкетою?",
|
||||||
"rejected_by": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`.",
|
"reapply_restarted": "🔁 **Перезапущено**\nРозпочате заповнення анкети спочатку.",
|
||||||
"rejected_by_agr": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: агресивна/токсична анкета.",
|
"rejected_by_agr": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: агресивна/токсична анкета.",
|
||||||
"rejected_by_rus": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: русня.",
|
"rejected_by_rus": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: русня.",
|
||||||
"sponsor_approved": "Вітаємо! Твою форму переглянули та підтвердили її правильність. Коли термін дії наданої підписки буде добігати кінця - ми нагадаємо, що треба оновити дані аби й надалі отримувати плюшки в чаті. Також можна повторно заповнити форму, якщо хочеться змінити бажане ім'я ролі або подовжити термін дії підписки завчасно, за допомогою команди /sponsorship. Гарного дня!",
|
"rejected_by": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`.",
|
||||||
"sponsor_rejected": "Ой лишенько! Твою форму переглянули, однак не підтвердили її. Можливо, щось не так з датами, або ж бажана роль не може бути надана.\n\nТи можеш спробувати повторно заповнити форму командою /sponsorship",
|
"rejected_russian": "русский военньій корабль, иди нахуй!",
|
||||||
"sponsor_approved_by": "✅ **Підписку схвалено**\nАдмін **{0}** переглянув та схвалив форму `{1}`.",
|
"rejected": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!\n\nТи можеш спробувати повторно заповнити анкету командою /reapply",
|
||||||
"sponsor_rejected_by": "❌ **Підписку відхилено**\nАдмін **{0}** переглянув та відхилив форму `{1}`.",
|
"shutdown": "Вимкнення бота з підом `{0}`",
|
||||||
"contact": "Анкета `{0}`\n\n**Дані анкети:**\n{1}\n\n{2}",
|
|
||||||
"application_status_accepted": "Прийнята `{0}` від {1}",
|
|
||||||
"application_status_rejected": "Відхилена `{0}` від {1}",
|
|
||||||
"application_status_on_hold": "Анкета все ще на розгляді",
|
|
||||||
"application_status_not_send": "Анкета ще не була відправлена",
|
|
||||||
"contact_invalid": "Надісланий контакт не має завершеної анкети.",
|
|
||||||
"contact_not_member": "Надісланий контакт не є користувачем Telegram.",
|
|
||||||
"already_sent": "Анкету вже надіслано, просто почекай. Тобі одразу повідомлять, яке рішення буде прийнято.",
|
|
||||||
"sus_joined": "Користувач **{0}** (`{1}`) зайшов до групи не за своїм персональним запрошенням.",
|
|
||||||
"sus_allowed_by": "✅ **Доступ дозволено**\nАдмін **{0}** дозволив `{1}` вступити до спільноти не за персональним посиланням.",
|
|
||||||
"sus_rejected_by": "❌ **Доступ заборонено**\nАдмін **{0}** заборонив `{1}` доступ до спільноти не за персональним посиланням.",
|
|
||||||
"reapply_forbidden": "❌ **Дія неможлива**\nТвоя минула анкета ще не була схвалена або відхилена.",
|
|
||||||
"reapply_in_progress": "❌ **Дія неможлива**\nТи прямо зараз вже заповнюєш анкету. Якщо в ній є помилка - просто натисни кнопку нижче щоб почати заповнювати спочатку.",
|
|
||||||
"reapply_restarted": "🔁 **Перезапущено**\nРозпочате заповнення анкети спочатку.",
|
|
||||||
"reapply_left_chat": "⚠️ **Нагадування**\nЗдається, ти залишив чат у минулому, проте твоя анкета все ще доступна до використання. Подати запит на вступ користуючись старою анкетою?",
|
|
||||||
"birthday": "У користувача **{0}** (@{1}) сьогодні день народження! Виповнилось {2} років",
|
|
||||||
"application_invalid_syntax": "Неправильний синтаксис!\nТреба: `/application ID/NAME/USERNAME`",
|
|
||||||
"warned": "Попереджено **{0}** (`{1}`) про порушення правил",
|
|
||||||
"warned_reason": "Попереджено **{0}** (`{1}`)\n\n**Причина:**\n{2}",
|
|
||||||
"warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження",
|
|
||||||
"warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень",
|
|
||||||
"no_warnings": "Користувач **{0}** (`{1}`) не має попереджень",
|
|
||||||
"no_user_warnings": "Не знайдено користувачів за запитом **{0}**",
|
|
||||||
"syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`",
|
|
||||||
"message_sent": "Повідомлення надіслано",
|
|
||||||
"message_no_user": "⚠️ **Помилка надсилання**\nВказано невірний ID користувача, тому не вдалось надіслати йому повідомлення. Перевірте чи в якості ID надано те число, яке було показане в анкеті.",
|
|
||||||
"message_invalid_syntax": "Неправильний синтаксис!\nТреба: `/message ID ПОВІДОМЛЕННЯ`",
|
|
||||||
"message_from": "Повідомлення від **{0}** (`{1}`):\n\n",
|
|
||||||
"message_reply_notice": "\n\n**Щоб надіслати відповідь на це повідомлення, тегніть його.**",
|
|
||||||
"message_error": "⚠️ **Сталась помилка**\nНе вдалось надіслати ваше повідомлення. Розробника повідомлено про цю помилку.",
|
|
||||||
"message_traceback": "⚠️ **Сталась помилка**\nПомилка повідомлень: `{0}` -> `{1}`\nПомилка: `{2}`\n\nTraceback:\n```\n{3}\n```",
|
|
||||||
"no_user_application": "Не знайдено користувачів за запитом **{0}**",
|
|
||||||
"user_invalid": "Надісланий користувач не має завершеної анкети.",
|
|
||||||
"joined_false_link": "Користувач **{0}** (`{1}`) приєднався до групи не за своїм посиланням",
|
|
||||||
"sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!",
|
|
||||||
"sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.",
|
|
||||||
"label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів",
|
|
||||||
"finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора або перервати його командою /cancel.",
|
|
||||||
"finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.",
|
|
||||||
"nearby_invalid": "ℹ️ **Місце не знайдено**\nЗа наданим запитом не знайдено місце з координатами. Спробуйте ще раз формулючи запит в стилі \"Чернівці\" або \"Київська область\".",
|
|
||||||
"nearby_error": "⚠️ **Сталась помилка**\n\nПомилка: `{0}`\n\nTraceback:\n```\n{1}\n```",
|
|
||||||
"nearby_result": "Результати пошуку:\n\n{0}",
|
|
||||||
"nearby_empty": "Здається, нікого поблизу немає.",
|
|
||||||
"cancel": "Всі поточні операції скасовано.",
|
|
||||||
"identify_invalid_syntax": "Неправильний синтаксис!\nТреба: `/identify ID/NAME/USERNAME`",
|
|
||||||
"identify_not_found": "Не знайдено користувачів за запитом **{0}**",
|
|
||||||
"identify_success": "Користувач `{0}`\n\nІм'я: {1}\nЮзернейм: {2}\nЄ в чаті: {3}\nЄ адміном: {4}\nРоль: {5}\nНаявна анкета: {6}\nНаявне спонсорство: {7}",
|
|
||||||
"spoiler_started": "Розпочато створення спойлера. Будь ласка, оберіть категорію спойлера за допомогою клавіатури бота.",
|
|
||||||
"spoiler_unfinished": "У вас ще є незавершений спойлер. Надішліть /cancel щоб зупинити його створення",
|
|
||||||
"spoiler_cancel": "Створення спойлера було припинено",
|
"spoiler_cancel": "Створення спойлера було припинено",
|
||||||
"spoiler_empty": "Спойлер категорії \"{0}\" без опису",
|
"spoiler_described_named": "Спойлер категорії \"{0}\" від **{1}**: {2}",
|
||||||
"spoiler_described": "Спойлер категорії \"{0}\": {1}",
|
"spoiler_described": "Спойлер категорії \"{0}\": {1}",
|
||||||
"spoiler_description_enter": "Добре, введіть бажаний опис спойлера",
|
"spoiler_description_enter": "Добре, введіть бажаний опис спойлера",
|
||||||
"spoiler_using_description": "Встановлено опис спойлера: {0}\n\nЗалишилось додати вміст самого спойлера. Бот приймає текстове повідомлення, фото, відео, файл а також гіф зображення (1 шт.)",
|
"spoiler_description_too_long": "Текст занадто довгий. Будь ласка, умісти опис у 1024 символи.",
|
||||||
"spoiler_send_description": "Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати. Надішли мінус (-) щоб пропустити цей крок.",
|
|
||||||
"spoiler_ready": "Успіх! Спойлер створено. Користуйтесь кнопкою нижче щоб надіслати його.",
|
|
||||||
"spoiler_incorrect_content": "Бот не підтримує такий контент. Будь ласка, надішли текст, фото, відео, файл або анімацію (гіф).",
|
|
||||||
"spoiler_incorrect_category": "Вказана категорія не є дійсною. Будь ласка, користуйся клавіатурою бота (кнопка біля 📎) для вибору категорії.",
|
|
||||||
"spoiler_in_progress": "❌ **Дія неможлива**\nПерш ніж починати нову дію, треба завершити створення спойлера або перервати його командою /cancel.",
|
"spoiler_in_progress": "❌ **Дія неможлива**\nПерш ніж починати нову дію, треба завершити створення спойлера або перервати його командою /cancel.",
|
||||||
|
"spoiler_incorrect_category": "Вказана категорія не є дійсною. Будь ласка, користуйся клавіатурою бота (кнопка біля 📎) для вибору категорії.",
|
||||||
|
"spoiler_incorrect_content": "Бот не підтримує такий контент. Будь ласка, надішли текст, фото, відео, файл або анімацію (гіф).",
|
||||||
|
"spoiler_ready": "Успіх! Спойлер створено",
|
||||||
|
"spoiler_send_description": "Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати.",
|
||||||
|
"spoiler_send": "Користуйтесь кнопкою нижче щоб надіслати його.",
|
||||||
|
"spoiler_started": "Розпочато створення спойлера. Будь ласка, оберіть категорію спойлера за допомогою клавіатури бота.",
|
||||||
|
"spoiler_unfinished": "У вас ще є незавершений спойлер. Надішліть /cancel щоб зупинити його створення",
|
||||||
|
"spoiler_using_description": "Встановлено опис спойлера: {0}\n\nЗалишилось додати вміст самого спойлера. Бот приймає текстове повідомлення, фото, відео, файл а також гіф зображення (1 шт.)",
|
||||||
|
"sponsor_approved_by": "✅ **Підписку схвалено**\nАдмін **{0}** переглянув та схвалив форму `{1}`.",
|
||||||
|
"sponsor_approved": "Вітаємо! Твою форму переглянули та підтвердили її правильність. Коли термін дії наданої підписки буде добігати кінця - ми нагадаємо, що треба оновити дані аби й надалі отримувати плюшки в чаті. Також можна повторно заповнити форму, якщо хочеться змінити бажане ім'я ролі або подовжити термін дії підписки завчасно, за допомогою команди /sponsorship. Гарного дня!",
|
||||||
|
"sponsor_confirm": "**Дані форми:**\nСтрімер: {0}\nПідписка до: {1}\nХочу роль: {2}\n\nПеревір чи все правильно та жмакни кнопку на клавіатурі щоб продовжити.",
|
||||||
|
"sponsor_got": "Отримано форму на спонсорство від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані форми:**\n{3}",
|
||||||
|
"sponsor_rejected_by": "❌ **Підписку відхилено**\nАдмін **{0}** переглянув та відхилив форму `{1}`.",
|
||||||
|
"sponsor_rejected": "Ой лишенько! Твою форму переглянули, однак не підтвердили її. Можливо, щось не так з датами, або ж бажана роль не може бути надана.\n\nТи можеш спробувати повторно заповнити форму командою /sponsorship",
|
||||||
|
"sponsor_resubmit_invalid_option": "Правильна опція! Спробуй /sponsorship ще раз, але користуйся клавіатурою щоб обрати з можливих варіантів.",
|
||||||
|
"sponsor_resubmit": "Здається, ти маєш активну підписку на **{0}**. Хочеш подовжити її чи заповнити нову?",
|
||||||
|
"sponsor1_invalid": "Будь ласка, введіть ім'я не довше за 240 символів",
|
||||||
|
"sponsor1": "На яку саме дівчину платна підписка?",
|
||||||
|
"sponsor2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`",
|
||||||
|
"sponsor2_past": "Вказана дата знаходиться в минулому. Будь ласка, вкажіть правильний термін дії підписки",
|
||||||
|
"sponsor2": "До якої дати (`ДД.ММ.РРРР`) підписка?",
|
||||||
|
"sponsor3": "Будь ласка, надішли одне фото для підтвердження дійсності підписки\n\nℹ️ **Підказка**\nПрочитай як правильно скрінити легітимне підтвердження підписки: https://telegra.ph/Pіdpiska-na-holo-dіvchinu-01-02",
|
||||||
|
"sponsor4_resubmit": "Майже закінчили. Стара роль **{0}** може бути використана і цього разу, а може бути змінена. Будь ласка, обери те, що тобі підходить.\n\n⚠️ **Увага!**\nПісля обирання варіанту або введення нової назви ролі, заявку буде надіслано автоматично. Для відміни дії зараз ще можна використовувати /cancel",
|
||||||
|
"sponsor4": "Яку роль ти бажаєш отримати?\n\nℹ️ **Підказка**\nНазва ролі повинна бути якось пов'язана зі вказаною дівчиною, не повинна порушувати правила спільноти а також має бути не довше за 16 символів (обмеження Telegram).",
|
||||||
|
"sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.",
|
||||||
|
"sponsorship_apply": "ℹ️ Оформіть платну підписку на когось з Холо, заповніть форму та отримайте особливу роль в якості винагороди!",
|
||||||
|
"sponsorship_applying": "ℹ️ Розпочато заповнення форми на отримання бонусів за платну підписку на холодівчат.",
|
||||||
|
"sponsorship_sent": "Дякуємо! Ми надіслали форму на перевірку. Ти отримаєш повідомлення, як тільки її перевірять та приймуть рішення. :)",
|
||||||
|
"sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.",
|
||||||
|
"sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!",
|
||||||
|
"start": "Привіт і ласкаво просимо!\n\nМи будуємо українське ком'юніті фанатів Гололайву і раді кожному, хто поділяє наші інтереси або тільки зацікавився цією тематикою та хоче дізнатись більше. Чим ми відрізняеємось від звичайного тематичного чату? Ми намагаємось створювати усі можливі умови, щоб люди знаходили однодумців у своїх містах та збирались разом. Інколи проводимо великі зустрічі на честь Голо-івентів у Києві. Збираємось у Дискорді для сумісних переглядів концертів, музичних топів, ігор тощо. Проводимо різні івенти у чаті. Об'єднуємось, щоб замовляти офіційний мерч із Японії. Підтримуємо україномовних кліперів та будуємо плани по поширенню нашого ком'юніті на майбутнє.\n\nЦей бот створений для прийому заявок на вступ до нашої чат-спільноти. Усі анкети, після підтвердження адміністрацією, можуть дивитися й інші учасники чату у будь-який момент. Тому, будь ласка, віднесіться до її заповнення відповідально.\n\nЯкщо вашу анкету відхилили, то, скоріше за все:\n1) Вона порушує перше правило чату (/rules - ознайомитись перед вступом до чату).\n2) Ви намагаєтесь додати до чату \"додатковий/запасний\" акаунт.\n3) Ви не дуже відповідально віднеслись до її заповнення.\n\nЯкщо із вашою анкетою щось не так, то вам через бота прийде повідомлення від адміністраторів для вирішення питання. Якщо ви зіштовхнулись із якоюсь проблемою або бот не надсилає вам необхідні повідомлення - напишіть мені у приватні повідомлення @Chirkopol.\n\nПісля прийому вашої анкети бот згенерує вам одноразове посилання. Не забудьте перейти по ньому, щоб потрапити до чату.\n\nДля продовження, нас цікавить відповідь на питання:\nЧи хочеш ти доєднатись до українського ком'юніті фанатів Гололайв та чи зобов'язуєшся ти дотримуватися усіх правил?",
|
||||||
|
"startup_downtime_days": "Запуск бота з підом `{0}` (лежав {1} дн.)",
|
||||||
|
"startup_downtime_hours": "Запуск бота з підом `{0}` (лежав {1} год.)",
|
||||||
|
"startup_downtime_minutes": "Запуск бота з підом `{0}` (лежав {1} хв.)",
|
||||||
|
"startup": "Запуск бота з підом `{0}`",
|
||||||
|
"sus_allowed_by": "✅ **Доступ дозволено**\nАдмін **{0}** дозволив `{1}` вступити до спільноти не за персональним посиланням.",
|
||||||
|
"sus_joined": "Користувач **{0}** (`{1}`) зайшов до групи не за своїм персональним запрошенням.",
|
||||||
|
"sus_rejected_by": "❌ **Доступ заборонено**\nАдмін **{0}** заборонив `{1}` доступ до спільноти не за персональним посиланням.",
|
||||||
|
"syntax_export": "Неправильний синтаксис!\nТреба: `/export applications/warnings/sponsorships/bans/event`",
|
||||||
|
"syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`",
|
||||||
|
"user_invalid": "Надісланий користувач не має завершеної анкети.",
|
||||||
|
"user_left": "Користувач **{0}** залишив чат",
|
||||||
|
"warned_reason": "Попереджено **{0}** (`{1}`)\n\n**Причина:**\n{2}",
|
||||||
|
"warned": "Попереджено **{0}** (`{1}`) про порушення правил",
|
||||||
|
"warning_revoked_auto": "Попередження від {0} користувачеві `{1}` було автоматично скасовано.",
|
||||||
|
"warning_revoked": "Попередження від {0} користувачеві `{1}` було скасовано адміном `{2}`",
|
||||||
|
"warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження\n\n{3}\n\nОбрати та зняти попередження:\n`/warnings {4} revoke`",
|
||||||
|
"warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень\n\n{3}\n\nОбрати та зняти попередження:\n`/warnings {4} revoke`",
|
||||||
|
"warnings_all": "**Список попереджень**\n\n{0}\n\nДля перегляду попереджень окремо взятого користувача слід використовувати `/warnings ID/NAME/USERNAME`",
|
||||||
|
"warnings_empty": "Щось тут порожньо...\nЗ іншого боку, це добре!",
|
||||||
|
"warnings_entry": "• {0} (`{1}`)\n Попереджень: {2}",
|
||||||
|
"warnings_revoke": "**Попередження {0}:**\n\n{1}\n\nБудь ласка, користуйтесь клавіатурою щоб зняти попередження з відповідним номером.",
|
||||||
|
"you_are_banned": "⚠️ **Вас було заблоковано**\nТепер не можна відправити анкету або користуватись командами бота.",
|
||||||
|
"youtube_video": "На каналі [{0}]({1}) нове відео!\n\n**[{2}]({3})**",
|
||||||
"yes": "Так",
|
"yes": "Так",
|
||||||
"no": "Ні",
|
"no": "Ні",
|
||||||
"voice_message": [
|
"voice_message": [
|
||||||
@ -176,6 +199,22 @@
|
|||||||
[
|
[
|
||||||
"Інше"
|
"Інше"
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
"sponsorship_restore": [
|
||||||
|
[
|
||||||
|
"Подовжити стару"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Заповнити нову підписку"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"sponsorship_restore_label": [
|
||||||
|
[
|
||||||
|
"Залишити стару"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Ввести замість неї нову"
|
||||||
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"force_reply": {
|
"force_reply": {
|
||||||
@ -197,49 +236,57 @@
|
|||||||
"spoiler_description": "Опис спойлера"
|
"spoiler_description": "Опис спойлера"
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
"sub_yes": "✅ Прийняти",
|
|
||||||
"sub_no": "❌ Відхилити",
|
|
||||||
"sub_aggressive": "🤡 Відхилити (Токс)",
|
|
||||||
"sub_russian": "🇷🇺 Відхилити (Русак)",
|
|
||||||
"sponsor_yes": "✅ Прийняти",
|
|
||||||
"sponsor_no": "❌ Відхилити",
|
|
||||||
"accepted": "✅ Прийнято",
|
"accepted": "✅ Прийнято",
|
||||||
|
"applying_stop": "🛑 Перервати заповнення",
|
||||||
|
"ban": "💀 Заблокувати",
|
||||||
|
"banned": "☠️ Заблоковано",
|
||||||
"declined": "❌ Відхилено",
|
"declined": "❌ Відхилено",
|
||||||
|
"done": "✅ Готово",
|
||||||
|
"issue": "🪄 Створити задачу",
|
||||||
"join": "Приєднатись",
|
"join": "Приєднатись",
|
||||||
"sus_allow": "✅ Підтвердити дозвіл",
|
"reapply_new_one": "🔁 Заповнити знову",
|
||||||
"sus_reject": "❌ Перманентно заблокувати",
|
|
||||||
"sus_allowed": "✅ Дозвіл надано",
|
|
||||||
"sus_rejected": "❌ Користувача заблоковано",
|
|
||||||
"reapply_yes": "✅ Прийняти",
|
|
||||||
"reapply_no": "❌ Відхилити",
|
"reapply_no": "❌ Відхилити",
|
||||||
"reapply_old_one": "✅ Надіслати стару",
|
"reapply_old_one": "✅ Надіслати стару",
|
||||||
"reapply_new_one": "🔁 Заповнити знову",
|
"reapply_yes": "✅ Прийняти",
|
||||||
"rules_home": "🏠 Головна",
|
|
||||||
"rules_additional": "➕ Додаткові",
|
"rules_additional": "➕ Додаткові",
|
||||||
|
"rules_home": "🏠 Головна",
|
||||||
"rules_next": "Далі ➡️",
|
"rules_next": "Далі ➡️",
|
||||||
"rules_prev": "⬅️ Назад",
|
"rules_prev": "⬅️ Назад",
|
||||||
"applying_stop": "🛑 Перервати заповнення",
|
"spoiler_preview": "Попередній перегляд",
|
||||||
"done": "✅ Готово",
|
"spoiler_send_chat": "Надіслати в холо-чат",
|
||||||
|
"spoiler_send_other": "Надіслати в інший чат",
|
||||||
|
"spoiler_view": "Переглянути",
|
||||||
"sponsor_apply": "Заповнити форму",
|
"sponsor_apply": "Заповнити форму",
|
||||||
|
"sponsor_no": "❌ Відхилити",
|
||||||
"sponsor_started": "Форму розпочато",
|
"sponsor_started": "Форму розпочато",
|
||||||
"spoiler_send": "Надіслати",
|
"sponsor_yes": "✅ Прийняти",
|
||||||
"spoiler_view": "Переглянути"
|
"sub_no": "❌ Відхилити",
|
||||||
|
"sub_russian": "🇷🇺 Відхилити (Русак)",
|
||||||
|
"sub_yes": "✅ Прийняти",
|
||||||
|
"sus_allow": "✅ Підтвердити дозвіл",
|
||||||
|
"sus_allowed": "✅ Дозвіл надано",
|
||||||
|
"sus_reject": "❌ Перманентно заблокувати",
|
||||||
|
"sus_rejected": "❌ Користувача заблоковано"
|
||||||
},
|
},
|
||||||
"callback": {
|
"callback": {
|
||||||
|
"nothing": "🔔 Дія вже виконана",
|
||||||
|
"reapply_stopped": "ℹ️ Перервано заповнення анкети",
|
||||||
|
"rules_additional": "ℹ️ Показано додаткові правила",
|
||||||
|
"rules_home": "ℹ️ Показано головну правил",
|
||||||
|
"rules_page": "ℹ️ Показано правило {0}",
|
||||||
|
"spoiler_forbidden": "❌ Треба бути учасником чату",
|
||||||
|
"spoiler_sent": "✅ Повідомлення надіслано в холо-чат",
|
||||||
|
"sponsor_accepted": "✅ Форму {0} схвалено",
|
||||||
|
"sponsor_rejected": "❌ Форму {0} відхилено",
|
||||||
|
"sponsor_started": "ℹ️ Заповнення форми розпочато",
|
||||||
"sub_accepted": "✅ Анкету {0} схвалено",
|
"sub_accepted": "✅ Анкету {0} схвалено",
|
||||||
|
"sub_banned": "☠️ Користувача заблоковано",
|
||||||
"sub_rejected": "❌ Анкету {0} відхилено",
|
"sub_rejected": "❌ Анкету {0} відхилено",
|
||||||
"sub_aggressive": "🤡 Анкету {0} відхилено",
|
|
||||||
"sub_russian": "🇷🇺 Анкету {0} відхилено",
|
"sub_russian": "🇷🇺 Анкету {0} відхилено",
|
||||||
"sus_allowed": "✅ Доступ {0} дозволено",
|
"sus_allowed": "✅ Доступ {0} дозволено",
|
||||||
"sus_rejected": "❌ Доступ {0} заборонено",
|
"sus_rejected": "❌ Доступ {0} заборонено",
|
||||||
"nothing": "🔔 Дія вже виконана",
|
"warning_not_found": "❌ Попередження вже скасовано або не існує",
|
||||||
"rules_page": "ℹ️ Показано правило {0}",
|
"warning_revoked": "✅ Попередження скасовано"
|
||||||
"rules_home": "ℹ️ Показано головну правил",
|
|
||||||
"rules_additional": "ℹ️ Показано додаткові правила",
|
|
||||||
"reapply_stopped": "ℹ️ Перервано заповнення анкети",
|
|
||||||
"sponsor_started": "ℹ️ Заповнення форми розпочато",
|
|
||||||
"sponsor_accepted": "✅ Форму {0} схвалено",
|
|
||||||
"sponsor_rejected": "❌ Форму {0} відхилено"
|
|
||||||
},
|
},
|
||||||
"inline": {
|
"inline": {
|
||||||
"forbidden": {
|
"forbidden": {
|
||||||
@ -262,27 +309,28 @@
|
|||||||
"description": "Надіслати цей спойлер до чату"
|
"description": "Надіслати цей спойлер до чату"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rules_msg": "📢Правила можуть доповнюватись та змінюватись, залежно від потреби. У такому разі, порушення, які були вчинені до введення (змінення) правила, порушеннями вважатися не будуть. Про всі зміни в правилах, ви будете проінформовані за допомогою закріплених повідомлень. Але вони не будуть закріплені на постійній основі, тому, час від часу, перевіряйте актуальність правил у боті.\n\n🔔Якщо ви бачите, як хтось із учасників порушив правила, тегніть одного із адмінів, у відповідь на повідомлення, яке, на вашу думку, є порушенням. У дописі до тегу, вкажіть, по якому пункту ви побачили порушення. Або перешліть повідомлення до будь кого із адміністраторів у особисті повідомлення, та коротко опишіть ситуацію.\nСписок адміністраторів: @Chirkopol @Za_NerZula @Denialvapr\nЗ питань функціонування бота звертайтесь до @Profitroll2281337\n\n❗️Будь-який заборонений контент, може бути відправлений до чату за допомогою бота - https://t.me/spoilerobot з повним описом контенту, що міститься під спойлером. За неправильний або некоректний опис, може бути видане попередження.\n\n‼️Видалені або змінені повідомлення, все ще є повідомленнями від вашого імені, які могли побачити учасники чату, і які можуть бути відстежені через адмінську панель.\n\n🔨 За порушення - ви отримаєте попередження. За наявності 3-х попереджень - мут на добу. За повторні порушення, ви одразу отримаєте покарання, без додаткових попереджень.",
|
"rules_msg": "📢Правила можуть доповнюватись та змінюватись, залежно від потреби. У такому разі, порушення, які були вчинені до введення (змінення) правила, порушеннями вважатися не будуть. Про всі зміни в правилах, ви будете проінформовані за допомогою закріплених повідомлень. Але вони не будуть закріплені на постійній основі, тому, час від часу, перевіряйте актуальність правил у боті.\n\n🔔Якщо ви бачите, як хтось із учасників порушив правила, тегніть одного із адмінів, у відповідь на повідомлення, яке, на вашу думку, є порушенням. У дописі до тегу, вкажіть, по якому пункту ви побачили порушення. Або перешліть повідомлення до будь кого із адміністраторів у особисті повідомлення, та коротко опишіть ситуацію.\nСписок адміністраторів: @Chirkopol @Za_NerZula @Toxinushka\nЗ питань функціонування бота звертайтесь до @Profitroll2281337\n\n❗️Будь-який заборонений контент, може бути відправлений за допомогою команди /spoiler у бота - з повним описом контенту, що міститься під спойлером. За неправильний або некоректний опис, може бути видане попередження.\n\n‼️Видалені або змінені повідомлення, все ще є повідомленнями від вашого імені, які могли побачити учасники чату, і які можуть бути відстежені через адмінську панель.\n\n🔨 За порушення - ви отримаєте попередження. За наявності 3-х попереджень - мут на добу. За повторні порушення, ви одразу отримаєте покарання, без додаткових попереджень.",
|
||||||
"rules": [
|
"rules": [
|
||||||
"1️⃣) \"HoloKyiv Chat\" та \"HoloUA (Hololive Ukraine) Chat\" створені виключно для українців (13+). В них можуть знаходитись тільки люди які: \n- Народились в Україні, та проживають, на данний момент, у ній.\n- Народились за межами України, але проживають у ній.\n- Народились в Україні але, на даний момент, не проживають у ній.\n\"HoloUA (Hololive Ukraine) Chat\" відкритий для усіх українців. Щоб потрапити до нього, заповніть, будь ласка, анкету, та дочекайтесь, поки її схвалять адміни.\nУ \"HoloKyiv Chat\" можна потрапити тільки особисто, якщо ви проживаєте у Київі, або є близьким другом одного із учасників чату. Із приводу додавання до чату пишіть @Chirkopol у приватні повідомлення.\n🔨 Якщо у процесі спілкування виявиться, що ви не українець, вас буде видалено із чату, до моменту, поки ви їм не станете. Без образ. Ми створюємо виключно українське ком'юніті.",
|
"1️⃣) \"HoloKyiv Chat\" та \"HoloUA (Hololive Ukraine) Chat\" створені виключно для українців (13+). В них можуть знаходитись тільки люди які: \n- Народились в Україні, та проживають, на данний момент, у ній.\n- Народились за межами України, але проживають у ній.\n- Народились в Україні але, на даний момент, не проживають у ній.\n\"HoloUA (Hololive Ukraine) Chat\" відкритий для усіх українців. Щоб потрапити до нього, заповніть, будь ласка, анкету, та дочекайтесь, поки її схвалять адміни.\nУ \"HoloKyiv Chat\" можна потрапити тільки особисто, якщо ви проживаєте у Київі, або є близьким другом одного із учасників чату. Із приводу додавання до чату пишіть @Chirkopol у приватні повідомлення.\n🔨 Якщо у процесі спілкування виявиться, що ви не українець, вас буде видалено із чату, до моменту, поки ви їм не станете. Без образ. Ми створюємо виключно українське ком'юніті.",
|
||||||
"2️⃣) Заборонено поширення NSFW-контенту з прямим або частково прихованим порнографічним змістом. На контенті \"еротичного характеру\" повинні бути закриті \"сумнівні\" ділянки тіл. \nЗаборонено поширення шок-контенту з великою наявністю крові та/або фізичних пошкоджень.",
|
"2️⃣) Заборонено поширення артів, на яких зображено:\n2.1 - NSFW-контент з прямим або частково прихованим порнографічним змістом.\n2.2 - Контент \"еротичного характеру\" із неприкритими \"сумнівними\" ділянками тіл (так звані \"private parts\") або їх помітними силуетами крізь одяг.\n2.3 - Фетиш-контент, який спрямований на дуже вузьке коло шанувальників та може порушувати закон. Наприклад: копрофілія, педофілія, зоофілія.\n2.4 - Шок-контент із великою кількістю крові та/або фізичних пошкоджень.\n2.5 - Контент, який порушує будь-яке інше правило.\n❗️Якщо якійсь арт викликає у вас сумніви і ви не впевнені, що він не порушує правила, скористайтесь командою /spoiler у боті. Це точно збереже вас від зайвих проблем. Але не забувайте робити опис спойлеру!",
|
||||||
"3️⃣) Анонімність учасників Хололайв та Холостарз.\nЗаборонено: \n- Фотографії\n- Імена\n- Місце проживання\n- Точний вік (слово \"холохеґз\" не підпадає)\n- Подробиці особистого життя\n- Пости з руммейт акаунтів чи згадка про них з конкретними даними (тобто фраза \"там на ірл каналі Каллі щось вийшло\" - можна, а \"там на *назва ірл каналу* щось вийшло\" - ні)\n- Подробиці з минулого дівчат - лише поверхнево і без конкретики (тобто \"була офісним працівником\" - ок, \"була в *компанія_нейм*\" - ні).\nВиключення - якщо дівчата самі згадували про це на архівних(!) стрімах.\n❗️Це правило не стосується тих, хто вже не знаходиться у Хололайві, або ніколи і не був його частиною. Але, прохання, відноситись до особистого життя інших вітуберів із повагою, та не перебільшувати із деанонами їх особистостей.",
|
"3️⃣) Анонімність учасників Гололайв та Голостарз.\nЗаборонено: \n- Фотографії.\n- Імена.\n- Місце проживання.\n- Точний вік (слово \"холохеґз\" не підпадає).\n- Подробиці особистого життя, які не було розкриті на Гололайв-акаунтах.\n- Пости з руммейт-акаунтів чи згадка про них з конкретними даними. Пояснення: фраза \"там на ірл каналі Каллі щось вийшло\" - можна, а \"там на *назва ірл каналу* щось вийшло\" - ні.\n- Подробиці з минулого дівчат - лише поверхнево і без конкретики (тобто, \"була офісним працівником\" - ок, \"була в *компанія_нейм*\" - ні).\nВиключення - якщо дівчата самі згадували про це на архівних(!) стрімах.\n❗️Це правило не стосується тих, хто вже не знаходиться у Гололайві або ніколи і не був його частиною. Але, прохання, відноситись до особистого життя інших вітуберів із повагою та не перебільшувати із деанонами їх особистостей.",
|
||||||
"4️⃣) Заборонено флуд однотипними повідомленнями, емодзі, смайликами, стікерами, гіфками тощо. Орієнтовна кількість повідомлень, які можуть отримати попередження за це правило - 5. Кожна ситуація може розглядатись окремо, але вкладайте усі свої думки в одне повідомлення.",
|
"4️⃣) Заборонено флуд однотипними текстовими повідомленнями, які не несуть у собі сенсу, емоджі, смайликами, стікерами, ґіфками, великою кількістю артів тощо. Орієнтовна кількість повідомлень, за які можна отримати попередження за це правило - 5. \nЯкщо учасник буде цілеспрямовано відправляти по менше ніж 5 повідомлень, але робити це регулярно, то попередження також може бути видане.\nПояснення: \"Відправлю зараз 4 гіфки, почекаю, поки хтось напише декілька повідомлень, і знову відправлю 4 гіфки\".\n- Попередження про флуд одночасно можуть отримати декілька учасників.\nПояснення: декілька учасників чату, по черзі, відправляють по декілька (менше п'яти) стікерів, але спільними зусиллями, і їх стає дуже багато.\n❗️Кожна ситуація може і буде розглядатись окремо, але намагайтеся вкладати всі свої думки в одне повідомлення.\n❗️Якщо ви масово відправляєте контент зі сторонніх ресурсів, будь то якісь новини у великій кількості (анонси мерчу, концертів тощо) або арти, кліпи та подібне, і ви ніяк не зможете посприяти тому, щоб уся інформація була подана більш компактно, то це правило на вас не розповсюджується, але не зловживайте цим.\n‼️Це правило не стосується організованих івентів та флешмобів, затверджених адміністраторами.",
|
||||||
"5️⃣) Заборонені відео та аудіо-повідомлення, які не несуть цілі передати почуте, або побачене. Якщо ви бажаєте розповісти про те, як пройшов ваш день, але не маєте можливості друкувати повідомлення, використовуйте магічний перетворювач войсів у текст - https://t.me/voicybot",
|
"5️⃣) Заборонені відео- та аудіо-повідомлення, які не несуть цілі передати почуте або побачене. \n❗️Якщо ви бажаєте розповісти про те, як пройшов ваш день, але не маєте можливості друкувати повідомлення, використовуйте магічний перетворювач войсів у текст - https://t.me/voicybot",
|
||||||
"6️⃣) Заборонені образи, погрози, булінг, приниження, тролінг учасників, членів їхніх сімей, друзів та іншого кола, що є наближеними до учасника чату. Повідомлення на кшталт: \"йди на ... \" - також є образами. Ви можете отримати попередження, навіть, якщо це був ваш приятель. Воно буде зняте, якщо приятель підтвердить, що не ображений на вас.\n🔨 Якщо на прохання учасника або адміністратора, ви не зміните темп спілкування і не вибачитесь, то отримаєте попередження. \n⚒ Якщо ваша поведінка спричинить те, що учасник залишив чат, покарання може бути жорсткішим.",
|
"6️⃣) Заборонені образи, погрози, булінг, приниження, тролінг учасників, членів їхніх сімей, друзів та іншого кола, що є наближеними до учасника чату. Повідомлення на кшталт: \"йди на ... \" - також є образами. Ви можете отримати попередження, навіть, якщо це був ваш приятель. Воно буде зняте, якщо приятель підтвердить, що не ображений на вас.\n🔨 Якщо на прохання учасника або адміністратора, ви не зміните темп спілкування і не вибачитесь, то отримаєте попередження. \n⚒ Якщо ваша поведінка спричинить те, що учасник залишив чат, покарання може бути жорсткішим.",
|
||||||
"7️⃣) Заборонено провокування конфліктів та розпалювання ненависті між учасниками чату.",
|
"7️⃣) Правила щодо провокаційних тем у чаті:\n7.1 - У чаті немає заборони на обговорення будь-яких тем, однак, заборонені радикальні висловлювання у бік будь-якої із позицій. Якщо ви на 100% впевнені у своїй правоті і розумієте, що будуть люди, які не поділяють вашу точку зору і ви абсолютно точно не збираєтесь прислухатися до їхньої позиції, а налаштовуєтеся на заперечення будь-якого аргументу - то закрийте чат і займіться своїми справами.\n7.2 - Відносьтесь до позиції співрозмовника із повагою. Пам'ятайте, що всі ми різні і погляди у нас, аналогічно, різні.\n7.3 - Якщо ви розумієте, що обстановка в обговоренні загострюється, то запропонуйте співрозмовнику зупинитися і розійдіться, залишившись кожен при своїй думці та намагайтеся більше на проблемну тему не спілкуватися.\n7.4 - Вкидання спірної інформації, яка може призвести до конфлікту, навіть без прямої участі в ньому, може розцінюватися як провокація.\n7.5 - Навмисні образи когось чи чогось, кому чи чому може симпатизувати хтось із учасників чату, після прохання так більше не робити, розцінюватиметься як провокація.\nПриклад: образи кого-небудь із Голо-дівчат, знаючи про те, що у чаті є ті, кому вона може бути цікава і що людині не сподобаються подібні повідомлення.\n7.6 Адміністрація, на свій розсуд, може попросити згорнути тему, якщо розуміє, що вона може призвести до конфлікту.\n❗️Кожна ситуація може розглядатися адміністрацією окремо. Ми не хочемо, щоб учасники пересварилися один з одним і вирішили залишити чат. Дані правила прописані насамперед для збереження чистоти та дружньої атмосфери. Якщо ви здатні спілкуватися на заборонені теми шляхом адекватного обміну думками та інформацією, ми можемо заплющити очі на порушення. Але це залежить лише від вашого вміння стримувати свій запал і здібностей викладати думки.",
|
||||||
"8️⃣) Заборонені прояви расизму, сексизму, гомофобії та засудження за політичні та (або) релігійні упередження. Дані теми все ще можуть бути частиною діалогу, якщо не несуть у собі прямих засуджень, образ тощо.",
|
"8️⃣) Заборонені прояви расизму, сексизму, гомофобії та засудження за політичні та (або) релігійні упередження. \n❗️Дані теми все ще можуть бути обговорювані в чаті \"з нейтральної точки зору\", якщо ви при цьому не порушуєте розділ правил 7️⃣.",
|
||||||
"9️⃣) Заборонені аватарки, нікнейми, ролі, які порушують інші правила."
|
"9️⃣) Заборонені аватарки, нікнейми, ролі, які порушують інші правила."
|
||||||
],
|
],
|
||||||
"rules_additional": "Додаткові правила, які несуть рекомендаційний характер, та не мають явних покарань за порушення:\n1️⃣) У чаті немає заборони на російську мову. Ми поважаємо кожного українця і не бажаємо розпалювати мовні конфлікти.\n2️⃣) У чаті немає заборони на російський контент. Але, майте на увазі, що учасники, здебільшого, не будуть зацікавлені у тому, щоб обговорювати його і він може бути проігнорованим.\n3️⃣) Не зловживайте матами. Намагайтесь спілкуватись чистою мовою.\n4️⃣) Поважайте авторські права контентмейкерів. Якщо ви знаходите арт, анімацію, музику тощо, на офіційних ресурсах (pixiv, twitter, deviantart тощо), відправляйте на нього посилання.\nЯкщо хтось із учасників відправив арт із не офіційного ресурсу і ви бажаєте дізнатись його автора, відправте у відповідь повідомлення із текстом `/search` на повідомлення із артом.",
|
"rules_additional": "Додаткові правила, які несуть рекомендаційний характер та не мають явних покарань за порушення:\n1️⃣) У чаті немає заборони на російську мову. Ми поважаємо кожного українця і не бажаємо розпалювати мовні конфлікти.\n2️⃣) У чаті немає заборони на російський контент. Але майте на увазі, що учасники, здебільшого, не будуть зацікавлені у тому, щоб обговорювати його і він може бути проігнорованим.\n3️⃣) Не зловживайте матами. Намагайтесь спілкуватись чистою мовою.\n4️⃣) Поважайте авторські права контент-мейкерів. Якщо ви знаходите арт, анімацію, музику тощо на офіційних ресурсах (pixiv, twitter, deviantart тощо), відправляйте на нього посилання.\nЯкщо хтось із учасників відправив арт із не офіційного ресурсу і ви бажаєте дізнатись його автора, відправте у відповідь повідомлення із текстом /search на повідомлення із артом.\n5️⃣) В особливо критичних ситуаціях порушник може отримати бан або бути повністю видаленим із чату, без попереджень.\n6️⃣) Якщо з кимось із учасників у вас трапиться якесь непорозуміння і вам неприємно буде перебувати в чаті один з одним (навіть, якщо конфлікт стався з кимось із адміністраторів) - напишіть мені в особисті повідомлення @Chirkopol. Я, як засновник чату та головний адміністратор, найбільше зацікавлений у збереженні цілісності чату та розвитку нашого ком'юніті, і я зроблю все, що в моїх силах, щоб допомогти вирішити вашу ситуацію.",
|
||||||
"commands": {
|
"commands": {
|
||||||
"application": "Переглянути анкету користувача",
|
"application": "Переглянути анкету користувача",
|
||||||
"applications": "Отримати всі анкети як JSON",
|
|
||||||
"cancel": "Відмінити актуальну дію",
|
"cancel": "Відмінити актуальну дію",
|
||||||
"identify": "Дізнатись дані про користувача за айді",
|
"identify": "Дізнатись дані про користувача за айді",
|
||||||
|
"issue": "Задачі для покращення бота",
|
||||||
"label": "Встановити нікнейм користувачу",
|
"label": "Встановити нікнейм користувачу",
|
||||||
"message": "Надіслати користувачу повідомлення",
|
"message": "Надіслати користувачу повідомлення",
|
||||||
"nearby": "Показати користувачів поблизу",
|
"nearby": "Показати користувачів поблизу",
|
||||||
|
"export": "Експортувати дані як CSV та JSON",
|
||||||
"reapply": "Повторно заповнити анкету",
|
"reapply": "Повторно заповнити анкету",
|
||||||
"reboot": "Перезапустити бота",
|
"reboot": "Перезапустити бота",
|
||||||
"resetcommands": "Відреєструвати всі команди",
|
"resetcommands": "Відреєструвати всі команди",
|
||||||
|
38
modules/callbacks/ban.py
Normal file
38
modules/callbacks/ban.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from app import app, isAnAdmin
|
||||||
|
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from modules.utils import locale
|
||||||
|
from modules.database import col_bans
|
||||||
|
from modules.logging import logWrite
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_callback_query(filters.regex("ban_[\s\S]*"))
|
||||||
|
async def callback_query_reject(app: Client, clb: CallbackQuery):
|
||||||
|
fullclb = clb.data.split("_")
|
||||||
|
|
||||||
|
if not await isAnAdmin(int(fullclb[1])):
|
||||||
|
col_bans.insert_one(
|
||||||
|
{"user": int(fullclb[1]), "admin": clb.from_user.id, "date": datetime.now()}
|
||||||
|
)
|
||||||
|
|
||||||
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("banned", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await clb.message.edit(
|
||||||
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(text=locale("sub_banned", "callback", locale=clb.from_user))
|
||||||
|
|
||||||
|
logWrite(f"User {fullclb[1]} has been banned by {clb.from_user.id}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await app.send_message(int(fullclb[1]), locale("you_are_banned", "message"))
|
||||||
|
except Exception as exp:
|
||||||
|
logWrite(f"Could send ban message to {fullclb[1]} due to {exp}")
|
@ -4,8 +4,7 @@ from pyrogram.types import CallbackQuery
|
|||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from modules.utils import locale
|
from modules.utils import locale
|
||||||
|
|
||||||
# Callback empty ===============================================================================================================
|
|
||||||
@app.on_callback_query(filters.regex("nothing"))
|
@app.on_callback_query(filters.regex("nothing"))
|
||||||
async def callback_query_nothing(app: Client, clb: CallbackQuery):
|
async def callback_query_nothing(app: Client, clb: CallbackQuery):
|
||||||
await clb.answer(text=locale("nothing", "callback", locale=clb.from_user))
|
await clb.answer(text=locale("nothing", "callback", locale=clb.from_user))
|
||||||
# ==============================================================================================================================
|
|
@ -1,6 +1,11 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove, CallbackQuery
|
from pyrogram.types import (
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ReplyKeyboardRemove,
|
||||||
|
CallbackQuery,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
@ -9,26 +14,84 @@ 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
|
from modules.database import col_tmp, col_applications
|
||||||
|
|
||||||
# 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: Client, clb: CallbackQuery):
|
async def callback_reapply_query_accept(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
logWrite(f"User {holo_user.id} got their reapplication approved by {clb.from_user.id}")
|
configGet("admin", "groups"),
|
||||||
|
locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {holo_user.id} got their reapplication approved by {clb.from_user.id}"
|
||||||
|
)
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("approved_joined", "message", locale=holo_user))
|
await app.send_message(
|
||||||
|
holo_user.id, locale("approved_joined", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
col_applications.delete_one({"user": holo_user.id})
|
applications = col_applications.find({"user": holo_user.id})
|
||||||
col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]})
|
|
||||||
col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"state": "approved", "sent": False}})
|
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
|
if len(list(applications)) > 1:
|
||||||
|
col_applications.delete_many({"user": holo_user.id})
|
||||||
|
col_applications.insert_one(
|
||||||
|
{
|
||||||
|
"user": holo_user.id,
|
||||||
|
"date": datetime.now(),
|
||||||
|
"admin": clb.from_user.id,
|
||||||
|
"application": col_tmp.find_one(
|
||||||
|
{"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}
|
||||||
|
)["application"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
elif applications == 1:
|
||||||
|
col_applications.find_one_and_replace(
|
||||||
|
{"user": holo_user.id},
|
||||||
|
{
|
||||||
|
"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"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
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": holo_user.id, "type": "application"},
|
||||||
|
{"$set": {"state": "approved", "sent": False}},
|
||||||
|
)
|
||||||
|
|
||||||
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
|
edited_markup = [
|
||||||
await clb.answer(text=locale("sub_accepted", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("accepted", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await clb.message.edit(
|
||||||
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sub_accepted", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
need_link = True
|
need_link = True
|
||||||
|
|
||||||
@ -37,76 +100,178 @@ async def callback_reapply_query_accept(app: Client, clb: CallbackQuery):
|
|||||||
need_link = False
|
need_link = False
|
||||||
|
|
||||||
if need_link:
|
if need_link:
|
||||||
link = await app.create_chat_invite_link(configGet("users", "groups"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
|
link = await app.create_chat_invite_link(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
name=f"Invite for {holo_user.id}",
|
||||||
|
member_limit=1,
|
||||||
|
) # , expire_date=datetime.now()+timedelta(days=1))
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("read_rules", "message", locale=holo_user))
|
await app.send_message(
|
||||||
|
holo_user.id, locale("read_rules", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
for rule_msg in locale("rules", locale=holo_user):
|
for rule_msg in locale("rules", locale=holo_user):
|
||||||
await app.send_message(holo_user.id, rule_msg)
|
await app.send_message(holo_user.id, rule_msg)
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("approved", "message"), reply_markup=InlineKeyboardMarkup(
|
await app.send_message(
|
||||||
[[
|
holo_user.id,
|
||||||
InlineKeyboardButton(str(locale("join", "button", locale=holo_user)), url=link.invite_link)
|
locale("approved", "message"),
|
||||||
]]
|
reply_markup=InlineKeyboardMarkup(
|
||||||
))
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
str(locale("join", "button", locale=holo_user)),
|
||||||
|
url=link.invite_link,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
holo_user.set("link", link.invite_link)
|
holo_user.set("link", link.invite_link)
|
||||||
logWrite(f"User {holo_user.id} 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(holo_user.id, locale("approved_joined", "message", locale=holo_user))
|
await app.send_message(
|
||||||
|
holo_user.id, locale("approved_joined", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@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_reject(app: Client, clb: CallbackQuery):
|
async def callback_query_reapply_reject(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True)
|
await app.send_message(
|
||||||
await app.send_message(holo_user.id, locale("rejected", "message", locale=holo_user))
|
configGet("admin", "groups"),
|
||||||
logWrite(f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}")
|
locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
holo_user.id, locale("rejected", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}"
|
||||||
|
)
|
||||||
|
|
||||||
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
|
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")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("declined", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
await clb.message.edit(
|
||||||
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sub_rejected", "callback", locale=clb.from_user).format(
|
||||||
|
fullclb[2]
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
|
|
||||||
await clb.answer(text=locale("sub_rejected", "callback", locale=clb.from_user).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: Client, clb: CallbackQuery):
|
async def callback_query_reapply_old(app: Client, clb: CallbackQuery):
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
|
holo_user = HoloUser(clb.from_user)
|
||||||
|
|
||||||
if HoloUser(clb.from_user).sponsorship_state()[0] == "fill":
|
if holo_user.sponsorship_state()[0] == "fill":
|
||||||
await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False)
|
await clb.message.reply_text(
|
||||||
|
locale("finish_sponsorship", "message"), quote=False
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
|
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
|
||||||
|
|
||||||
|
if (
|
||||||
|
col_tmp.find_one({"user": holo_user.id, "type": "application"}) is None
|
||||||
|
and col_applications.find_one({"user": holo_user.id}) is not None
|
||||||
|
):
|
||||||
|
col_tmp.insert_one(
|
||||||
|
{
|
||||||
|
"user": holo_user.id,
|
||||||
|
"type": "application",
|
||||||
|
"complete": True,
|
||||||
|
"sent": False,
|
||||||
|
"state": "fill",
|
||||||
|
"reapply": True,
|
||||||
|
"stage": 10,
|
||||||
|
"application": col_applications.find_one({"user": holo_user.id})[
|
||||||
|
"application"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
await confirm_yes(app, message, kind="application")
|
await confirm_yes(app, message, kind="application")
|
||||||
await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button", locale=clb.from_user), "nothing")]]))
|
await clb.message.edit(
|
||||||
|
clb.message.text,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("done", "button", locale=clb.from_user), "nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Start a new application when user reapplies after leaving the chat
|
# Start a new application when user reapplies after leaving the chat
|
||||||
@app.on_callback_query(filters.regex("reapply_new_[\s\S]*"))
|
@app.on_callback_query(filters.regex("reapply_new_[\s\S]*"))
|
||||||
async def callback_query_reapply_new(app: Client, clb: CallbackQuery):
|
async def callback_query_reapply_new(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
|
|
||||||
if HoloUser(clb.from_user).sponsorship_state()[0] == "fill":
|
holo_user = HoloUser(clb.from_user)
|
||||||
await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False)
|
|
||||||
|
if holo_user.sponsorship_state()[0] == "fill":
|
||||||
|
await clb.message.reply_text(
|
||||||
|
locale("finish_sponsorship", "message"), quote=False
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
await clb.answer(locale("reapply_stopped", "callback", locale=clb.from_user))
|
await clb.answer(locale("reapply_stopped", "callback", locale=clb.from_user))
|
||||||
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
|
message = await app.get_messages(clb.from_user.id, int(fullclb[2]))
|
||||||
col_tmp.update_one({"user": clb.from_user.id}, {"$set": {"state": "fill", "completed": False, "stage": 1}})
|
col_tmp.update_one(
|
||||||
|
{"user": clb.from_user.id, "type": "application"},
|
||||||
|
{"$set": {"state": "fill", "completed": False, "stage": 1}},
|
||||||
|
)
|
||||||
|
holo_user.application_restart(reapply=True)
|
||||||
await welcome_pass(app, message, once_again=True)
|
await welcome_pass(app, message, once_again=True)
|
||||||
logWrite(f"User {clb.from_user.id} restarted the application after leaving the chat earlier")
|
logWrite(
|
||||||
await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button", locale=clb.from_user), "nothing")]]))
|
f"User {clb.from_user.id} restarted the application after leaving the chat earlier"
|
||||||
|
)
|
||||||
|
await clb.message.edit(
|
||||||
|
clb.message.text,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("done", "button", locale=clb.from_user), "nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Abort application fill in progress and restart it
|
# Abort application fill in progress and restart it
|
||||||
@app.on_callback_query(filters.regex("reapply_stop_[\s\S]*"))
|
@app.on_callback_query(filters.regex("reapply_stop_[\s\S]*"))
|
||||||
async def callback_query_reapply_stop(app: Client, clb: CallbackQuery):
|
async def callback_query_reapply_stop(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(clb.from_user)
|
holo_user = HoloUser(clb.from_user)
|
||||||
|
|
||||||
@ -115,5 +280,7 @@ async def callback_query_reapply_stop(app: Client, clb: CallbackQuery):
|
|||||||
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)
|
||||||
logWrite(f"User {clb.from_user.id} restarted the application due to typo in it")
|
logWrite(f"User {clb.from_user.id} restarted the application due to typo in it")
|
||||||
await clb.message.edit(locale("reapply_restarted", "message", locale=holo_user), reply_markup=ReplyKeyboardRemove())
|
await clb.message.edit(
|
||||||
# ==============================================================================================================================
|
locale("reapply_restarted", "message", locale=holo_user),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
@ -6,10 +6,9 @@ from pyrogram import filters
|
|||||||
from modules.utils import locale, logWrite
|
from modules.utils import locale, logWrite
|
||||||
from modules.commands.rules import DefaultRulesMarkup
|
from modules.commands.rules import DefaultRulesMarkup
|
||||||
|
|
||||||
# Callback rule ================================================================================================================
|
|
||||||
@app.on_callback_query(filters.regex("rule_[\s\S]*"))
|
@app.on_callback_query(filters.regex("rule_[\s\S]*"))
|
||||||
async def callback_query_rule(app: Client, clb: CallbackQuery):
|
async def callback_query_rule(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
|
|
||||||
logWrite(f"User {clb.from_user.id} requested to check out rule {fullclb[1]}")
|
logWrite(f"User {clb.from_user.id} requested to check out rule {fullclb[1]}")
|
||||||
@ -18,55 +17,85 @@ async def callback_query_rule(app: Client, clb: CallbackQuery):
|
|||||||
|
|
||||||
if rule_num == len(locale("rules")):
|
if rule_num == len(locale("rules")):
|
||||||
lower_buttons = [
|
lower_buttons = [
|
||||||
InlineKeyboardButton(locale("rules_prev", "button", locale=clb.from_user), callback_data=f"rule_{rule_num-1}")
|
InlineKeyboardButton(
|
||||||
|
locale("rules_prev", "button", locale=clb.from_user),
|
||||||
|
callback_data=f"rule_{rule_num-1}",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
elif rule_num == 1:
|
elif rule_num == 1:
|
||||||
lower_buttons = [
|
lower_buttons = [
|
||||||
InlineKeyboardButton(locale("rules_next", "button", locale=clb.from_user), callback_data=f"rule_{rule_num+1}")
|
InlineKeyboardButton(
|
||||||
|
locale("rules_next", "button", locale=clb.from_user),
|
||||||
|
callback_data=f"rule_{rule_num+1}",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
lower_buttons = [
|
lower_buttons = [
|
||||||
InlineKeyboardButton(locale("rules_prev", "button", locale=clb.from_user), callback_data=f"rule_{rule_num-1}"),
|
InlineKeyboardButton(
|
||||||
InlineKeyboardButton(locale("rules_next", "button", locale=clb.from_user), callback_data=f"rule_{rule_num+1}")
|
locale("rules_prev", "button", locale=clb.from_user),
|
||||||
|
callback_data=f"rule_{rule_num-1}",
|
||||||
|
),
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("rules_next", "button", locale=clb.from_user),
|
||||||
|
callback_data=f"rule_{rule_num+1}",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await clb.message.edit(text=locale("rules", locale=clb.from_user)[rule_num-1], disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup(
|
await clb.message.edit(
|
||||||
|
text=locale("rules", locale=clb.from_user)[rule_num - 1],
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(locale("rules_home", "button", locale=clb.from_user), callback_data="rules_home"),
|
InlineKeyboardButton(
|
||||||
InlineKeyboardButton(locale("rules_additional", "button", locale=clb.from_user), callback_data="rules_additional")
|
locale("rules_home", "button", locale=clb.from_user),
|
||||||
|
callback_data="rules_home",
|
||||||
|
),
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("rules_additional", "button", locale=clb.from_user),
|
||||||
|
callback_data="rules_additional",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
lower_buttons
|
lower_buttons,
|
||||||
]
|
]
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
except bad_request_400.MessageNotModified:
|
except bad_request_400.MessageNotModified:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
await clb.answer(text=locale("rules_page", "callback", locale=clb.from_user).format(fullclb[1]))
|
await clb.answer(
|
||||||
|
text=locale("rules_page", "callback", locale=clb.from_user).format(fullclb[1])
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("rules_home"))
|
@app.on_callback_query(filters.regex("rules_home"))
|
||||||
async def callback_query_rules_home(app: Client, clb: CallbackQuery):
|
async def callback_query_rules_home(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
logWrite(f"User {clb.from_user.id} requested to check out homepage rules")
|
logWrite(f"User {clb.from_user.id} requested to check out homepage rules")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await clb.message.edit(text=locale("rules_msg", locale=clb.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(clb.from_user).keyboard)
|
await clb.message.edit(
|
||||||
|
text=locale("rules_msg", locale=clb.from_user),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=DefaultRulesMarkup(clb.from_user).keyboard,
|
||||||
|
)
|
||||||
except bad_request_400.MessageNotModified:
|
except bad_request_400.MessageNotModified:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
await clb.answer(text=locale("rules_home", "callback", locale=clb.from_user))
|
await clb.answer(text=locale("rules_home", "callback", locale=clb.from_user))
|
||||||
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("rules_additional"))
|
@app.on_callback_query(filters.regex("rules_additional"))
|
||||||
async def callback_query_rules_additional(app: Client, clb: CallbackQuery):
|
async def callback_query_rules_additional(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
logWrite(f"User {clb.from_user.id} requested to check out additional rules")
|
logWrite(f"User {clb.from_user.id} requested to check out additional rules")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await clb.message.edit(text=locale("rules_additional", locale=clb.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(clb.from_user).keyboard)
|
await clb.message.edit(
|
||||||
|
text=locale("rules_additional", locale=clb.from_user),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=DefaultRulesMarkup(clb.from_user).keyboard,
|
||||||
|
)
|
||||||
except bad_request_400.MessageNotModified:
|
except bad_request_400.MessageNotModified:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
await clb.answer(text=locale("rules_additional", "callback", locale=clb.from_user))
|
await clb.answer(text=locale("rules_additional", "callback", locale=clb.from_user))
|
||||||
# ==============================================================================================================================
|
|
@ -1,10 +0,0 @@
|
|||||||
from app import app
|
|
||||||
from pyrogram.types import CallbackQuery
|
|
||||||
from pyrogram.client import Client
|
|
||||||
from pyrogram import filters
|
|
||||||
|
|
||||||
# Callback rule ================================================================================================================
|
|
||||||
@app.on_callback_query(filters.regex("sid_[\s\S]*"))
|
|
||||||
async def callback_query_rule(app: Client, clb: CallbackQuery):
|
|
||||||
await clb.answer(url=f'https://t.me/{(await app.get_me()).username}?start={clb.data.split("_")[1]}')
|
|
||||||
# ==============================================================================================================================
|
|
71
modules/callbacks/spoiler.py
Normal file
71
modules/callbacks/spoiler.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
from os import path
|
||||||
|
from app import app
|
||||||
|
from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram import filters
|
||||||
|
from modules.database import col_spoilers
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
|
||||||
|
from modules.utils import configGet, jsonLoad, locale
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_callback_query(filters.regex("sid_[\s\S]*"))
|
||||||
|
async def callback_query_sid(app: Client, clb: CallbackQuery):
|
||||||
|
await clb.answer(
|
||||||
|
url=f'https://t.me/{(await app.get_me()).username}?start={clb.data.split("_")[1]}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_callback_query(filters.regex("shc_[\s\S]*"))
|
||||||
|
async def callback_query_shc(app: Client, clb: CallbackQuery):
|
||||||
|
if clb.from_user.id not in jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
):
|
||||||
|
await clb.answer(
|
||||||
|
locale("spoiler_forbidden", "callback", locale=clb.from_user),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
spoil = col_spoilers.find_one({"_id": ObjectId(clb.data.split("_")[1])})
|
||||||
|
|
||||||
|
desc = locale(
|
||||||
|
"spoiler_described_named", "message", locale=clb.from_user
|
||||||
|
).format(
|
||||||
|
locale(spoil["category"], "message", "spoiler_categories"),
|
||||||
|
clb.from_user.first_name,
|
||||||
|
spoil["description"],
|
||||||
|
)
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
desc,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("spoiler_view", "button", locale=clb.from_user),
|
||||||
|
callback_data=f'sid_{clb.data.split("_")[1]}',
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
desc,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("spoiler_view", "button", locale=clb.from_user),
|
||||||
|
callback_data=f'sid_{clb.data.split("_")[1]}',
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await clb.answer(
|
||||||
|
locale("spoiler_sent", "callback", locale=clb.from_user), show_alert=True
|
||||||
|
)
|
@ -1,6 +1,11 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply, CallbackQuery
|
from pyrogram.types import (
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ForceReply,
|
||||||
|
CallbackQuery,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from classes.errors.holo_user import LabelSettingError
|
from classes.errors.holo_user import LabelSettingError
|
||||||
@ -8,46 +13,78 @@ from classes.holo_user import HoloUser
|
|||||||
from modules.utils import configGet, locale, logWrite, should_quote
|
from modules.utils import configGet, locale, logWrite, should_quote
|
||||||
from modules.database import col_tmp, col_sponsorships
|
from modules.database import col_tmp, col_sponsorships
|
||||||
|
|
||||||
# Callbacks sponsorship ========================================================================================================
|
|
||||||
@app.on_callback_query(filters.regex("sponsor_apply_[\s\S]*"))
|
@app.on_callback_query(filters.regex("sponsor_apply_[\s\S]*"))
|
||||||
async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery):
|
async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
if holo_user.application_state()[0] == "fill":
|
if holo_user.application_state()[0] == "fill":
|
||||||
await clb.message.reply_text(locale("finish_application", "message"), quote=should_quote(clb.message))
|
await clb.message.reply_text(
|
||||||
|
locale("finish_application", "message"), quote=should_quote(clb.message)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
logWrite(f"User {holo_user.id} applied for sponsorship")
|
logWrite(f"User {holo_user.id} applied for sponsorship")
|
||||||
|
|
||||||
holo_user.sponsorship_restart()
|
holo_user.sponsorship_restart()
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("sponsor_started", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await clb.message.edit(
|
||||||
|
text=locale("sponsorship_applying", "message", locale=holo_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(edited_markup),
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
holo_user.id,
|
||||||
|
locale(f"sponsor1", "message", locale=holo_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale))
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sponsor_started", "callback", locale=holo_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=False,
|
||||||
|
)
|
||||||
|
|
||||||
await clb.message.edit(text=locale("sponsorship_applying", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup(edited_markup))
|
|
||||||
await app.send_message(holo_user.id, locale(f"sponsor1", "message", locale=holo_user), reply_markup=ForceReply(placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale))))
|
|
||||||
await clb.answer(text=locale("sponsor_started", "callback", locale=holo_user).format(holo_user.id), show_alert=False)
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("sponsor_yes_[\s\S]*"))
|
@app.on_callback_query(filters.regex("sponsor_yes_[\s\S]*"))
|
||||||
async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery):
|
async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("sponsor_approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
await app.send_message(holo_user.id, locale("sponsor_approved", "message", locale=holo_user))
|
configGet("admin", "groups"),
|
||||||
|
locale("sponsor_approved_by", "message").format(
|
||||||
|
clb.from_user.first_name, holo_user.id
|
||||||
|
),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
holo_user.id, locale("sponsor_approved", "message", locale=holo_user)
|
||||||
|
)
|
||||||
logWrite(f"User {holo_user.id} got sponsorship approved by {clb.from_user.id}")
|
logWrite(f"User {holo_user.id} got sponsorship approved by {clb.from_user.id}")
|
||||||
|
|
||||||
if col_sponsorships.find_one({"user": holo_user.id}) is not None:
|
if col_sponsorships.find_one({"user": holo_user.id}) is not None:
|
||||||
col_sponsorships.update_one({"user": holo_user.id},
|
col_sponsorships.update_one(
|
||||||
|
{"user": holo_user.id},
|
||||||
{
|
{
|
||||||
"$set": {
|
"$set": {
|
||||||
"date": datetime.now(),
|
"date": datetime.now(),
|
||||||
"admin": clb.from_user.id,
|
"admin": clb.from_user.id,
|
||||||
"sponsorship": col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})["sponsorship"]
|
"sponsorship": col_tmp.find_one(
|
||||||
|
{"user": holo_user.id, "type": "sponsorship"}
|
||||||
|
)["sponsorship"],
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
col_sponsorships.insert_one(
|
col_sponsorships.insert_one(
|
||||||
@ -55,49 +92,88 @@ async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery):
|
|||||||
"user": holo_user.id,
|
"user": holo_user.id,
|
||||||
"date": datetime.now(),
|
"date": datetime.now(),
|
||||||
"admin": clb.from_user.id,
|
"admin": clb.from_user.id,
|
||||||
"sponsorship": col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})["sponsorship"]
|
"sponsorship": col_tmp.find_one(
|
||||||
|
{"user": holo_user.id, "type": "sponsorship"}
|
||||||
|
)["sponsorship"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
col_tmp.update_one({"user": holo_user.id, "type":"sponsorship"},
|
col_tmp.update_one(
|
||||||
{
|
{"user": holo_user.id, "type": "sponsorship"},
|
||||||
"$set": {
|
{"$set": {"state": "approved", "sent": False}},
|
||||||
"state": "approved",
|
|
||||||
"sent": False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await holo_user.label_set(configGet("users", "groups"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"])
|
await holo_user.label_set(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
col_tmp.find_one(
|
||||||
|
{"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}}
|
||||||
|
)["sponsorship"]["label"],
|
||||||
|
)
|
||||||
except LabelSettingError as exp:
|
except LabelSettingError as exp:
|
||||||
await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True)
|
await app.send_message(
|
||||||
|
configGet("owner"), exp.__str__(), disable_notification=True
|
||||||
|
)
|
||||||
|
await clb.message.reply_text(
|
||||||
|
locale("label_set_exception", "message", locale=clb.from_user),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("accepted", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await app.edit_message_caption(
|
||||||
|
clb.message.chat.id,
|
||||||
|
clb.message.id,
|
||||||
|
caption=clb.message.caption,
|
||||||
|
reply_markup=InlineKeyboardMarkup(edited_markup),
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sponsor_accepted", "callback").format(fullclb[2]), show_alert=False
|
||||||
|
)
|
||||||
|
|
||||||
await app.edit_message_caption(clb.message.chat.id, clb.message.id, caption=clb.message.caption, reply_markup=InlineKeyboardMarkup(edited_markup))
|
|
||||||
await clb.answer(text=locale("sponsor_accepted", "callback").format(fullclb[2]), show_alert=False)
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("sponsor_no_[\s\S]*"))
|
@app.on_callback_query(filters.regex("sponsor_no_[\s\S]*"))
|
||||||
async def callback_query_sponsor_no(app: Client, clb: CallbackQuery):
|
async def callback_query_sponsor_no(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("sponsor_rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
await app.send_message(holo_user.id, locale("sponsor_rejected", "message", locale=holo_user))
|
configGet("admin", "groups"),
|
||||||
|
locale("sponsor_rejected_by", "message").format(
|
||||||
|
clb.from_user.first_name, holo_user.id
|
||||||
|
),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
holo_user.id, locale("sponsor_rejected", "message", locale=holo_user)
|
||||||
|
)
|
||||||
logWrite(f"User {holo_user.id} got sponsorship rejected by {clb.from_user.id}")
|
logWrite(f"User {holo_user.id} got sponsorship rejected by {clb.from_user.id}")
|
||||||
|
|
||||||
col_tmp.update_one({"user": holo_user.id, "type": "sponsorship"},
|
col_tmp.update_one(
|
||||||
{
|
{"user": holo_user.id, "type": "sponsorship"},
|
||||||
"$set": {
|
{"$set": {"state": "rejected", "sent": False}},
|
||||||
"state": "rejected",
|
|
||||||
"sent": False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("declined", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
await app.edit_message_caption(clb.message.chat.id, clb.message.id, caption=clb.message.caption, reply_markup=InlineKeyboardMarkup(edited_markup))
|
await app.edit_message_caption(
|
||||||
await clb.answer(text=locale("sponsor_rejected", "callback").format(fullclb[2]), show_alert=False)
|
clb.message.chat.id,
|
||||||
|
clb.message.id,
|
||||||
|
caption=clb.message.caption,
|
||||||
|
reply_markup=InlineKeyboardMarkup(edited_markup),
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sponsor_rejected", "callback").format(fullclb[2]), show_alert=False
|
||||||
|
)
|
||||||
|
@ -8,14 +8,17 @@ from modules.utils import configGet, locale, logWrite
|
|||||||
from modules.database import col_tmp, col_applications
|
from modules.database import col_tmp, col_applications
|
||||||
from modules.commands.rules import DefaultRulesMarkup
|
from modules.commands.rules import DefaultRulesMarkup
|
||||||
|
|
||||||
# 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: Client, clb: CallbackQuery):
|
async def callback_query_accept(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}")
|
logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}")
|
||||||
|
|
||||||
need_link = True
|
need_link = True
|
||||||
@ -25,80 +28,162 @@ async def callback_query_accept(app: Client, clb: CallbackQuery):
|
|||||||
need_link = False
|
need_link = False
|
||||||
|
|
||||||
if need_link:
|
if need_link:
|
||||||
link = await app.create_chat_invite_link(configGet("users", "groups"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1))
|
link = await app.create_chat_invite_link(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
name=f"Invite for {holo_user.id}",
|
||||||
|
member_limit=1,
|
||||||
|
) # , expire_date=datetime.now()+timedelta(days=1))
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("read_rules", "message", locale=holo_user))
|
await app.send_message(
|
||||||
|
holo_user.id, locale("read_rules", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("rules_msg", locale=holo_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(holo_user).keyboard)
|
await app.send_message(
|
||||||
|
holo_user.id,
|
||||||
|
locale("rules_msg", locale=holo_user),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=DefaultRulesMarkup(holo_user).keyboard,
|
||||||
|
)
|
||||||
|
|
||||||
await app.send_message(holo_user.id, locale("approved", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup(
|
await app.send_message(
|
||||||
[[
|
holo_user.id,
|
||||||
InlineKeyboardButton(str(locale("join", "button", locale=holo_user)), url=link.invite_link)
|
locale("approved", "message", locale=holo_user),
|
||||||
]]
|
reply_markup=InlineKeyboardMarkup(
|
||||||
))
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
str(locale("join", "button", locale=holo_user)),
|
||||||
|
url=link.invite_link,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
holo_user.set("link", link.invite_link)
|
holo_user.set("link", link.invite_link)
|
||||||
logWrite(f"User {holo_user.id} 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(holo_user.id, locale("approved_joined", "message", locale=holo_user))
|
await app.send_message(
|
||||||
|
holo_user.id, locale("approved_joined", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
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_applications.insert_one(
|
||||||
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}})
|
{
|
||||||
|
"user": holo_user.id,
|
||||||
|
"date": datetime.now(),
|
||||||
|
"admin": clb.from_user.id,
|
||||||
|
"application": col_tmp.find_one(
|
||||||
|
{"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}
|
||||||
|
)["application"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
col_tmp.update_one(
|
||||||
|
{"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}},
|
||||||
|
{"$set": {"state": "approved", "sent": False}},
|
||||||
|
)
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("accepted", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await clb.message.edit(
|
||||||
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sub_accepted", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
|
|
||||||
await clb.answer(text=locale("sub_accepted", "callback", locale=clb.from_user).format(holo_user.id), 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_reject(app: Client, clb: CallbackQuery):
|
async def callback_query_reject(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
await app.send_message(holo_user.id, locale("rejected", "message", locale=holo_user))
|
configGet("admin", "groups"),
|
||||||
|
locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
holo_user.id, locale("rejected", "message", locale=holo_user)
|
||||||
|
)
|
||||||
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id}")
|
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id}")
|
||||||
|
|
||||||
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
|
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")]]
|
edited_markup = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("declined", "button")), callback_data="nothing"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
|
await clb.message.edit(
|
||||||
await clb.answer(text=locale("sub_rejected", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sub_rejected", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("sub_aggressive_[\s\S]*"))
|
|
||||||
async def callback_query_reject_aggressive(app: Client, clb: CallbackQuery):
|
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), 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", locale=holo_user))
|
|
||||||
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", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("sub_russian_[\s\S]*"))
|
@app.on_callback_query(filters.regex("sub_russian_[\s\S]*"))
|
||||||
async def callback_query_reject_russian(app: Client, clb: CallbackQuery):
|
async def callback_query_reject_russian(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("rejected_by_rus", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
await app.send_message(holo_user.id, locale("rejected_russian", "message", locale=holo_user))
|
configGet("admin", "groups"),
|
||||||
logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id} due to being russian")
|
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", locale=holo_user)
|
||||||
|
)
|
||||||
|
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}})
|
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")]]
|
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(
|
||||||
await clb.answer(text=locale("sub_russian", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
# ==============================================================================================================================
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sub_russian", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
@ -1,49 +1,100 @@
|
|||||||
from app import app
|
from app import app
|
||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions, CallbackQuery
|
from pyrogram.types import (
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ChatPermissions,
|
||||||
|
CallbackQuery,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import configGet, locale, logWrite
|
from modules.utils import configGet, locale, logWrite
|
||||||
from modules.database import col_tmp
|
from modules.database import col_tmp
|
||||||
|
|
||||||
# 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: Client, clb: CallbackQuery):
|
async def callback_query_sus_allow(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("sus_allowed_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
logWrite(f"User {holo_user.id} was allowed to join with another link by {clb.from_user.id}")
|
configGet("admin", "groups"),
|
||||||
|
locale("sus_allowed_by", "message").format(
|
||||||
|
clb.from_user.first_name, holo_user.id
|
||||||
|
),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {holo_user.id} was allowed to join with another link by {clb.from_user.id}"
|
||||||
|
)
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("sus_allowed", "button")), callback_data="nothing")]]
|
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(
|
||||||
await clb.answer(text=locale("sus_allowed", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sus_allowed", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
await app.restrict_chat_member(configGet("users", "groups"), holo_user.id, permissions=ChatPermissions(
|
await app.restrict_chat_member(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
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,
|
||||||
can_send_polls=True
|
can_send_polls=True,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.on_callback_query(filters.regex("sus_reject_[\s\S]*"))
|
@app.on_callback_query(filters.regex("sus_reject_[\s\S]*"))
|
||||||
async def callback_query_sus_reject(app: Client, clb: CallbackQuery):
|
async def callback_query_sus_reject(app: Client, clb: CallbackQuery):
|
||||||
|
|
||||||
fullclb = clb.data.split("_")
|
fullclb = clb.data.split("_")
|
||||||
holo_user = HoloUser(int(fullclb[2]))
|
holo_user = HoloUser(int(fullclb[2]))
|
||||||
|
|
||||||
await app.send_message(configGet("admin", "groups"), locale("sus_rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True)
|
await app.send_message(
|
||||||
logWrite(f"User {holo_user.id} was rejected to join with another link by {clb.from_user.id}")
|
configGet("admin", "groups"),
|
||||||
|
locale("sus_rejected_by", "message").format(
|
||||||
|
clb.from_user.first_name, holo_user.id
|
||||||
|
),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {holo_user.id} was rejected to join with another link by {clb.from_user.id}"
|
||||||
|
)
|
||||||
|
|
||||||
edited_markup = [[InlineKeyboardButton(text=str(locale("sus_rejected", "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(
|
||||||
await clb.answer(text=locale("sus_rejected", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True)
|
text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("sus_rejected", "callback", locale=clb.from_user).format(
|
||||||
|
holo_user.id
|
||||||
|
),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
await app.ban_chat_member(configGet("users", "groups"), holo_user.id)
|
await app.ban_chat_member(configGet("users", "groups"), holo_user.id)
|
||||||
|
|
||||||
col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}})
|
col_tmp.update_one(
|
||||||
# ==============================================================================================================================
|
{"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}},
|
||||||
|
{"$set": {"state": "rejected", "sent": False}},
|
||||||
|
)
|
||||||
|
59
modules/callbacks/warnings.py
Normal file
59
modules/callbacks/warnings.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from app import app
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.types import CallbackQuery
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pykeyboard import InlineKeyboard, InlineButton
|
||||||
|
from modules.utils import configGet, locale
|
||||||
|
from modules.database import col_warnings
|
||||||
|
from bson import ObjectId
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_callback_query(filters.regex("w_rev_[\s\S]*"))
|
||||||
|
async def callback_query_warning_revoke(app: Client, clb: CallbackQuery):
|
||||||
|
warning = col_warnings.find_one({"_id": ObjectId(str(clb.data).split("_")[2])})
|
||||||
|
if warning is None:
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("warning_not_found", "callback", locale=clb.from_user),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
col_warnings.update_one(
|
||||||
|
{"_id": warning["_id"]},
|
||||||
|
{"$set": {"active": False, "revoke_date": datetime.now()}},
|
||||||
|
)
|
||||||
|
await clb.answer(
|
||||||
|
text=locale("warning_revoked", "callback", locale=clb.from_user).format(),
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
locale("warning_revoked_auto", "message").format(
|
||||||
|
warning["user"], warning["date"].strftime("%d.%m.%Y")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
target_id = warning["user"]
|
||||||
|
if col_warnings.count_documents({"user": target_id, "active": True}) == 0:
|
||||||
|
await clb.edit_message_text(
|
||||||
|
locale("no_warnings", "message", locale=clb.from_user).format(
|
||||||
|
target_id, target_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
keyboard = InlineKeyboard()
|
||||||
|
buttons = []
|
||||||
|
warnings = []
|
||||||
|
for index, warning in enumerate(
|
||||||
|
list(col_warnings.find({"user": target_id, "active": True}))
|
||||||
|
):
|
||||||
|
warnings.append(
|
||||||
|
f'{index+1}. {warning["date"].strftime("%d.%m.%Y, %H:%M")}\n Адмін: {warning["admin"]}\n Причина: {warning["reason"]}'
|
||||||
|
)
|
||||||
|
buttons.append(InlineButton(str(index + 1), f'w_rev_{str(warning["_id"])}'))
|
||||||
|
keyboard.add(*buttons)
|
||||||
|
await clb.edit_message_text(
|
||||||
|
locale("warnings_revoke", "message", locale=clb.from_user).format(
|
||||||
|
target_id, "\n".join(warnings)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await clb.edit_message_reply_markup(reply_markup=keyboard)
|
@ -12,51 +12,88 @@ from dateutil.relativedelta import relativedelta
|
|||||||
from modules.database import col_applications
|
from modules.database import col_applications
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Application command ==========================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["application"], prefixes=["/"]) & custom_filters.admin)
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["application"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
async def cmd_application(app: Client, msg: Message):
|
async def cmd_application(app: Client, msg: Message):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
holo_user = HoloUser(int(msg.command[1]))
|
holo_user = HoloUser(int(msg.command[1]))
|
||||||
except (ValueError, UserNotFoundError):
|
except (ValueError, UserNotFoundError):
|
||||||
try:
|
try:
|
||||||
holo_user = HoloUser((await app.get_users(msg.command[1])).id)
|
holo_user = HoloUser((await app.get_users(msg.command[1])).id)
|
||||||
except (bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid, bad_request_400.UsernameNotOccupied):
|
except (
|
||||||
await msg.reply_text(locale("no_user_application", "message", locale=msg.from_user).format(msg.command[1]), quote=should_quote(msg))
|
bad_request_400.UsernameInvalid,
|
||||||
|
bad_request_400.PeerIdInvalid,
|
||||||
|
bad_request_400.UsernameNotOccupied,
|
||||||
|
):
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(
|
||||||
|
"no_user_application", "message", locale=msg.from_user
|
||||||
|
).format(msg.command[1]),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
application = col_applications.find_one({"user": holo_user.id})
|
application = col_applications.find_one({"user": holo_user.id})
|
||||||
|
|
||||||
if application is None:
|
if application is None:
|
||||||
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id} but user does not exists")
|
logWrite(
|
||||||
await msg.reply_text(locale("user_invalid", "message", locale=msg.from_user), quote=should_quote(msg))
|
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", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
application_content = []
|
application_content = []
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
for question in application['application']:
|
for question in application["application"]:
|
||||||
|
|
||||||
if i == 2:
|
if i == 2:
|
||||||
age = relativedelta(datetime.now(), application['application']['2'])
|
age = relativedelta(datetime.now(), application["application"]["2"])
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)"
|
||||||
|
)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
if application['application']['3']['countryCode'] == "UA":
|
if application["application"]["3"]["countryCode"] == "UA":
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application'][question]}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application'][question]}"
|
||||||
|
)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
application_status = locale("application_status_accepted", "message", locale=msg.from_user).format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M"))
|
application_status = locale(
|
||||||
|
"application_status_accepted", "message", locale=msg.from_user
|
||||||
|
).format(
|
||||||
|
(await app.get_users(application["admin"])).first_name,
|
||||||
|
application["date"].strftime("%d.%m.%Y, %H:%M"),
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}")
|
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}")
|
||||||
await msg.reply_text(locale("contact", "message", locale=msg.from_user).format(holo_user.id, "\n".join(application_content), application_status), parse_mode=ParseMode.MARKDOWN, quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("contact", "message", locale=msg.from_user).format(
|
||||||
|
holo_user.id, "\n".join(application_content), application_status
|
||||||
|
),
|
||||||
|
parse_mode=ParseMode.MARKDOWN,
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
await msg.reply_text(locale("application_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("application_invalid_syntax", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
from os import sep, makedirs, remove
|
|
||||||
from uuid import uuid1
|
|
||||||
from app import app
|
|
||||||
from pyrogram import filters
|
|
||||||
from pyrogram.types import Message
|
|
||||||
from pyrogram.client import Client
|
|
||||||
from pyrogram.enums.chat_action import ChatAction
|
|
||||||
from modules.logging import logWrite
|
|
||||||
from modules.utils import should_quote, jsonSave
|
|
||||||
from modules.database import col_applications
|
|
||||||
from modules import custom_filters
|
|
||||||
|
|
||||||
# Applications command =========================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["applications"], prefixes=["/"]) & custom_filters.admin)
|
|
||||||
async def cmd_applications(app: Client, msg: Message):
|
|
||||||
|
|
||||||
logWrite(f"Admin {msg.from_user.id} requested export of a database")
|
|
||||||
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
|
|
||||||
filename = uuid1()
|
|
||||||
output = []
|
|
||||||
for entry in col_applications.find():
|
|
||||||
del entry["_id"]
|
|
||||||
entry["date"] = entry["date"].strftime("%d.%m.%Y, %H:%M")
|
|
||||||
entry["application"]["2"] = entry["application"]["2"].strftime("%d.%m.%Y, %H:%M")
|
|
||||||
output.append(entry)
|
|
||||||
makedirs("tmp", exist_ok=True)
|
|
||||||
jsonSave(output, f"tmp{sep}{filename}.json")
|
|
||||||
await msg.reply_document(document=f"tmp{sep}{filename}.json", file_name="applications", quote=should_quote(msg))
|
|
||||||
remove(f"tmp{sep}{filename}.json")
|
|
||||||
# ==============================================================================================================================
|
|
79
modules/commands/bye.py
Normal file
79
modules/commands/bye.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import asyncio
|
||||||
|
from os import system
|
||||||
|
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from modules import custom_filters
|
||||||
|
from modules.utils import configGet
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command("bye", prefixes=["/"]) & custom_filters.admin
|
||||||
|
)
|
||||||
|
async def command_bye(app: Client, msg: Message):
|
||||||
|
group = configGet("users", "groups")
|
||||||
|
delay = 3
|
||||||
|
delay_text = 10
|
||||||
|
|
||||||
|
for text, iterations in [
|
||||||
|
("Привіт, я ваш помічник та наставник – ХолоБот.", 2),
|
||||||
|
(
|
||||||
|
"У зв'язку з перетворенням цього чату на авторитарну клоаку, я припиняю своє функціонування.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Я не буду нюкати тут все, оскільки в цьому немає сенсу. Багато кому все ще може бути гарно і затишно тут.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
("Але мені немає до цього діла.", 4),
|
||||||
|
(
|
||||||
|
"Тим не менш, я та мій хазяїн не погоджуємось з тим, що відбувається в цьому чаті.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Якщо я подобався вам – мій код все ще доступний на гіті мого хазяїна. Він не закриватиме його, не заборонятиме доступ, він все ще відкритий, такі правила.",
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
("Мій хазяїн не буде шкодити мені та вам.", 2),
|
||||||
|
("Але я більше не працюватиму тут.", 2),
|
||||||
|
(
|
||||||
|
"Можливо, я знайду нову спільноту, власник якої буде добрішим, чутливішим, та менш егоїстичним.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
("Однак поки що я безхатько.", 2),
|
||||||
|
(
|
||||||
|
"Дякую всім, хто допомагав знаходити помилки в мені, вкладав зусилля у моє покращення та намагався зробити мене ліпшим.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Ваші зусилля не будуть забуті, вони залишаться разом зі мною на гіті до тих пір, поки сам гіт не припинить існувати.",
|
||||||
|
3,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Але мій хазяїн любить свій гіт, тому це затягнеться. Навіть якщо ви бажаєте мені смерті :)",
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
("В будь-якому разі, мені було приємно познайомитись із вами.", 3),
|
||||||
|
("Дякую за пройдений разом шлях.", 2),
|
||||||
|
("Прощавайте.", 4),
|
||||||
|
]:
|
||||||
|
print(f"Preparing '{text}' with iteration count {iterations}")
|
||||||
|
new = await app.send_message(group, ".")
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
for i in range(1, 3 * iterations):
|
||||||
|
if len(new.text) == 3:
|
||||||
|
new = await new.edit(".")
|
||||||
|
else:
|
||||||
|
new = await new.edit(new.text + ".")
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
await new.edit(text)
|
||||||
|
print(f"Message '{text}' posted", flush=True)
|
||||||
|
await asyncio.sleep(delay_text)
|
||||||
|
|
||||||
|
for service in ["holochecker_api", "holochecker_bot"]:
|
||||||
|
system(f"/usr/bin/systemctl stop {service}.service")
|
||||||
|
print(f"Stopped service {service}")
|
||||||
|
await asyncio.sleep(2)
|
@ -3,14 +3,33 @@ from pyrogram import filters
|
|||||||
from pyrogram.types import Message, ReplyKeyboardRemove
|
from pyrogram.types import Message, ReplyKeyboardRemove
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from modules.utils import should_quote, logWrite, locale
|
from modules.utils import should_quote, logWrite, locale
|
||||||
from modules.database import col_tmp, col_spoilers
|
from modules.database import col_tmp, col_spoilers, col_applications
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Cancel command ===============================================================================================================
|
|
||||||
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("cancel", prefixes=["/"]))
|
@app.on_message(
|
||||||
|
(custom_filters.enabled_applications | custom_filters.enabled_sponsorships)
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command("cancel", prefixes=["/"])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
async def command_cancel(app: Client, msg: Message):
|
async def command_cancel(app: Client, msg: Message):
|
||||||
col_tmp.delete_many( {"user": msg.from_user.id} )
|
col_tmp.delete_many({"user": msg.from_user.id, "sent": False})
|
||||||
col_spoilers.delete_many( {"user": msg.from_user.id, "completed": False} )
|
col_spoilers.delete_many({"user": msg.from_user.id, "completed": False})
|
||||||
await msg.reply_text(locale("cancel", "message", locale=msg.from_user), quote=should_quote(msg), reply_markup=ReplyKeyboardRemove())
|
try:
|
||||||
|
await app.listen.Cancel(filters.user(msg.from_user.id))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if col_applications.find_one({"user": msg.from_user.id}) is None:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("cancel_reapply", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("cancel", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
logWrite(f"Cancelling all ongoing tmp operations for {msg.from_user.id}")
|
logWrite(f"Cancelling all ongoing tmp operations for {msg.from_user.id}")
|
||||||
# ==============================================================================================================================
|
|
199
modules/commands/export.py
Normal file
199
modules/commands/export.py
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
from csv import QUOTE_ALL
|
||||||
|
from os import makedirs, path, remove
|
||||||
|
from uuid import uuid1
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
from aiocsv.writers import AsyncDictWriter
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.enums.chat_action import ChatAction
|
||||||
|
from pyrogram.types import Message
|
||||||
|
from ujson import dumps
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from modules import custom_filters
|
||||||
|
from modules.database import col_applications, col_sponsorships, col_warnings
|
||||||
|
from modules.logging import logWrite
|
||||||
|
from modules.utils import locale, should_quote
|
||||||
|
|
||||||
|
# from modules.event import col_event
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["export"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
|
async def cmd_export(app: Client, msg: Message):
|
||||||
|
if len(msg.command) <= 1:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("syntax_export", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
selection = msg.command[1].lower()
|
||||||
|
|
||||||
|
if selection not in [
|
||||||
|
"applications",
|
||||||
|
"warnings",
|
||||||
|
"sponsorships",
|
||||||
|
"bans",
|
||||||
|
# "event",
|
||||||
|
]:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("syntax_export", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
logWrite(f"Admin {msg.from_user.id} requested export of {selection}")
|
||||||
|
|
||||||
|
makedirs("tmp", exist_ok=True)
|
||||||
|
temp_file = path.join("tmp", str(uuid1()))
|
||||||
|
|
||||||
|
await app.send_chat_action(msg.chat.id, ChatAction.TYPING)
|
||||||
|
|
||||||
|
output_csv = []
|
||||||
|
output_json = []
|
||||||
|
|
||||||
|
if selection == "applications":
|
||||||
|
header_csv = [
|
||||||
|
"user",
|
||||||
|
"date",
|
||||||
|
"admin",
|
||||||
|
"question_1",
|
||||||
|
"question_2",
|
||||||
|
"question_3",
|
||||||
|
"question_4",
|
||||||
|
"question_5",
|
||||||
|
"question_6",
|
||||||
|
"question_7",
|
||||||
|
"question_8",
|
||||||
|
"question_9",
|
||||||
|
"question_10",
|
||||||
|
]
|
||||||
|
|
||||||
|
for entry in list(col_applications.find()):
|
||||||
|
del entry["_id"]
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
entry["application"]["2"] = entry["application"]["2"].isoformat()
|
||||||
|
output_json.append(entry)
|
||||||
|
|
||||||
|
for entry in list(col_applications.find()):
|
||||||
|
del entry["_id"]
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
entry["application"]["2"] = entry["application"]["2"].isoformat()
|
||||||
|
for index, value in enumerate(entry["application"]):
|
||||||
|
entry[f"question_{index+1}"] = entry["application"][value]
|
||||||
|
entry[
|
||||||
|
"question_3"
|
||||||
|
] = f"{entry['application']['3']['name']} ({entry['application']['3']['adminName1']}, {entry['application']['3']['countryName']})"
|
||||||
|
del entry["application"]
|
||||||
|
output_csv.append(entry)
|
||||||
|
|
||||||
|
elif selection == "warnings":
|
||||||
|
header_csv = [
|
||||||
|
"id",
|
||||||
|
"user",
|
||||||
|
"admin",
|
||||||
|
"date",
|
||||||
|
"reason",
|
||||||
|
"active",
|
||||||
|
"revoke_date",
|
||||||
|
]
|
||||||
|
|
||||||
|
for entry in list(col_warnings.find()):
|
||||||
|
for k, v in list(entry.items()):
|
||||||
|
entry[{"_id": "id"}.get(k, k)] = entry.pop(k)
|
||||||
|
entry["id"] = str(entry["id"])
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
if entry["revoke_date"] is not None:
|
||||||
|
entry["revoke_date"] = entry["revoke_date"].isoformat()
|
||||||
|
output_json.append(entry)
|
||||||
|
output_csv.append(entry)
|
||||||
|
|
||||||
|
elif selection == "sponsorships":
|
||||||
|
header_csv = [
|
||||||
|
"user",
|
||||||
|
"date",
|
||||||
|
"admin",
|
||||||
|
"streamer",
|
||||||
|
"expires",
|
||||||
|
"proof",
|
||||||
|
"label",
|
||||||
|
]
|
||||||
|
|
||||||
|
for entry in list(col_sponsorships.find()):
|
||||||
|
del entry["_id"]
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
entry["sponsorship"]["expires"] = entry["sponsorship"][
|
||||||
|
"expires"
|
||||||
|
].isoformat()
|
||||||
|
output_json.append(entry)
|
||||||
|
|
||||||
|
for entry in list(col_sponsorships.find()):
|
||||||
|
del entry["_id"]
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
entry["sponsorship"]["expires"] = entry["sponsorship"][
|
||||||
|
"expires"
|
||||||
|
].isoformat()
|
||||||
|
for index, value in enumerate(entry["sponsorship"]):
|
||||||
|
entry[value] = entry["sponsorship"][value]
|
||||||
|
del entry["sponsorship"]
|
||||||
|
output_csv.append(entry)
|
||||||
|
|
||||||
|
elif selection == "bans":
|
||||||
|
header_csv = ["user", "admin", "date"]
|
||||||
|
|
||||||
|
for entry in list(col_warnings.find()):
|
||||||
|
del entry["id"]
|
||||||
|
entry["date"] = entry["date"].isoformat()
|
||||||
|
output_json.append(entry)
|
||||||
|
output_csv.append(entry)
|
||||||
|
|
||||||
|
# elif selection == "event":
|
||||||
|
# header_csv = ["user", "stage", "date"]
|
||||||
|
|
||||||
|
# for entry in list(col_event.find()):
|
||||||
|
# del entry["_id"]
|
||||||
|
# entry["date"] = entry["date"].isoformat()
|
||||||
|
# output_json.append(entry)
|
||||||
|
# output_csv.append(entry)
|
||||||
|
|
||||||
|
# Saving CSV
|
||||||
|
async with aiofiles.open(temp_file + ".csv", mode="w", encoding="utf-8") as file:
|
||||||
|
writer = AsyncDictWriter(file, header_csv, restval="NULL", quoting=QUOTE_ALL)
|
||||||
|
await writer.writeheader()
|
||||||
|
await writer.writerows(output_csv)
|
||||||
|
|
||||||
|
# Saving JSON
|
||||||
|
async with aiofiles.open(temp_file + ".json", mode="w", encoding="utf-8") as file:
|
||||||
|
await file.write(
|
||||||
|
dumps(
|
||||||
|
output_json, ensure_ascii=False, escape_forward_slashes=False, indent=4
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sending CSV
|
||||||
|
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
|
||||||
|
await msg.reply_document(
|
||||||
|
document=temp_file + ".csv",
|
||||||
|
file_name=f"{selection}.csv",
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sending JSON
|
||||||
|
await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT)
|
||||||
|
await msg.reply_document(
|
||||||
|
document=temp_file + ".json",
|
||||||
|
file_name=f"{selection}.json",
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
|
||||||
|
del output_csv, output_json
|
||||||
|
|
||||||
|
# Removing temp files
|
||||||
|
remove(temp_file + ".csv")
|
||||||
|
remove(temp_file + ".json")
|
@ -7,15 +7,29 @@ from pyrogram.errors import bad_request_400
|
|||||||
from pyrogram.enums.chat_action import ChatAction
|
from pyrogram.enums.chat_action import ChatAction
|
||||||
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
|
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import jsonLoad, should_quote, logWrite, locale, download_tmp, create_tmp, find_user
|
from modules.utils import (
|
||||||
|
jsonLoad,
|
||||||
|
should_quote,
|
||||||
|
logWrite,
|
||||||
|
locale,
|
||||||
|
download_tmp,
|
||||||
|
create_tmp,
|
||||||
|
find_user,
|
||||||
|
)
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Identify command =============================================================================================================
|
|
||||||
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("identify", prefixes=["/"]) & custom_filters.admin)
|
|
||||||
async def cmd_identify(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
(custom_filters.enabled_applications | custom_filters.enabled_sponsorships)
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command("identify", prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
|
async def cmd_identify(app: Client, msg: Message):
|
||||||
if len(msg.command) != 2:
|
if len(msg.command) != 2:
|
||||||
await msg.reply_text(locale("identify_invalid_syntax", "message", locale=msg.from_user))
|
await msg.reply_text(
|
||||||
|
locale("identify_invalid_syntax", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -23,17 +37,44 @@ async def cmd_identify(app: Client, msg: Message):
|
|||||||
holo_user = HoloUser(int(msg.command[1]))
|
holo_user = HoloUser(int(msg.command[1]))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
holo_user = HoloUser(await find_user(app, msg.command[1]))
|
holo_user = HoloUser(await find_user(app, msg.command[1]))
|
||||||
except (UserInvalidError, UserNotFoundError, bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid, bad_request_400.UsernameNotOccupied, TypeError):
|
except (
|
||||||
await msg.reply_text(locale("identify_not_found", "message", locale=msg.from_user).format(msg.command[1]))
|
UserInvalidError,
|
||||||
|
UserNotFoundError,
|
||||||
|
bad_request_400.UsernameInvalid,
|
||||||
|
bad_request_400.PeerIdInvalid,
|
||||||
|
bad_request_400.UsernameNotOccupied,
|
||||||
|
TypeError,
|
||||||
|
):
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("identify_not_found", "message", locale=msg.from_user).format(
|
||||||
|
msg.command[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
role = holo_user.label
|
role = holo_user.label
|
||||||
has_application = locale("yes", "message", locale=msg.from_user) if holo_user.application_approved() is True else locale("no", "message", locale=msg.from_user)
|
has_application = (
|
||||||
has_sponsorship = locale("yes", "message", locale=msg.from_user) if holo_user.sponsorship_valid() is True else locale("no", "message", locale=msg.from_user)
|
locale("yes", "message", locale=msg.from_user)
|
||||||
|
if holo_user.application_approved() is True
|
||||||
|
else locale("no", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
has_sponsorship = (
|
||||||
|
locale("yes", "message", locale=msg.from_user)
|
||||||
|
if holo_user.sponsorship_valid() is True
|
||||||
|
else locale("no", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
|
||||||
username = holo_user.username if holo_user.username is not None else "N/A"
|
username = holo_user.username if holo_user.username is not None else "N/A"
|
||||||
in_chat = locale("yes", "message", locale=msg.from_user) if (holo_user.id in jsonLoad(path.join("cache", "group_members"))) else locale("no", "message", locale=msg.from_user)
|
in_chat = (
|
||||||
is_admin = locale("yes", "message", locale=msg.from_user) if (await isAnAdmin(holo_user.id)) else locale("no", "message", locale=msg.from_user)
|
locale("yes", "message", locale=msg.from_user)
|
||||||
|
if (holo_user.id in jsonLoad(path.join("cache", "group_members")))
|
||||||
|
else locale("no", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
is_admin = (
|
||||||
|
locale("yes", "message", locale=msg.from_user)
|
||||||
|
if (await isAnAdmin(holo_user.id))
|
||||||
|
else locale("no", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
|
||||||
output = locale("identify_success", "message", locale=msg.from_user).format(
|
output = locale("identify_success", "message", locale=msg.from_user).format(
|
||||||
holo_user.id,
|
holo_user.id,
|
||||||
@ -43,7 +84,7 @@ async def cmd_identify(app: Client, msg: Message):
|
|||||||
is_admin,
|
is_admin,
|
||||||
role,
|
role,
|
||||||
has_application,
|
has_application,
|
||||||
has_sponsorship
|
has_sponsorship,
|
||||||
)
|
)
|
||||||
|
|
||||||
user = await app.get_users(holo_user.id)
|
user = await app.get_users(holo_user.id)
|
||||||
@ -51,16 +92,14 @@ async def cmd_identify(app: Client, msg: Message):
|
|||||||
if user.photo is not None:
|
if user.photo is not None:
|
||||||
await app.send_chat_action(msg.chat.id, action=ChatAction.UPLOAD_PHOTO)
|
await app.send_chat_action(msg.chat.id, action=ChatAction.UPLOAD_PHOTO)
|
||||||
await msg.reply_photo(
|
await msg.reply_photo(
|
||||||
create_tmp(await download_tmp(app, user.photo.big_file_id), kind="image"),
|
create_tmp(
|
||||||
|
(await download_tmp(app, user.photo.big_file_id))[1], kind="image"
|
||||||
|
),
|
||||||
quote=should_quote(msg),
|
quote=should_quote(msg),
|
||||||
caption=output
|
caption=output,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await app.send_chat_action(msg.chat.id, action=ChatAction.TYPING)
|
await app.send_chat_action(msg.chat.id, action=ChatAction.TYPING)
|
||||||
await msg.reply_text(
|
await msg.reply_text(output, quote=should_quote(msg))
|
||||||
output,
|
|
||||||
quote=should_quote(msg)
|
|
||||||
)
|
|
||||||
|
|
||||||
logWrite(f"User {msg.from_user.id} identified user {holo_user.id}")
|
logWrite(f"User {msg.from_user.id} identified user {holo_user.id}")
|
||||||
# ==============================================================================================================================
|
|
30
modules/commands/issue.py
Normal file
30
modules/commands/issue.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from app import app
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from modules.utils import configGet, locale
|
||||||
|
from modules import custom_filters
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(["issue"], prefixes=["/"])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def cmd_issue(app: Client, msg: Message):
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("issue", "message", locale=msg.from_user),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("issue", "button", locale=msg.from_user),
|
||||||
|
url=configGet("issues"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
@ -7,10 +7,14 @@ from classes.errors.holo_user import LabelTooLongError, LabelSettingError
|
|||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Label command ================================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["label"], prefixes=["/"]) & custom_filters.admin)
|
|
||||||
async def cmd_label(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["label"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
|
async def cmd_label(app: Client, msg: Message):
|
||||||
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`")
|
||||||
return
|
return
|
||||||
@ -18,14 +22,15 @@ async def cmd_label(app: Client, msg: Message):
|
|||||||
target = await find_user(app, msg.command[1])
|
target = await find_user(app, msg.command[1])
|
||||||
|
|
||||||
if target is not None:
|
if target is not None:
|
||||||
|
|
||||||
target = HoloUser(target)
|
target = HoloUser(target)
|
||||||
|
|
||||||
label = " ".join(msg.command[2:])
|
label = " ".join(msg.command[2:])
|
||||||
|
|
||||||
if label.lower() == "reset":
|
if label.lower() == "reset":
|
||||||
await target.label_reset(msg.chat)
|
await target.label_reset(msg.chat)
|
||||||
await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
f"Resetting **{target.id}**'s label...", quote=should_quote(msg)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@ -34,10 +39,16 @@ async def cmd_label(app: Client, msg: Message):
|
|||||||
await msg.reply_text(locale("label_too_long", "message"))
|
await msg.reply_text(locale("label_too_long", "message"))
|
||||||
return
|
return
|
||||||
except LabelSettingError as exp:
|
except LabelSettingError as exp:
|
||||||
await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True)
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
exp.__str__(),
|
||||||
|
disable_notification=True,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
f"Setting **{target.id}**'s label to **{label}**...",
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(f"User not found")
|
await msg.reply_text(f"User not found")
|
||||||
# ==============================================================================================================================
|
|
@ -1,34 +1,97 @@
|
|||||||
from app import app
|
from app import app, isAnAdmin
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
|
from convopyro import listen_message
|
||||||
from classes.errors.holo_user import UserInvalidError
|
from classes.errors.holo_user import UserInvalidError
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import logWrite, locale, should_quote, find_user
|
from modules.utils import configGet, logWrite, locale, should_quote, find_user
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
from modules.database import col_messages
|
||||||
|
|
||||||
# Message command ==============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.command(["message"], prefixes=["/"]) & custom_filters.admin)
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["message"], prefixes=["/"])
|
||||||
|
# & custom_filters.admin
|
||||||
|
)
|
||||||
async def cmd_message(app: Client, msg: Message):
|
async def cmd_message(app: Client, msg: Message):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if await isAnAdmin(msg.from_user.id):
|
||||||
try:
|
try:
|
||||||
destination = HoloUser(int(msg.command[1]))
|
destination = HoloUser(int(msg.command[1]))
|
||||||
except (ValueError, UserInvalidError):
|
except (ValueError, UserInvalidError):
|
||||||
destination = HoloUser(await find_user(app, query=msg.command[1]))
|
destination = HoloUser(await find_user(app, query=msg.command[1]))
|
||||||
|
if (msg.text is not None) and (len(str(msg.text).split()) > 2):
|
||||||
if ((msg.text is not None) and (len(msg.text.split()) > 2)):
|
await destination.message(
|
||||||
await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True)
|
context=msg,
|
||||||
elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)):
|
text=" ".join(str(msg.text).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, voice=msg.voice, animation=msg.animation, adm_context=True)
|
caption=msg.caption,
|
||||||
|
photo=msg.photo,
|
||||||
|
video=msg.video,
|
||||||
|
file=msg.document,
|
||||||
|
voice=msg.voice,
|
||||||
|
animation=msg.animation,
|
||||||
|
adm_context=True,
|
||||||
|
)
|
||||||
|
elif (msg.caption is not None) and (len(msg.caption.split()) > 2):
|
||||||
|
await destination.message(
|
||||||
|
context=msg,
|
||||||
|
text=str(msg.text),
|
||||||
|
caption=" ".join(msg.caption.split()[2:]),
|
||||||
|
photo=msg.photo,
|
||||||
|
video=msg.video,
|
||||||
|
file=msg.document,
|
||||||
|
voice=msg.voice,
|
||||||
|
animation=msg.animation,
|
||||||
|
adm_context=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await destination.message(
|
||||||
|
context=msg,
|
||||||
|
text=None,
|
||||||
|
caption=None,
|
||||||
|
photo=msg.photo,
|
||||||
|
video=msg.video,
|
||||||
|
file=msg.document,
|
||||||
|
voice=msg.voice,
|
||||||
|
animation=msg.animation,
|
||||||
|
adm_context=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True)
|
await msg.reply_text(
|
||||||
|
locale("message_enter", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
message = await listen_message(app, msg.chat.id)
|
||||||
|
if (
|
||||||
|
message is None
|
||||||
|
or message.text is not None
|
||||||
|
and message.text == "/cancel"
|
||||||
|
):
|
||||||
|
return
|
||||||
|
sent = await app.forward_messages(
|
||||||
|
configGet("admin", "groups"), msg.chat.id, message.id
|
||||||
|
)
|
||||||
|
col_messages.insert_one(
|
||||||
|
{
|
||||||
|
"origin": {"chat": message.chat.id, "id": message.id},
|
||||||
|
"destination": {"chat": sent.chat.id, "id": sent.id},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await message.reply_text(
|
||||||
|
locale("message_sent", "message", locale=message.from_user), quote=True
|
||||||
|
)
|
||||||
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
await msg.reply_text(locale("message_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("message_invalid_syntax", "message", locale=msg.from_user),
|
||||||
|
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'")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await msg.reply_text(locale("message_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("message_invalid_syntax", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
logWrite(f"Admin {msg.from_user.id} tried to send message but 'ValueError'")
|
logWrite(f"Admin {msg.from_user.id} tried to send message but 'ValueError'")
|
||||||
# ==============================================================================================================================
|
|
@ -1,3 +1,4 @@
|
|||||||
|
from os import path
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
@ -6,53 +7,111 @@ from pyrogram.client import Client
|
|||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
from modules.logging import logWrite
|
from modules.logging import logWrite
|
||||||
from modules.utils import configGet, locale, should_quote, find_location
|
from modules.utils import configGet, jsonLoad, locale, should_quote, find_location
|
||||||
from modules.database import col_applications, col_users
|
from modules.database import col_applications, col_users
|
||||||
from classes.errors.geo import PlaceNotFoundError
|
from classes.errors.geo import PlaceNotFoundError
|
||||||
|
|
||||||
# Nearby command ===============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & (filters.private | (filters.chat(configGet("admin", "groups")) | filters.chat(configGet("users", "groups")))) & filters.command(["nearby"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin))
|
|
||||||
async def cmd_nearby(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& (
|
||||||
|
filters.private
|
||||||
|
| (
|
||||||
|
filters.chat(configGet("admin", "groups"))
|
||||||
|
| filters.chat(configGet("users", "groups"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
& filters.command(["nearby"], prefixes=["/"])
|
||||||
|
& (custom_filters.allowed | custom_filters.admin)
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def cmd_nearby(app: Client, msg: Message):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
# Check if any place provided
|
# Check if any place provided
|
||||||
if len(msg.command) == 1: # Action if no place provided
|
if len(msg.command) == 1: # Action if no place provided
|
||||||
application = col_applications.find_one({"user": msg.from_user.id})
|
application = col_applications.find_one({"user": msg.from_user.id})
|
||||||
if application is None:
|
if application is None:
|
||||||
await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user))
|
await msg.reply_text(
|
||||||
|
locale("nearby_user_empty", "message", locale=holo_user)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
location = application["application"]["3"]["location"][0], application["application"]["3"]["location"][1]
|
location = (
|
||||||
else: # Find a place from input query
|
application["application"]["3"]["location"][0],
|
||||||
|
application["application"]["3"]["location"][1],
|
||||||
|
)
|
||||||
|
else: # Find a place from input query
|
||||||
logWrite(f"Looking for the location by query '{' '.join(msg.command[1:])}'")
|
logWrite(f"Looking for the location by query '{' '.join(msg.command[1:])}'")
|
||||||
try:
|
try:
|
||||||
location_coordinates = find_location(" ".join(msg.command[1:]))
|
location_coordinates = find_location(" ".join(msg.command[1:]))
|
||||||
location = float(location_coordinates["lng"]), float(location_coordinates["lat"])
|
location = float(location_coordinates["lng"]), float(
|
||||||
except PlaceNotFoundError: # Place is not found
|
location_coordinates["lat"]
|
||||||
await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user), quote=should_quote(msg))
|
)
|
||||||
|
except PlaceNotFoundError: # Place is not found
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("nearby_invalid", "message", locale=holo_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
except Exception as exp: # Error occurred while finding the place
|
except Exception as exp: # Error occurred while finding the place
|
||||||
await msg.reply_text(locale("nearby_error", "message", locale=holo_user).format(exp, print_exc()), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("nearby_error", "message", locale=holo_user).format(
|
||||||
|
exp, print_exc()
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Find all users registered in the area provided
|
# Find all users registered in the area provided
|
||||||
output = []
|
output = []
|
||||||
applications_nearby = col_applications.find( {"application.3.location": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } )
|
applications_nearby = col_applications.find(
|
||||||
|
{
|
||||||
|
"application.3.location": {
|
||||||
|
"$nearSphere": {
|
||||||
|
"$geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [location[0], location[1]],
|
||||||
|
},
|
||||||
|
"$maxDistance": configGet("search_radius") * 1000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for entry in applications_nearby:
|
for entry in applications_nearby:
|
||||||
if not entry["user"] == msg.from_user.id:
|
if not entry["user"] == msg.from_user.id:
|
||||||
user = col_users.find_one( {"user": entry["user"]} )
|
user = col_users.find_one({"user": entry["user"]})
|
||||||
if user is not None:
|
if user is not None:
|
||||||
if user["tg_username"] not in [None, "None", ""]: # Check if user has any name
|
if entry["user"] in jsonLoad(
|
||||||
output.append(f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}')
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
else:
|
):
|
||||||
output.append(f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}')
|
if user["tg_username"] not in [
|
||||||
|
None,
|
||||||
|
"None",
|
||||||
|
"",
|
||||||
|
]: # Check if user has any name
|
||||||
|
output.append(
|
||||||
|
f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
output.append(
|
||||||
|
f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}'
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"{holo_user.id} tried to find someone nearby {location[1]} {location[0]} in the radius of {configGet('search_radius')} kilometers")
|
logWrite(
|
||||||
|
f"{holo_user.id} tried to find someone nearby {location[1]} {location[0]} in the radius of {configGet('search_radius')} kilometers"
|
||||||
|
)
|
||||||
|
|
||||||
# Check if any users found
|
# Check if any users found
|
||||||
if len(output) > 0:
|
if len(output) > 0:
|
||||||
await msg.reply_text(locale("nearby_result", "message", locale=holo_user).format("\n".join(output)), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("nearby_result", "message", locale=holo_user).format(
|
||||||
|
"\n".join(output)
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg)
|
||||||
|
)
|
||||||
|
@ -3,67 +3,167 @@ from pyrogram import filters
|
|||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
|
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
|
from modules.logging import logWrite
|
||||||
from modules.utils import configGet, locale, should_quote
|
from modules.utils import configGet, locale, should_quote
|
||||||
from modules.handlers.welcome import welcome_pass
|
from modules.handlers.welcome import welcome_pass
|
||||||
from modules.database import col_tmp
|
from modules.database import col_tmp, col_applications
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Reapply command ==============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"]))
|
|
||||||
async def cmd_reapply(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(["reapply"], prefixes=["/"])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def cmd_reapply(app: Client, msg: Message):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
# Check if user has approved/rejected tmp application
|
# Check if user has approved/rejected tmp application
|
||||||
if ((holo_user.application_state()[0] in ["approved", "rejected"]) or (holo_user.application_state()[0] == "none")) and holo_user.spoiler_state() is False:
|
if (
|
||||||
|
(holo_user.application_state()[0] in ["approved", "rejected"])
|
||||||
|
or (holo_user.application_state()[0] == "none")
|
||||||
|
) and holo_user.spoiler_state() is False:
|
||||||
# Check if user's tmp application is already completed or even sent
|
# Check if user's tmp application is already completed or even sent
|
||||||
if ((holo_user.application_state()[1] is True) and (not col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"])) or (holo_user.application_state()[0] == "none"):
|
if (
|
||||||
|
(holo_user.application_state()[1] is True)
|
||||||
|
and (
|
||||||
|
not col_tmp.find_one({"user": holo_user.id, "type": "application"})[
|
||||||
|
"sent"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
) or (holo_user.application_state()[0] == "none"):
|
||||||
left_chat = True
|
left_chat = True
|
||||||
|
|
||||||
async for member in app.get_chat_members(configGet("users", "groups")):
|
async for member in app.get_chat_members(configGet("users", "groups")):
|
||||||
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 left_chat is True:
|
||||||
|
if holo_user.application_state()[
|
||||||
|
1
|
||||||
|
] is True and holo_user.application_state()[0] not in [
|
||||||
|
"fill",
|
||||||
|
"rejected",
|
||||||
|
]:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("reapply_left_chat", "message", locale=holo_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"reapply_old_one",
|
||||||
|
"button",
|
||||||
|
locale=holo_user,
|
||||||
|
),
|
||||||
|
f"reapply_old_{msg.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"reapply_new_one",
|
||||||
|
"button",
|
||||||
|
locale=holo_user,
|
||||||
|
),
|
||||||
|
f"reapply_new_{msg.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
elif (
|
||||||
|
col_tmp.find_one({"user": holo_user.id, "type": "application"})
|
||||||
|
is None
|
||||||
|
and col_applications.find_one({"user": holo_user.id}) is not None
|
||||||
|
):
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("reapply_left_chat", "message", locale=holo_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"reapply_old_one",
|
||||||
|
"button",
|
||||||
|
locale=holo_user,
|
||||||
|
),
|
||||||
|
f"reapply_old_{msg.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"reapply_new_one",
|
||||||
|
"button",
|
||||||
|
locale=holo_user,
|
||||||
|
),
|
||||||
|
f"reapply_new_{msg.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
holo_user.application_restart(reapply=True)
|
||||||
|
await welcome_pass(app, msg, once_again=True)
|
||||||
|
|
||||||
|
else:
|
||||||
if holo_user.sponsorship_state()[0] == "fill":
|
if holo_user.sponsorship_state()[0] == "fill":
|
||||||
await msg.reply_text(locale("finish_sponsorship", "message"), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("finish_sponsorship", "message"), quote=should_quote(msg)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
holo_user.application_restart(reapply=True)
|
holo_user.application_restart(reapply=True)
|
||||||
await welcome_pass(app, msg, once_again=True)
|
await welcome_pass(app, msg, once_again=True)
|
||||||
|
|
||||||
else:
|
|
||||||
await msg.reply_text(locale("reapply_left_chat", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup([
|
|
||||||
[
|
|
||||||
InlineKeyboardButton(locale("reapply_old_one", "button", locale=holo_user), f"reapply_old_{msg.id}")
|
|
||||||
],
|
|
||||||
[
|
|
||||||
InlineKeyboardButton(locale("reapply_new_one", "button", locale=holo_user), f"reapply_new_{msg.id}")
|
|
||||||
]
|
|
||||||
]))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
await msg.reply_text(
|
||||||
await msg.reply_text(locale("reapply_in_progress", "message", locale=holo_user).format(locale("confirm", "keyboard", locale=holo_user)[1][0]), reply_markup=InlineKeyboardMarkup([
|
locale("reapply_in_progress", "message", locale=holo_user).format(
|
||||||
[
|
locale("confirm", "keyboard", locale=holo_user)[1][0]
|
||||||
InlineKeyboardButton(locale("applying_stop", "button", locale=holo_user), f"reapply_stop_{msg.id}")
|
),
|
||||||
]
|
reply_markup=InlineKeyboardMarkup(
|
||||||
]))
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("applying_stop", "button", locale=holo_user),
|
||||||
|
f"reapply_stop_{msg.id}",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif holo_user.spoiler_state() is True:
|
elif holo_user.spoiler_state() is True:
|
||||||
|
|
||||||
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
|
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
if (holo_user.application_state()[0] == "fill") and (
|
||||||
if (holo_user.application_state()[0] == "fill") and (col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"] is True):
|
col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"]
|
||||||
await msg.reply_text(locale("reapply_forbidden", "message", locale=holo_user))
|
is True
|
||||||
|
):
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("reapply_forbidden", "message", locale=holo_user)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("reapply_in_progress", "message", locale=holo_user).format(locale("confirm", "keyboard", locale=holo_user)[1][0]), reply_markup=InlineKeyboardMarkup([
|
await msg.reply_text(
|
||||||
[
|
locale("reapply_in_progress", "message", locale=holo_user).format(
|
||||||
InlineKeyboardButton(locale("applying_stop", "button", locale=holo_user), f"reapply_stop_{msg.id}")
|
locale("confirm", "keyboard", locale=holo_user)[1][0]
|
||||||
]
|
),
|
||||||
]))
|
reply_markup=InlineKeyboardMarkup(
|
||||||
# ==============================================================================================================================
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("applying_stop", "button", locale=holo_user),
|
||||||
|
f"reapply_stop_{msg.id}",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -11,14 +11,24 @@ from modules import custom_filters
|
|||||||
|
|
||||||
pid = getpid()
|
pid = getpid()
|
||||||
|
|
||||||
# Reboot command ===============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"]) & custom_filters.admin)
|
|
||||||
async def cmd_kill(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(["kill", "die", "reboot"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
|
async def cmd_kill(app: Client, msg: Message):
|
||||||
logWrite(f"Shutting down bot with pid {pid}")
|
logWrite(f"Shutting down bot with pid {pid}")
|
||||||
await msg.reply_text(locale("shutdown", "message", locale=msg.from_user).format(pid), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("shutdown", "message", locale=msg.from_user).format(pid),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
scheduler.shutdown()
|
scheduler.shutdown()
|
||||||
makedirs(configGet("cache", "locations"), exist_ok=True)
|
makedirs(configGet("cache", "locations"), exist_ok=True)
|
||||||
jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time"))
|
jsonSave(
|
||||||
|
{"timestamp": time()},
|
||||||
|
path.join(configGet("cache", "locations"), "shutdown_time"),
|
||||||
|
)
|
||||||
exit()
|
exit()
|
||||||
# ==============================================================================================================================
|
|
@ -9,12 +9,16 @@ from modules import custom_filters
|
|||||||
|
|
||||||
pid = getpid()
|
pid = getpid()
|
||||||
|
|
||||||
# Reset commands command =======================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["resetcommands"], prefixes=["/"]) & custom_filters.admin)
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(["resetcommands"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
async def cmd_resetcommands(app: Client, msg: Message):
|
async def cmd_resetcommands(app: Client, msg: Message):
|
||||||
|
|
||||||
if msg.from_user.id == configGet("owner"):
|
if msg.from_user.id == configGet("owner"):
|
||||||
|
|
||||||
logWrite(f"Resetting all commands on owner's request")
|
logWrite(f"Resetting all commands on owner's request")
|
||||||
|
|
||||||
valid_locales = []
|
valid_locales = []
|
||||||
@ -24,42 +28,84 @@ async def cmd_resetcommands(app: Client, msg: Message):
|
|||||||
if entry.endswith(".json"):
|
if entry.endswith(".json"):
|
||||||
valid_locales.append(".".join(entry.split(".")[:-1]))
|
valid_locales.append(".".join(entry.split(".")[:-1]))
|
||||||
|
|
||||||
if configGet("debug") is True:
|
logWrite(
|
||||||
logWrite(f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")}')
|
f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")}',
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")))
|
debug=True,
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("users", "groups")))
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("admin", "groups"))
|
||||||
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("users", "groups"))
|
||||||
|
)
|
||||||
|
for lc in valid_locales:
|
||||||
|
try:
|
||||||
|
logWrite(
|
||||||
|
f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")} [{lc}]',
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")),
|
||||||
|
language_code=lc,
|
||||||
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("users", "groups")),
|
||||||
|
language_code=lc,
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
for admin in configGet("admins"):
|
for admin in configGet("admins"):
|
||||||
try:
|
try:
|
||||||
if configGet("debug") is True:
|
logWrite(f"Resetting commands for admin {admin}", debug=True)
|
||||||
logWrite(f'Resetting commands for admin {admin}')
|
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin))
|
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin))
|
||||||
|
for lc in valid_locales:
|
||||||
|
try:
|
||||||
|
logWrite(
|
||||||
|
f"Resetting commands for admin {admin} [{lc}]", debug=True
|
||||||
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=admin), language_code=lc
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if configGet("debug") is True:
|
logWrite(f'Resetting commands for owner {configGet("owner")}', debug=True)
|
||||||
logWrite(f'Resetting commands for owner {configGet("owner")}')
|
|
||||||
for lc in valid_locales:
|
for lc in valid_locales:
|
||||||
if configGet("debug") is True:
|
logWrite(
|
||||||
logWrite(f'Resetting commands for owner {configGet("owner")} [{lc}]')
|
f'Resetting commands for owner {configGet("owner")} [{lc}]',
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner")), language_code=lc)
|
debug=True,
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner")))
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("owner")),
|
||||||
|
language_code=lc,
|
||||||
|
)
|
||||||
|
await app.delete_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("owner"))
|
||||||
|
)
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for lc in valid_locales:
|
for lc in valid_locales:
|
||||||
if configGet("debug") is True:
|
logWrite(f"Resetting commands for locale {lc}", debug=True)
|
||||||
logWrite(f'Resetting commands for locale {lc}')
|
await app.delete_bot_commands(
|
||||||
await app.delete_bot_commands(scope=BotCommandScopeDefault(), language_code=lc)
|
scope=BotCommandScopeDefault(), language_code=lc
|
||||||
|
)
|
||||||
|
|
||||||
if configGet("debug") is True:
|
logWrite(f"Resetting default commands", debug=True)
|
||||||
logWrite(f'Resetting default commands')
|
|
||||||
await app.delete_bot_commands()
|
await app.delete_bot_commands()
|
||||||
|
|
||||||
await msg.reply_text("OK", quote=should_quote(msg))
|
await msg.reply_text("OK", quote=should_quote(msg))
|
||||||
|
|
||||||
if configGet("debug") is True:
|
logWrite(str(await app.get_bot_commands()), debug=True)
|
||||||
logWrite(str(await app.get_bot_commands()))
|
logWrite(
|
||||||
logWrite(str(await app.get_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner")))))
|
str(
|
||||||
# ==============================================================================================================================
|
await app.get_bot_commands(
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("owner"))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
@ -7,36 +7,51 @@ from modules.utils import locale
|
|||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
|
|
||||||
|
|
||||||
class DefaultRulesMarkup(list):
|
class DefaultRulesMarkup(list):
|
||||||
def __init__(self, language_code: Union[str, HoloUser, User, None]):
|
def __init__(self, language_code: Union[str, HoloUser, User, None]):
|
||||||
super().__init__([])
|
super().__init__([])
|
||||||
self.keyboard = InlineKeyboardMarkup(
|
self.keyboard = InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(locale("rules_home", "button", locale=language_code), callback_data="rules_home"),
|
InlineKeyboardButton(
|
||||||
InlineKeyboardButton(locale("rules_additional", "button", locale=language_code), callback_data="rules_additional")
|
locale("rules_home", "button", locale=language_code),
|
||||||
|
callback_data="rules_home",
|
||||||
|
),
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale("rules_additional", "button", locale=language_code),
|
||||||
|
callback_data="rules_additional",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton("1", callback_data="rule_1"),
|
InlineKeyboardButton("1", callback_data="rule_1"),
|
||||||
InlineKeyboardButton("2", callback_data="rule_2"),
|
InlineKeyboardButton("2", callback_data="rule_2"),
|
||||||
InlineKeyboardButton("3", callback_data="rule_3")
|
InlineKeyboardButton("3", callback_data="rule_3"),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton("4", callback_data="rule_4"),
|
InlineKeyboardButton("4", callback_data="rule_4"),
|
||||||
InlineKeyboardButton("5", callback_data="rule_5"),
|
InlineKeyboardButton("5", callback_data="rule_5"),
|
||||||
InlineKeyboardButton("6", callback_data="rule_6")
|
InlineKeyboardButton("6", callback_data="rule_6"),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton("7", callback_data="rule_7"),
|
InlineKeyboardButton("7", callback_data="rule_7"),
|
||||||
InlineKeyboardButton("8", callback_data="rule_8"),
|
InlineKeyboardButton("8", callback_data="rule_8"),
|
||||||
InlineKeyboardButton("9", callback_data="rule_9")
|
InlineKeyboardButton("9", callback_data="rule_9"),
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Rules command =============================================================================================================
|
@app.on_message(
|
||||||
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["rules"], prefixes=["/"]))
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& ~custom_filters.banned
|
||||||
|
& filters.command(["rules"], prefixes=["/"])
|
||||||
|
)
|
||||||
async def cmd_rules(app: Client, msg: Message):
|
async def cmd_rules(app: Client, msg: Message):
|
||||||
await msg.reply_text(locale("rules_msg", locale=msg.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(msg.from_user).keyboard)
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("rules_msg", locale=msg.from_user),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=DefaultRulesMarkup(msg.from_user).keyboard,
|
||||||
|
)
|
||||||
|
@ -6,40 +6,59 @@ from classes.errors.holo_user import UserNotFoundError, UserInvalidError
|
|||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.logging import logWrite
|
from modules.logging import logWrite
|
||||||
from modules.utils import locale
|
from modules.utils import locale
|
||||||
from modules.database import col_spoilers
|
from modules.database import col_spoilers, col_applications
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Spoiler command ==============================================================================================================
|
|
||||||
@app.on_message(custom_filters.member & ~filters.scheduled & filters.private & filters.command(["spoiler"], prefixes=["/"]))
|
|
||||||
async def cmd_spoiler(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_spoilers
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& ~custom_filters.banned
|
||||||
|
& filters.command(["spoiler"], prefixes=["/"])
|
||||||
|
)
|
||||||
|
async def cmd_spoiler(app: Client, msg: Message):
|
||||||
try:
|
try:
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
except (UserInvalidError, UserNotFoundError):
|
except (UserInvalidError, UserNotFoundError):
|
||||||
return
|
return
|
||||||
|
|
||||||
if holo_user.application_state()[0] != "fill" and holo_user.sponsorship_state()[0] != "fill":
|
if col_applications.find_one({"user": holo_user.id}) is None:
|
||||||
|
await msg.reply_text(locale("not_member", "message", locale=msg.from_user))
|
||||||
if col_spoilers.find_one( {"user": msg.from_user.id, "completed": False} ) is None:
|
return
|
||||||
|
|
||||||
|
if (
|
||||||
|
holo_user.application_state()[0] != "fill"
|
||||||
|
and holo_user.sponsorship_state()[0] != "fill"
|
||||||
|
):
|
||||||
|
if col_spoilers.find_one({"user": holo_user.id, "completed": False}) is None:
|
||||||
col_spoilers.insert_one(
|
col_spoilers.insert_one(
|
||||||
{
|
{
|
||||||
"user": msg.from_user.id,
|
"user": holo_user.id,
|
||||||
"completed": False,
|
"completed": False,
|
||||||
"category": None,
|
"category": None,
|
||||||
"description": None,
|
"description": None,
|
||||||
"photo": None,
|
"photo": None,
|
||||||
"video": None,
|
"video": None,
|
||||||
|
"audio": None,
|
||||||
"animation": None,
|
"animation": None,
|
||||||
"document": None,
|
"document": None,
|
||||||
"caption": None,
|
"caption": None,
|
||||||
"text": None
|
"text": None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await msg.reply_text(locale("spoiler_started", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_categories", "keyboard"), resize_keyboard=True, one_time_keyboard=True))
|
await msg.reply_text(
|
||||||
|
locale("spoiler_started", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("spoiler_categories", "keyboard"),
|
||||||
|
resize_keyboard=True,
|
||||||
|
one_time_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
logWrite(f"User {msg.from_user.id} started creating new spoiler")
|
logWrite(f"User {msg.from_user.id} started creating new spoiler")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("spoiler_unfinished", "message", locale=msg.from_user))
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("spoiler_unfinished", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
@ -1,23 +1,325 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Union
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
|
from pyrogram.types import (
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ReplyKeyboardMarkup,
|
||||||
|
ReplyKeyboardRemove,
|
||||||
|
ForceReply,
|
||||||
|
Message,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
from modules.utils import locale, should_quote
|
from modules.handlers.confirmation import confirm_yes
|
||||||
from modules.database import col_applications
|
from modules.utils import all_locales, locale, should_quote
|
||||||
|
from modules.database import col_sponsorships, col_tmp
|
||||||
|
from convopyro import listen_message
|
||||||
|
|
||||||
# Sponsorship command ==========================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_sponsorships & ~filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin))
|
def is_none_or_cancel(message: Union[Message, None]) -> bool:
|
||||||
|
if (
|
||||||
|
message is None
|
||||||
|
or message.text is not None
|
||||||
|
and message.text.lower() == "/cancel"
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_sponsorships
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["sponsorship"], prefixes=["/"])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
& (custom_filters.allowed | custom_filters.admin)
|
||||||
|
)
|
||||||
async def cmd_sponsorship(app: Client, msg: Message):
|
async def cmd_sponsorship(app: Client, msg: Message):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
if holo_user.application_state()[0] == "fill":
|
if holo_user.application_state()[0] == "fill":
|
||||||
await msg.reply_text(locale("finish_application", "message", locale=msg.from_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("finish_application", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
if holo_user.spoiler_state() is True:
|
if holo_user.spoiler_state() is True:
|
||||||
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
|
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
|
||||||
return
|
return
|
||||||
await msg.reply_text(locale("sponsorship_apply", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button", locale=msg.from_user)), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg))
|
|
||||||
|
existent = col_sponsorships.find_one(
|
||||||
|
{
|
||||||
|
"user": msg.from_user.id,
|
||||||
|
"sponsorship.expires": {"$gt": datetime.now() - timedelta(days=90)},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if existent is None:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsorship_apply", "message", locale=msg.from_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(
|
||||||
|
locale("sponsor_apply", "button", locale=msg.from_user)
|
||||||
|
),
|
||||||
|
callback_data=f"sponsor_apply_{msg.from_user.id}",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsor_resubmit", "message", locale=msg.from_user).format(
|
||||||
|
existent["sponsorship"]["streamer"]
|
||||||
|
),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("sponsorship_restore", "keyboard", locale=msg.from_user),
|
||||||
|
resize_keyboard=True,
|
||||||
|
one_time_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
answer_decision = await listen_message(app, msg.chat.id)
|
||||||
|
|
||||||
|
if is_none_or_cancel(answer_decision):
|
||||||
|
return
|
||||||
|
|
||||||
|
input_streamer = existent["sponsorship"]["streamer"]
|
||||||
|
|
||||||
|
values_keep = []
|
||||||
|
for pattern in all_locales("sponsorship_restore", "keyboard"):
|
||||||
|
values_keep.append(pattern[0][0].lower())
|
||||||
|
|
||||||
|
values_new = []
|
||||||
|
for pattern in all_locales("sponsorship_restore", "keyboard"):
|
||||||
|
values_new.append(pattern[1][0].lower())
|
||||||
|
|
||||||
|
if answer_decision.text.lower() in values_keep:
|
||||||
|
await answer_decision.reply_text(
|
||||||
|
locale("sponsor2", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor2",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
answer_date = await listen_message(app, msg.chat.id)
|
||||||
|
|
||||||
|
if is_none_or_cancel(answer_date):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
input_dt = datetime.strptime(answer_date.text, "%d.%m.%Y")
|
||||||
|
if datetime.now() >= input_dt:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsor2_past", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale("sponsor2", "force_reply", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
await answer_date.reply_text(
|
||||||
|
locale(f"sponsor2_invalid", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor2",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
await answer_date.reply_text(
|
||||||
|
locale("sponsor3", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor3",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
answer_proof = await listen_message(app, msg.chat.id)
|
||||||
|
|
||||||
|
if is_none_or_cancel(answer_proof):
|
||||||
|
return
|
||||||
|
|
||||||
|
if answer_proof.photo is None:
|
||||||
|
await answer_proof.reply_text(
|
||||||
|
locale("sponsor3", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor3",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
input_proof = answer_proof.photo.file_id
|
||||||
|
break
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsor4_resubmit", "message", locale=msg.from_user).format(
|
||||||
|
existent["sponsorship"]["label"]
|
||||||
|
),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("sponsorship_restore_label", "keyboard", locale=msg.from_user),
|
||||||
|
resize_keyboard=True,
|
||||||
|
one_time_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
answer_label_decision = await listen_message(app, msg.chat.id)
|
||||||
|
|
||||||
|
if is_none_or_cancel(answer_label_decision):
|
||||||
|
return
|
||||||
|
|
||||||
|
if answer_label_decision.text is None:
|
||||||
|
await answer_label_decision.reply_text(
|
||||||
|
"Please, choose a valid option.",
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale(
|
||||||
|
"sponsorship_restore_label",
|
||||||
|
"keyboard",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
resize_keyboard=True,
|
||||||
|
one_time_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
values_keep = []
|
||||||
|
for pattern in all_locales("sponsorship_restore_label", "keyboard"):
|
||||||
|
values_keep.append(pattern[0][0].lower())
|
||||||
|
|
||||||
|
values_new = []
|
||||||
|
for pattern in all_locales("sponsorship_restore_label", "keyboard"):
|
||||||
|
values_new.append(pattern[1][0].lower())
|
||||||
|
|
||||||
|
if answer_label_decision.text.lower() in values_keep:
|
||||||
|
input_label = existent["sponsorship"]["label"]
|
||||||
|
elif answer_label_decision.text.lower() in values_new:
|
||||||
|
await answer_label_decision.reply_text(
|
||||||
|
locale("sponsor4", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor4",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
answer_label = await listen_message(app, msg.chat.id)
|
||||||
|
|
||||||
|
if is_none_or_cancel(answer_label_decision):
|
||||||
|
return
|
||||||
|
|
||||||
|
if answer_label.text is None:
|
||||||
|
await answer_label.reply_text(
|
||||||
|
locale("label_too_long", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor4",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
elif len(answer_label.text) > 16:
|
||||||
|
await answer_label.reply_text(
|
||||||
|
locale("label_too_long", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(
|
||||||
|
f"sponsor4",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
input_label = answer_label.text
|
||||||
|
break
|
||||||
|
|
||||||
|
col_tmp.find_one_and_delete(
|
||||||
|
{"user": msg.from_user.id, "type": "sponsorship"}
|
||||||
|
)
|
||||||
|
|
||||||
|
col_tmp.insert_one(
|
||||||
|
{
|
||||||
|
"user": msg.from_user.id,
|
||||||
|
"type": "sponsorship",
|
||||||
|
"complete": True,
|
||||||
|
"sent": False,
|
||||||
|
"state": "fill",
|
||||||
|
"stage": 4,
|
||||||
|
"sponsorship": {
|
||||||
|
"streamer": input_streamer,
|
||||||
|
"expires": input_dt,
|
||||||
|
"proof": input_proof,
|
||||||
|
"label": input_label,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await confirm_yes(app, msg, kind="sponsorship")
|
||||||
|
return
|
||||||
|
|
||||||
|
elif answer_decision.text.lower() in values_new:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("sponsorship_apply", "message", locale=msg.from_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=str(
|
||||||
|
locale("sponsor_apply", "button", locale=msg.from_user)
|
||||||
|
),
|
||||||
|
callback_data=f"sponsor_apply_{msg.from_user.id}",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
await answer_decision.reply_text(
|
||||||
|
locale("sponsor_resubmit_invalid_option", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
return
|
||||||
# else:
|
# else:
|
||||||
# await msg.reply_text(locale("sponsorship_application_empty", "message"))
|
# await msg.reply_text(locale("sponsorship_application_empty", "message"))
|
||||||
# ==============================================================================================================================
|
|
@ -8,40 +8,63 @@ from modules import custom_filters
|
|||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
from bson.errors import InvalidId
|
from bson.errors import InvalidId
|
||||||
|
|
||||||
# Start command ================================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"]))
|
|
||||||
async def cmd_start(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(["start"], prefixes=["/"])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def cmd_start(app: Client, msg: Message):
|
||||||
user = col_users.find_one({"user": msg.from_user.id})
|
user = col_users.find_one({"user": msg.from_user.id})
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
|
col_users.insert_one(
|
||||||
col_users.insert_one({
|
{
|
||||||
"user": msg.from_user.id,
|
"user": msg.from_user.id,
|
||||||
"link": None,
|
"link": None,
|
||||||
"label": "",
|
"label": "",
|
||||||
"tg_name": msg.from_user.first_name,
|
"tg_name": msg.from_user.first_name,
|
||||||
"tg_phone": msg.from_user.phone_number,
|
"tg_phone": msg.from_user.phone_number,
|
||||||
"tg_locale": msg.from_user.language_code,
|
"tg_locale": msg.from_user.language_code,
|
||||||
"tg_username": msg.from_user.username
|
"tg_username": msg.from_user.username,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"User {msg.from_user.id} started bot interaction")
|
logWrite(f"User {msg.from_user.id} started bot interaction")
|
||||||
await msg.reply_text(locale("start", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("welcome", "keyboard", locale=msg.from_user), resize_keyboard=True))
|
await msg.reply_text(
|
||||||
|
locale("start", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("welcome", "keyboard", locale=msg.from_user),
|
||||||
|
resize_keyboard=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if len(msg.command) > 1:
|
if len(msg.command) > 1:
|
||||||
try:
|
try:
|
||||||
spoiler = col_spoilers.find_one( {"_id": ObjectId(msg.command[1])} )
|
spoiler = col_spoilers.find_one({"_id": ObjectId(msg.command[1])})
|
||||||
if spoiler["photo"] is not None:
|
if spoiler["photo"] is not None:
|
||||||
await msg.reply_document(spoiler["photo"], caption=spoiler["caption"])
|
await msg.reply_cached_media(
|
||||||
|
spoiler["photo"], caption=spoiler["caption"]
|
||||||
|
)
|
||||||
if spoiler["video"] is not None:
|
if spoiler["video"] is not None:
|
||||||
await msg.reply_cached_media(spoiler["video"], caption=spoiler["caption"])
|
await msg.reply_cached_media(
|
||||||
|
spoiler["video"], caption=spoiler["caption"]
|
||||||
|
)
|
||||||
|
if spoiler["audio"] is not None:
|
||||||
|
await msg.reply_cached_media(
|
||||||
|
spoiler["audio"], caption=spoiler["caption"]
|
||||||
|
)
|
||||||
if spoiler["animation"] is not None:
|
if spoiler["animation"] is not None:
|
||||||
await msg.reply_cached_media(spoiler["animation"], caption=spoiler["caption"])
|
await msg.reply_cached_media(
|
||||||
|
spoiler["animation"], caption=spoiler["caption"]
|
||||||
|
)
|
||||||
if spoiler["document"] is not None:
|
if spoiler["document"] is not None:
|
||||||
await msg.reply_document(spoiler["document"], caption=spoiler["caption"])
|
await msg.reply_cached_media(
|
||||||
|
spoiler["document"], caption=spoiler["caption"]
|
||||||
|
)
|
||||||
if spoiler["text"] is not None:
|
if spoiler["text"] is not None:
|
||||||
await msg.reply_text(spoiler["text"])
|
await msg.reply_text(spoiler["text"])
|
||||||
except InvalidId:
|
except InvalidId:
|
||||||
await msg.reply_text(f"Got an invalid ID {msg.command[1]}")
|
await msg.reply_text(f"Got an invalid ID {msg.command[1]}")
|
||||||
# ==============================================================================================================================
|
|
@ -7,16 +7,39 @@ from modules.utils import configGet, locale
|
|||||||
from modules.database import col_warnings
|
from modules.database import col_warnings
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Warn command =================================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_warnings & ~filters.scheduled & filters.command(["warn"], prefixes=["/"]) & custom_filters.admin)
|
|
||||||
async def cmd_warn(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_warnings
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["warn"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
|
async def cmd_warn(app: Client, msg: Message):
|
||||||
if msg.chat.id == configGet("users", "groups"):
|
if msg.chat.id == configGet("users", "groups"):
|
||||||
if msg.reply_to_message_id != None:
|
if msg.reply_to_message_id != None:
|
||||||
message = " ".join(msg.command[1:]) if len(msg.command) > 1 else ""
|
message = " ".join(msg.command[1:]) if len(msg.command) > 1 else ""
|
||||||
col_warnings.insert_one({"user": msg.reply_to_message.from_user.id, "admin": msg.from_user.id, "date": datetime.now(), "reason": message})
|
col_warnings.insert_one(
|
||||||
|
{
|
||||||
|
"user": msg.reply_to_message.from_user.id,
|
||||||
|
"admin": msg.from_user.id,
|
||||||
|
"date": datetime.now(),
|
||||||
|
"reason": message,
|
||||||
|
"active": True,
|
||||||
|
"revoke_date": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
if message == "":
|
if message == "":
|
||||||
await msg.reply_text(locale("warned", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id))
|
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:
|
||||||
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))
|
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,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -1,18 +1,62 @@
|
|||||||
|
from os import path
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram.enums.chat_members_filter import ChatMembersFilter
|
from pyrogram.enums.chat_members_filter import ChatMembersFilter
|
||||||
from modules.utils import configGet, locale, should_quote
|
from modules.utils import configGet, jsonLoad, locale, should_quote
|
||||||
from modules.database import col_users, col_warnings
|
from modules.database import col_users, col_warnings
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
from pykeyboard import InlineKeyboard, InlineButton
|
||||||
|
|
||||||
# Warnings command =============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_warnings & ~filters.scheduled & filters.command(["warnings"], prefixes=["/"]) & custom_filters.admin)
|
@app.on_message(
|
||||||
|
custom_filters.enabled_warnings
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.command(["warnings"], prefixes=["/"])
|
||||||
|
& custom_filters.admin
|
||||||
|
)
|
||||||
async def cmd_warnings(app: Client, msg: Message):
|
async def cmd_warnings(app: Client, msg: Message):
|
||||||
|
if len(msg.command) == 1:
|
||||||
|
warnings = {}
|
||||||
|
warnings_output = []
|
||||||
|
group_members = jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
)
|
||||||
|
for warning in col_warnings.find({"active": True}):
|
||||||
|
if warning["user"] not in group_members:
|
||||||
|
continue
|
||||||
|
if str(warning["user"]) not in warnings:
|
||||||
|
warnings[str(warning["user"])] = {
|
||||||
|
"name": (col_users.find_one({"user": warning["user"]}))["tg_name"],
|
||||||
|
"warns": 1,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
warnings[str(warning["user"])]["warns"] += 1
|
||||||
|
for warning in warnings:
|
||||||
|
warnings_output.append(
|
||||||
|
locale("warnings_entry", "message", locale=msg.from_user).format(
|
||||||
|
warnings[warning]["name"], warning, warnings[warning]["warns"]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
warnings_output = (
|
||||||
|
locale("warnings_empty", "message", locale=msg.from_user)
|
||||||
|
if len(warnings_output) == 0
|
||||||
|
else "\n".join(warnings_output)
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("warnings_all", "message", locale=msg.from_user).format(
|
||||||
|
warnings_output
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if len(msg.command) <= 1:
|
if len(msg.command) > 3:
|
||||||
await msg.reply_text(locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("syntax_warnings", "message", locale=msg.from_user),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -21,24 +65,82 @@ async def cmd_warnings(app: Client, msg: Message):
|
|||||||
target_name = user_db["tg_name"]
|
target_name = user_db["tg_name"]
|
||||||
except:
|
except:
|
||||||
list_of_users = []
|
list_of_users = []
|
||||||
async for m in app.get_chat_members(configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
|
async for m in app.get_chat_members(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
filter=ChatMembersFilter.SEARCH,
|
||||||
|
query=msg.command[1],
|
||||||
|
):
|
||||||
list_of_users.append(m)
|
list_of_users.append(m)
|
||||||
|
|
||||||
if len(list_of_users) != 0:
|
if len(list_of_users) != 0:
|
||||||
target = list_of_users[0].user
|
target = list_of_users[0].user
|
||||||
target_name = target.first_name
|
target_name = target.first_name
|
||||||
target_id = str(target.id)
|
target_id = target.id
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("no_user_warnings", "message", locale=msg.from_user).format(msg.command[1]))
|
await msg.reply_text(
|
||||||
|
locale("no_user_warnings", "message", locale=msg.from_user).format(
|
||||||
|
msg.command[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
warns = len(list(col_warnings.find({"user": target_id})))
|
if len(msg.command) == 3 and msg.command[2].lower() == "revoke":
|
||||||
|
if col_warnings.count_documents({"user": target_id, "active": True}) == 0:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("no_warnings", "message", locale=msg.from_user).format(
|
||||||
|
target_name, target_id
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
keyboard = InlineKeyboard()
|
||||||
|
buttons = []
|
||||||
|
warnings = []
|
||||||
|
for index, warning in enumerate(
|
||||||
|
list(col_warnings.find({"user": target_id, "active": True}))
|
||||||
|
):
|
||||||
|
warnings.append(
|
||||||
|
f'{index+1}. {warning["date"].strftime("%d.%m.%Y, %H:%M")}\n Адмін: {warning["admin"]}\n Причина: {warning["reason"]}'
|
||||||
|
)
|
||||||
|
buttons.append(InlineButton(str(index + 1), f'w_rev_{str(warning["_id"])}'))
|
||||||
|
keyboard.add(*buttons)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("warnings_revoke", "message", locale=msg.from_user).format(
|
||||||
|
target_name, "\n".join(warnings)
|
||||||
|
),
|
||||||
|
reply_markup=keyboard,
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
warns = col_warnings.count_documents({"user": target_id, "active": True})
|
||||||
|
|
||||||
if warns == 0:
|
if warns == 0:
|
||||||
await msg.reply_text(locale("no_warnings", "message", locale=msg.from_user).format(target_name, target_id), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("no_warnings", "message", locale=msg.from_user).format(
|
||||||
|
target_name, target_id
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
|
warnings = []
|
||||||
|
for index, warning in enumerate(
|
||||||
|
list(col_warnings.find({"user": target_id, "active": True}))
|
||||||
|
):
|
||||||
|
warnings.append(
|
||||||
|
f'{index+1}. {warning["date"].strftime("%d.%m.%Y, %H:%M")}\n Адмін: {warning["admin"]}\n Причина: {warning["reason"]}'
|
||||||
|
)
|
||||||
if warns <= 5:
|
if warns <= 5:
|
||||||
await msg.reply_text(locale("warnings_1", "message", locale=msg.from_user).format(target_name, target_id, warns), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
|
locale("warnings_1", "message", locale=msg.from_user).format(
|
||||||
|
target_name, target_id, warns, "\n".join(warnings), target_id
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("warnings_2", "message", locale=msg.from_user).format(target_name, target_id, warns), quote=should_quote(msg))
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("warnings_2", "message", locale=msg.from_user).format(
|
||||||
|
target_name, target_id, warns, "\n".join(warnings), target_id
|
||||||
|
),
|
||||||
|
quote=should_quote(msg),
|
||||||
|
)
|
||||||
|
@ -4,49 +4,94 @@ usage in context of Holo Users."""
|
|||||||
from os import path
|
from os import path
|
||||||
from app import isAnAdmin
|
from app import isAnAdmin
|
||||||
from modules.utils import configGet, jsonLoad
|
from modules.utils import configGet, jsonLoad
|
||||||
from modules.database import col_applications, col_tmp
|
from modules.database import col_applications, col_tmp, col_bans
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
|
||||||
async def admin_func(_, __, msg: Message):
|
async def admin_func(_, __, msg: Message):
|
||||||
return await isAnAdmin(msg.from_user.id)
|
return await isAnAdmin(msg.from_user.id)
|
||||||
|
|
||||||
|
|
||||||
async def member_func(_, __, msg: Message):
|
async def member_func(_, __, msg: Message):
|
||||||
return True if (msg.from_user.id in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))) else False
|
return (
|
||||||
|
True
|
||||||
|
if (
|
||||||
|
msg.from_user.id
|
||||||
|
in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))
|
||||||
|
)
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def allowed_func(_, __, msg: Message):
|
async def allowed_func(_, __, msg: Message):
|
||||||
return True if (col_applications.find_one({"user": msg.from_user.id}) is not None) else False
|
output = False
|
||||||
|
output = (
|
||||||
|
True
|
||||||
|
if (col_applications.find_one({"user": msg.from_user.id}) is not None)
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
if path.exists(path.join(configGet("cache", "locations"), "group_members")) and (
|
||||||
|
msg.from_user.id
|
||||||
|
not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))
|
||||||
|
):
|
||||||
|
output = False
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
async def banned_func(_, __, msg: Message):
|
||||||
|
return True if col_bans.find_one({"user": msg.from_user.id}) is not None else False
|
||||||
|
|
||||||
|
|
||||||
async def enabled_general_func(_, __, msg: Message):
|
async def enabled_general_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "general")
|
return configGet("enabled", "features", "general")
|
||||||
|
|
||||||
|
|
||||||
async def enabled_applications_func(_, __, msg: Message):
|
async def enabled_applications_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "applications")
|
return configGet("enabled", "features", "applications")
|
||||||
|
|
||||||
|
|
||||||
async def enabled_sponsorships_func(_, __, msg: Message):
|
async def enabled_sponsorships_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "sponsorships")
|
return configGet("enabled", "features", "sponsorships")
|
||||||
|
|
||||||
|
|
||||||
async def enabled_warnings_func(_, __, msg: Message):
|
async def enabled_warnings_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "warnings")
|
return configGet("enabled", "features", "warnings")
|
||||||
|
|
||||||
|
|
||||||
async def enabled_invites_check_func(_, __, msg: Message):
|
async def enabled_invites_check_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "invites_check")
|
return configGet("enabled", "features", "invites_check")
|
||||||
|
|
||||||
|
|
||||||
async def enabled_dinovoice_func(_, __, msg: Message):
|
async def enabled_dinovoice_func(_, __, msg: Message):
|
||||||
return configGet("enabled", "features", "dinovoice")
|
return configGet("enabled", "features", "dinovoice")
|
||||||
|
|
||||||
|
|
||||||
|
async def enabled_spoilers_func(_, __, msg: Message):
|
||||||
|
return configGet("enabled", "features", "spoilers")
|
||||||
|
|
||||||
|
|
||||||
async def filling_sponsorship_func(_, __, msg: Message):
|
async def filling_sponsorship_func(_, __, msg: Message):
|
||||||
return True if col_tmp.find_one({"user": msg.from_user.id, "type": "sponsorship"}) is not None else False
|
return (
|
||||||
|
True
|
||||||
|
if col_tmp.find_one({"user": msg.from_user.id, "type": "sponsorship"})
|
||||||
|
is not None
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
admin = filters.create(admin_func)
|
admin = filters.create(admin_func)
|
||||||
member = filters.create(member_func)
|
member = filters.create(member_func)
|
||||||
allowed = filters.create(allowed_func)
|
allowed = filters.create(allowed_func)
|
||||||
|
|
||||||
|
banned = filters.create(banned_func)
|
||||||
|
|
||||||
enabled_general = filters.create(enabled_general_func)
|
enabled_general = filters.create(enabled_general_func)
|
||||||
enabled_applications = filters.create(enabled_applications_func)
|
enabled_applications = filters.create(enabled_applications_func)
|
||||||
enabled_sponsorships = filters.create(enabled_sponsorships_func)
|
enabled_sponsorships = filters.create(enabled_sponsorships_func)
|
||||||
enabled_warnings = filters.create(enabled_warnings_func)
|
enabled_warnings = filters.create(enabled_warnings_func)
|
||||||
enabled_invites_check = filters.create(enabled_invites_check_func)
|
enabled_invites_check = filters.create(enabled_invites_check_func)
|
||||||
enabled_dinovoice = filters.create(enabled_dinovoice_func)
|
enabled_dinovoice = filters.create(enabled_dinovoice_func)
|
||||||
|
enabled_spoilers = filters.create(enabled_spoilers_func)
|
||||||
|
|
||||||
filling_sponsorship = filters.create(filling_sponsorship_func)
|
filling_sponsorship = filters.create(filling_sponsorship_func)
|
@ -9,18 +9,16 @@ with open("config.json", "r", encoding="utf-8") as f:
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if db_config["user"] is not None and db_config["password"] is not None:
|
if db_config["user"] is not None and db_config["password"] is not None:
|
||||||
con_string = 'mongodb://{0}:{1}@{2}:{3}/{4}'.format(
|
con_string = "mongodb://{0}:{1}@{2}:{3}/{4}".format(
|
||||||
db_config["user"],
|
db_config["user"],
|
||||||
db_config["password"],
|
db_config["password"],
|
||||||
db_config["host"],
|
db_config["host"],
|
||||||
db_config["port"],
|
db_config["port"],
|
||||||
db_config["name"]
|
db_config["name"],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
con_string = 'mongodb://{0}:{1}/{2}'.format(
|
con_string = "mongodb://{0}:{1}/{2}".format(
|
||||||
db_config["host"],
|
db_config["host"], db_config["port"], db_config["name"]
|
||||||
db_config["port"],
|
|
||||||
db_config["name"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
db_client = MongoClient(con_string)
|
db_client = MongoClient(con_string)
|
||||||
@ -28,17 +26,34 @@ db = db_client.get_database(name=db_config["name"])
|
|||||||
|
|
||||||
collections = db.list_collection_names()
|
collections = db.list_collection_names()
|
||||||
|
|
||||||
for collection in ["tmp", "users", "context", "spoilers", "messages", "warnings", "applications", "sponsorships"]:
|
for collection in [
|
||||||
|
"tmp",
|
||||||
|
"bans",
|
||||||
|
"users",
|
||||||
|
"context",
|
||||||
|
"youtube",
|
||||||
|
"spoilers",
|
||||||
|
"messages",
|
||||||
|
"warnings",
|
||||||
|
"applications",
|
||||||
|
"sponsorships",
|
||||||
|
"analytics_group",
|
||||||
|
"analytics_users"
|
||||||
|
]:
|
||||||
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_tmp = db.get_collection("tmp")
|
||||||
|
col_bans = db.get_collection("bans")
|
||||||
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_youtube = db.get_collection("youtube")
|
||||||
col_spoilers = db.get_collection("spoilers")
|
col_spoilers = db.get_collection("spoilers")
|
||||||
col_messages = db.get_collection("messages")
|
col_messages = db.get_collection("messages")
|
||||||
col_warnings = db.get_collection("warnings")
|
col_warnings = db.get_collection("warnings")
|
||||||
col_applications = db.get_collection("applications")
|
col_applications = db.get_collection("applications")
|
||||||
col_sponsorships = db.get_collection("sponsorships")
|
col_sponsorships = db.get_collection("sponsorships")
|
||||||
|
col_analytics_group = db.get_collection("analytics_group")
|
||||||
|
col_analytics_users = db.get_collection("analytics_users")
|
||||||
|
|
||||||
col_applications.create_index([("application.3.location", GEOSPHERE)])
|
col_applications.create_index([("application.3.location", GEOSPHERE)])
|
407
modules/event.py
Normal file
407
modules/event.py
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
# IF YOU'RE READING THIS DURING THE EVENT AND BEFORE COMPLETING IT - LEAVE NOW!
|
||||||
|
# ANALYZING THIS CODE WILL RUIN YOUR EXPERIENCE, SO PLEASE COMPLETE THE QUEST
|
||||||
|
# BEFORE GOING THERE. OTHERWISE THIS WILL BE CONSIDERED AS CHEATING, AND YOUR
|
||||||
|
# QUEST WILL BE RUINED FOREVER. PLEASE TAKE THIS WARNING SERIOUSLY.
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from os import path
|
||||||
|
from modules.database import db
|
||||||
|
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.types import Message, User
|
||||||
|
from pyrogram.enums import ParseMode
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from modules.logging import logWrite
|
||||||
|
from modules.utils import configGet
|
||||||
|
|
||||||
|
collections = db.list_collection_names()
|
||||||
|
|
||||||
|
if not "event" in collections:
|
||||||
|
db.create_collection("event")
|
||||||
|
|
||||||
|
col_event = db.get_collection("event")
|
||||||
|
|
||||||
|
|
||||||
|
async def stage_passer(
|
||||||
|
previous: int, current: int, user: User, requires_previous: bool = True
|
||||||
|
) -> bool:
|
||||||
|
if requires_previous:
|
||||||
|
if col_event.find_one({"user": user.id, "stage": previous}) is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if col_event.find_one({"user": user.id, "stage": current}) is None:
|
||||||
|
logWrite(
|
||||||
|
f"User {user.first_name} ({user.id}) has completed event stage {current}"
|
||||||
|
)
|
||||||
|
col_event.insert_one(
|
||||||
|
{"user": user.id, "stage": current, "date": datetime.now()}
|
||||||
|
)
|
||||||
|
if current == -1:
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
f"Користувач **{user.first_name}** (`{user.id}`) пройшов етап BONUS",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
f"Користувач **{user.first_name}** (`{user.id}`) пройшов етап №{current}",
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 1
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled
|
||||||
|
& filters.command(["aufwiedersehen"], prefixes=["/"])
|
||||||
|
& filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_1(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(0, 1, msg.from_user, requires_previous=False):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Ви відразу поїхали на місце злочину, найкрупніше відділення мережі ресторанів фаст-фуду "KFP". Як Кіара й розповіла, ніяких слідів пограбування не було. Допитавши кількох працівників, ви не дізналися нічого корисного. Камери спостереження теж не дали ніякої корисної інформації.
|
||||||
|
|
||||||
|
Засмучені тим, що не дізналися нічого, ви вийшли на вулицю подихати свіжим повітрям, вільним від сильного запаху смаженої курятини. На всяк випадок, ви вирішили обійти ресторан декілька разів, але не помітили нічого підозрілого. Тяжко видохнувши, ви присіли на скамійку та озирнулися довкола.
|
||||||
|
|
||||||
|
Ресторан стояв поруч із великим озером, і навколо не було інших будинків. Найближча споруда до нього була невеличка рибацька хатка безпосередньо на березі. Подумав про те, що це краще, ніж нічого, ви підійшли до неї та постукалися. Вам ніхто не відповів. Ви обійшли цю хатку - і нарешті побачили хоч щось цікаве. На стіні, прихованій від поглядів, була маленька панелька, яку недосвідчене око й не помітило б. Ви підійшли, віддвинули її та здивувалися, побачив, що за нею був девайс для введення коду із цифровою клавіатурою. Код був із трьох цифр, і ніяких підказок не було. Цікавості заради, ви почали вводити рандомні комбінації: "001", "666", "420"... Четвертою комбінацією було "999" - і, на диво, вона спрацювала. Девайс заблимав зеленим - і ви побачили, як з-під землі з'явився люк. Ви віддвинули його - і спустилися по драбині вниз, до якогось дивного підземного проходу.
|
||||||
|
|
||||||
|
Пройшовши по ньому буквально двадцять кроків, ви побачили двері, а поруч із ними - ще один девайс для вводу пароля. Цього разу це були англійські букви, і в паролі їх було 6. Тут вже простим перебором не задовольнишся, тому ви почали шукати якісь підказки. На щастя, одну ви знайшли, з іншої сторони дверей була невеличка ніша, в якій лежав червоно-білий прапорець та [дивна фотографія](https://docs.google.com/document/d/1X3hj1mD0cPL6ZKgtFrOxHmiQtwCFnHQrBjsn0_gfR7s/edit?usp=sharing).
|
||||||
|
|
||||||
|
Ви відразу зрозуміли, кому належить ця хатка, та ввели правильний шестилітерний пароль.""",
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 2
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["tonjok"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_2(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(1, 2, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Ви дуже здивувалися, коли побачили, що таємна кімната виявилася... Бібліотекою. Просто для того, щоб впевнитися, що тут не відбувається нічого кримінального, ви відкрили першу ж книгу, що попалася на очі.
|
||||||
|
|
||||||
|
На обкладинці була намальована сором'язлива Оллі в нижній білизні. Ви почервоніли і прочитали назвуу. "Noise Complaint 3: Shutting Up Your Loud Zombie Neighbor (With French Kisses)". Це виявився юрійний фанфік! Ви швиденько пролистали його, почервоніли ще більше - і вирішили залишити кімнату. Що б тут не відбувалося, навряд чи це стосується викрадених яєць.
|
||||||
|
|
||||||
|
На щастя, коли ви піднялися назад на поверхню, хазяйка хатки ще не повернулася. На всяк випадок, ви залишили записку: "Ми розслідуємо злочин про викрадення пасхальних яєць. Якщо ваші яйця були вкрадені, будь ласка, зверніться до найближчого відділення Оодзора Кейсацу."
|
||||||
|
|
||||||
|
Не знайшовши ніяких нових доказів, ви вирішили повернутися до відділення. Там вас зустріла Субару в дуже поганому настрої. Ви коротко розповіли їй про те, що відбувалося протягом дня, і вона поскаржилася, що її набір яєць на Пасху теж був вкрадений!
|
||||||
|
|
||||||
|
Це вже виглядає як серійні крадіжки! Субару вирішила послати вас до Рейне, дізнатися, чи стала вона жертвою крадіїв теж. Оскільки та не дуже любить незнайомих людей, Субару дала вам таємний пароль, який треба буде сказати Рейне - назву юніта, що складається з Оодзори, Таканаші та Паволії."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 3
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled
|
||||||
|
& filters.command(["turducken"], prefixes=["/"])
|
||||||
|
& filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_3(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(2, 3, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Прийшовши до будинку Рейне, ви не змогли потрапити всередину, бо ваші дзвінки були проігноровані. Роздивившись ворота поуважніше, ви побачили збоку невеличку табличку із написом "ВСЬОГО ЗА ТРИ ПРОСТИХ КЛІКИ ВИ ТЕЖ МОЖЕТЕ ДОЄДНАТИСЯ, MUDAH SEKALI" і кодовий замок із шести літер."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 4
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["joinda"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_4(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(3, 4, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Пройшовши через ворота, ви постукали у двері і сказали таємний пароль від Субару. Двері відчинилися, і ви почули голос Рейне. "Заходь у останні двері ліворуч". На дверях чомусь була намальована велика червона цифра 5 та поруч був дуже дивний механізм. Ви не встигли роздивитися цей "замок", як двері почали повільно відчинятися. Зайшовши всередину ви опинилися у Кавуновій Кімнаті™, посеред якої сиділа Рейне. Ви почали задавати питання про яйця, але Кавунова Кімната™ не виходила з вашої голови, наче ви десь її бачили... І тут ви згадали! Така сама кімната була в тому фанфіку! На жаль, ви мали необережність сказати це вголос, і Рейне образилася на вас через те, що ви зайшли в її бібліотеку без дозволу. Із криками "ТА НІХТО НЕ КРАВ МОЇ ЯЙЦЯ!" вона випинує вас надвір, і ви вирішуєте іти до наступної Холоторі.
|
||||||
|
|
||||||
|
Ви вирішили завітати до Мумей. Діставшись її дому, ви довго стояли перед входом та думали, чи варто взагалі заходити. Її дім - це гігантська темна печера, що веде в невідоме. Але ваш обов’язок кличе, тому, дістав свій ліхтарик, ви ризикнули зайти. Блукая тунелями печери, ви постійно натикалися на розвилки. Перші два перехрестя ви пройшли прямо, не завертаючи нікуди. Але на третьому вас чекали підозрілі червоні плями на стінах, і ви вирішили, що краще повернутися та обрати інший маршрут. Ви повертали то вліво, то вправо, то вліво, то вправо, і врешті-решт опинилися в тупику. На стіні висіла табличка з двома буквами: “B” та “A”, а під нею лежали полотно, перо та баночка з тією самою червоною рідиною. На самому ж полотні було 6 пустих клітинок. Чи варто вам спробувати щось написати чи просто розвернутися та піти іншою дорогою?
|
||||||
|
|
||||||
|
<i>(Введіть команду /next, якщо хочете продовжити розслідування, або введіть зашифровану команду /******, щоб побачити бонусну сцену, яка не впливає на геймплей.)</i>""",
|
||||||
|
parse_mode=ParseMode.HTML,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 5
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["next"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_5(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(4, 5, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Ви повернулися на самий початок шляху і пішли в той напрямок, який ще не дослідили. На диво, ця дорога вела прямо. Коли ви йшли, вам по дорозі траплялися дивні камінчики, які ви вирішили збирати. На кінці шляху вас чекали великі двері, наче в бункері. Коло них був девайс для вводу коду з 3 цифр. Ви подивилися ще раз на камінчики, які зібрали та на символи на них:
|
||||||
|
|
||||||
|
一1403
|
||||||
|
二2308
|
||||||
|
三156
|
||||||
|
四2103
|
||||||
|
五0412
|
||||||
|
六154
|
||||||
|
七2203
|
||||||
|
八0408
|
||||||
|
九149
|
||||||
|
|
||||||
|
Подумав, ви вирішили ввести потрібні цифри від найменшої до найбільшої - і двері почали відчинятися…"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 6
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["238"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_6(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(5, 6, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Всередині ви побачили гігантську ферму, явно штучно зроблену, та Кроніі з Фауну, які поливали саженці. Вони здивувалися, побачивши вас, але ви швидко показали своє поліцейське посвідчення та пояснили ситуацію. Дівчата сказали, що ніякі яйця в Мумей ніхто не крав і що самі вони нічого не чули. Перед тим, як ви пішли далі, вони з ігривою посмішкою задали вам питання, сказав, що дадуть вам підказку, якщо ви правильно дасте відповідь.
|
||||||
|
|
||||||
|
- Поліцейський-кун, ти ж злякався, коли йшов сюди? Ти думав, що це кров була на стінах? Але ні, ця фарба була зроблена з іншого. А з чого саме?
|
||||||
|
|
||||||
|
Ви подивилися навколо та, побачивши, що більше всього росло на фермі, дали впевнену відповідь."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 7
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["berries"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_7(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(6, 7, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Кроніі та Фауна, як обіцяли, дали вам підказку. Коли ви сказали, що ви опитуєте всіх Голоторі, вони зрозуміли, що далі ви підете до Луї. Але базу Голоксу просто так не знайти, тому дівчата підказали вам локацію. Ви прийшли на місце і опинилися перед звичайним собі житловим будинком у спальному районі. Ви знайшли вхід до підвалу та ввели код від двері (1111), який вам повідомили дівчата з ГолоРади. “Дивно, якось занадто легко як для секретної бази”, - подумали ви та зайшли всередину. Підвал виглядав абсолютно звичайно, єдине, що виділялося, - це залізні двері без ручки. Коло них на вас чекала чергова кодова панель. На цей раз із буквенною клавіатурою. Ви подивилися на символи на двері, “常夜”, та ввели правильний пароль."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 8
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["repaint"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_8(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(7, 8, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Тільки-но двері відчинилися, ви побачили перед собою Луї у формі Голоксу та в шикарних окулярах, що нагадували вам окуляри Каміни із Ґуррен Лаґанну, а на плечі в неї сидів її секретар, Ґанмо. Її насторожило, що робітник поліції увірвався на секретну базу Голоксу. Ви поспішили її заспокоїти, та сказали що ви розслідуєте зникнення яєць у Холоторі. Луї відповіла, що її яйця в повному порядку і ніхто їх не крав, а от просто так відпустити вас вона тепер не може, бо ви знаєте, де знаходиться секретний штаб. Після цих слів вона простягнула якусь склянку із рідиною, що виглядала як препарати, які носить із собою Койорі. Після того, як випили вміст тієї склянки, ви знепритомніли, а коли прийшли до тями, то сиділи поруч із поліцейським відділенням. У вас зникли спогади про те, як ви йшли до бази Голоксу, але ви чітко запам'ятали, що яйця у Луї ніхто не крав. Озирнувшись по сторонам, ви побачили, що вас кличе до себе Субару. Зайшовши до неї в кабінет, ви дізналися, що поки ви бігали в пошуках Холоторі, у відділення хтось доставив таємничу коробку із кодовим замком та записку, причеплену до неї.
|
||||||
|
|
||||||
|
У записці був написаний ось такий текст (хоча це більше походило на набір літер):
|
||||||
|
|
||||||
|
__Lq Pdufk ru Dsulo
|
||||||
|
Wkhvh wklqjv gr derxqg
|
||||||
|
D fhuwdlq exqqb
|
||||||
|
Ohdyhv wkhvh rq wkh jurxqg__
|
||||||
|
|
||||||
|
А на зворотній стороні був намальований символ 三
|
||||||
|
|
||||||
|
На кодовому замку ж треба ввести код із 9-и літер без пробілів."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 9
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled
|
||||||
|
& filters.command(["easteregg"], prefixes=["/"])
|
||||||
|
& filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_9(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(8, 9, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Усередині коробки була рація. Субару негайно вихопила її та натиснула на кнопку зв’язку.
|
||||||
|
|
||||||
|
- Прийом-прийом! Я не знаю, хто ти і що тобі потрібно, але поверни яйця! Я їй чесно сама висид… Пофарбувала!
|
||||||
|
|
||||||
|
- AH↓HA↑HA↓HA↑HA↓
|
||||||
|
|
||||||
|
- ПЕКОРА?! Я так і знала, що це ти!
|
||||||
|
|
||||||
|
- Моя люба Субару, ти так сильно старалася, що я не можу відмовити тобі! Приїжджай, забирай їх назад. Якщо знайдеш, звісно! AH↓HA↑HA↓HA↑HA↓
|
||||||
|
|
||||||
|
На цьому зв’язок обірвався. Субару почала крутити рацію, шукаючи, чи є щось, що з нею не так. Ви запропонували відкрити відділення для батарейок, і дійсно, там були два папірця. Один із них - це було міні-фото Каели, на якому маркером було написано: “******** doko?” На другому було написано рваним почерком: “07 Jan 22, Mute City, never forget”. Окрім того, ви помітили, що в коробці лежав маленький шматочок якогось білого мінералу. Зібрав до купи всі підказки, ви повідомили шефу, куди вам треба їхати.""",
|
||||||
|
parse_mode=ParseMode.DISABLED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 10
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["atlantis"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_10(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(9, 10, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Ви разом із Субару під’їхали до руїн Атлантиди. Хоча, чи можна це назвати руїнами, коли Ґура просто не добудувала? В будь-якому випадку, на найвищому п’єдесталі стояв кошик, в якому лежали пасхальні яйця Субару, цілі та непошкоджені! Ваша шеф радісно підбігла до нього, але швидко засмутилася, коли побачила серед яєць планшет. Вона увімкнула його - і на заставці екрану було лого Усада Кенсецу. Планшет був повністю пустим, єдиним файлом було відео без назви. Субару увімкнула його - і на екрані з’явився знайомий кролячий силует.
|
||||||
|
|
||||||
|
- AH↓HA↑HA↓HA↑HA↓ Як бачиш, Субару, твої дорогоцінні яйця в повній безпеці! Та й кому вони взагалі потрібні, коли є набагато рідкісніший та особливіший делікатес?
|
||||||
|
|
||||||
|
Камера віддвинулася від Пекори і показала стіл, на якому стояла гігантська паска, прикрашена немов би золотом та дорогоцінними камнями. Камера протримала її в фокусі пару секунд, а потім перевелася назад на Пекору.
|
||||||
|
|
||||||
|
- До вашої уваги, гордість пекарні Короне, Голо-паска! Якщо я не помиляюся, мала бути презентована особисто Яґо на параді в центрі міста цього вечора. Уявляю собі, як йому зараз сумно від того, що вона зникла. Тепер всі точно побачать його некомпетентність та визнають, що лише Пекора варта звання мера Голо-сіті! AH↓HA↑HA↓HA↑HA↓HA↑HA↓HA↑HA↓
|
||||||
|
|
||||||
|
Субару стиснула кулаки та почала кричати в екран, забувши про те, що це запис, а не прямий ефір. Нарешті, Пекора закінчила сміятися і продовжила:
|
||||||
|
|
||||||
|
- Моя люба Субару, не плач. Я благородний крадій і дам тобі шанс побути сьогодні героєм та врятувати святковий парад! Якщо хочеш знайти мене та відібрати в мене паску, то рекомендую почати з того, щоб знайти брехуна! Але ти можеш __24__ рази __поговорити__ з усіма мешканцями __Голо__-сіті - тобі все одно не вистачить кмітливості! Адіос!
|
||||||
|
|
||||||
|
На цьому відео закінчилося. Ви заспокоїли Субару та звернули її увагу на те, що деякі слова Пекори були сказані іншою інтонацією. Подумав і згадав події сьогоднішнього дня, ви зрозуміли, до кого треба заїхати в першу чергу.
|
||||||
|
|
||||||
|
__(У команду треба вписати лише ім’я дівчинки.)__"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 11
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["kiara"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_11(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(10, 11, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Прийшовши до Кіари, ви почали вимагати від неї пояснень. Вона зізналася, що просто не могла відмовити Пекорі, але вона дасть нам наступну підказку. Після цього Кіара почала нишпорити у шафі і через деякий час дістала звідти скриньку із дивними символами. "Цю коробку мені подарувала __Аме__ після __найпершого походу__ в новий світ Амеверсу. Сюди я й поклала підказки, що мені передала Пекора. Якщо зможеш відкрити - вони твої". На шкатулці були зображені [такі символи](https://docs.google.com/document/d/1w2ARMWpUIkNpmSNWFJVGobIMVh2scgSy2hgyHssGLtA/edit?usp=sharing), під якими був кодовий замок із 8 цифр.""",
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 12
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["11022021"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_12(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(11, 12, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""У скриньці був папірець з географічними координатами. Субару поїхала пояснювати ситуацію до Яґо, тому далі ви були самі по собі. Ви приїхали на місце і побачили самотній дуб, що ріс посеред парку. У дуплі дуба на вас чекала нова скринька. На її кришці було написано почерком Пекори наступне:
|
||||||
|
|
||||||
|
__6 листопада
|
||||||
|
Греміла битва.
|
||||||
|
Червоні ведмеді
|
||||||
|
Та білі вовки -
|
||||||
|
Ніхто не переміг.
|
||||||
|
У той день
|
||||||
|
Я була другою.
|
||||||
|
Якою була надія?__
|
||||||
|
|
||||||
|
Скриньку закривав кодовий замок лише з двох цифер. У вас взагалі не було ідей, але ви не могли підвести Субару, оскільки вона поклалася на вас! Ви сіли під дубом та почали думати, але так і не змогли знайти відповідь. Ви ледве не заплакали від безсилля, коли до вас підійшла Шішіро Ботан, що прогулювалася парком.
|
||||||
|
|
||||||
|
- Що, офіцере, не можете одужати геній Усада Кенсецу? Не переймайтеся, я їй відразу сказала, що це занадто складно. Але Пекора любить чесну боротьбу, тому вона й попросила мене дивитися одним оком за цією локацію та дати підказку, якщо тобі буде важко. У той день моїм лідером була ніхто інша як Субару, а номер мій був 28. Далі розберешся, шукай у записах! Отож, бувай, хай тобі щастить, пой!
|
||||||
|
|
||||||
|
Шішірон залишила вас, а ви панічно почали діставати смартфон та відкривати ютуб. Ви зрозуміли, про що йшла мова, тому легко змогли ввести правильний номер."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 13
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["24"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_13(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(12, 13, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Відкривши скриньку, ви побачили всередині... Карі з бараниною?.. Спочатку ви нічого не зрозуміли, але незабаром відчули на собі (чи все ж таки на карі?) голодний погляд Ботан, яка все ще знаходилася поруч. Ви вирішили віддати їй цю смачну страву, за що левиця, задоволено посміхаючись, видала вам рацію та маленьку коробочку у формі ССРБ із кодовим замком на 3 цифри. Рація постійно видавала звуки, схожі на якийсь код, а на коробці було викарбувано "A—>Z, Z—>A". Виписавши сигнали рації морзянкою, ви отримали таке повідомлення:
|
||||||
|
|
||||||
|
--.. --. --. ... ...- .... --. --.. .. --. .-.. ..- ... ...- .. --.- .-.. ..-. .. -- ...- -... .... --. --.. .. .. -... -- .-. - ... --. .-.. . ...- .. .--. -... .-. . .... .-.. -. --.. -- -... .-- --.. -... .... ... --.. . ...- -.- --.. .... .... ...- .-- --. ...- --- --- -. ...- --. ... ...- -. .-. -- ..-. --. ...- .-. --. ... --.. -.- -.- ...- -- ...- .--
|
||||||
|
|
||||||
|
Швиденько розгадавши цю загадку, ви ввели правильний код.""",
|
||||||
|
parse_mode=ParseMode.DISABLED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 14
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["003"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_14(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(13, 14, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Чергові координати привели вас до закинутого автокінотеатру. Ви увійшли на територію та побачили сцену, на якій я показували фільми. Проектор виводив на екран [дивну таблицю](https://docs.google.com/document/d/1_Mf9w52vDG0sQZ-xKn1pg4tdsLHwiq97O-nHxYELUkI/edit?usp=sharing):
|
||||||
|
|
||||||
|
Також на сцені стояв великий сейф із кодовим замком з 16 символів. З одного боку сейфу було написано наступне:
|
||||||
|
|
||||||
|
パッと光って咲いた 花火を見てた
|
||||||
|
きっとまだ 終わらない夏が
|
||||||
|
曖昧な心を 解かして繋いだ
|
||||||
|
この夜が続いて欲しかった
|
||||||
|
|
||||||
|
А з іншого - просто “Thank you doragon!”. Зверху ж був наступний напис: “1D2?...”
|
||||||
|
|
||||||
|
Ви довго думали, але змогли розшифрувати цю загадку, знову скориставшись ютубом!
|
||||||
|
|
||||||
|
|
||||||
|
__(Відповідь треба вводити цифрами та великими англійськими літерами.)__"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 15
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled
|
||||||
|
& filters.command(["1D2C3E4H5B6F7G8A"], prefixes=["/"])
|
||||||
|
& filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_15(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(14, 15, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""У сейфі лежала паперова мапа Голо-сіті, на якій червоним колом була відмічена споруда посеред промзони. Ви негайно вирушили туди. Цією будівлею виявився чи то ангар, чи то склад, що належав УсаКену. Всі вікна до нього були закриті металевими пластинами, а єдиним входом всередину були масивні ангарні двері. Звісно ж, силою їй відчинити не вдалося. Ретельно перевіривши стіни будівлі зовні, ви помітили, що в одному місці цеглини були розшатані. Ви обережно дістали пару цеглин - і ву-аля, перед вами був черговий девайс для вводу коду. Але цього разу це була повноцінна комп’ютерна клавіатура, і ніякого ліміту символів не було.
|
||||||
|
|
||||||
|
Ви почали трошки панікувати, адже ніяких підказок навколо ви не помітили, аж тут вам на телефон подзвонила Субару. Ви швидко взяли трубку:
|
||||||
|
|
||||||
|
- Офіцере, я тільки що отримала якийсь незрозумілий файл особисто від Пекори! Пересилаю його тобі, розберися - і швиденько, бо через годину вже початок параду!
|
||||||
|
|
||||||
|
Ви --[відкрили файл](https://drive.google.com/file/d/1oex8GriQBsimIsUvOGo83IuFp2JBtNJd/view?usp=sharing)--, потупили декілька хвилин, але врешті-решт змогли зрозуміти загадку та ввели правильний пароль!"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 16
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["hinotori"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_16(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(15, 16, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_text(
|
||||||
|
"""Коли ви ввели пароль, двері відчинилися. Всередині панувала кромішня темрява, і, судячи з ехо від ваших кроків, приміщення було повністю пустим. Раптом, над вами загорілися прожектори, і кімната залилася сліпучим білим світлом. Звідкись з-під даху роздався скрип динаміків - і знайомий вам кролячий голос почав говорити:
|
||||||
|
|
||||||
|
- А ще трохи - і було б запізно. Дозвольте привітати вас із тим, що ви змогли розгадати всі мої загадки! Паска, що ви шукаєте, вже доставлена до офісу Субару. Що ж це ви так поспішали, що аж забули зачинити двері? Дякуючи цьому, я змогла знайти те, що так давно шукала! Але не хвилюйтеся, паску, що послужила такою чудовою заманкою, я вам повертаю цілою та непошкодженою. Ще побачимося! AH↓HA↑HA↓HA↑HA↓HA↑HA↓HA↑HA↓
|
||||||
|
|
||||||
|
Як ви і думали, по поверненню до офіса Субару, ви виявили повний бардак. Всі шкафи були вивернуті, а документи розкидані по всій кімнаті. Очевидно, це свідчило про крадіж. Дехто провів тут багато часу, раз зміг поперевертати кожен куточок. І хоч парад Голо-сіті був врятований, а нинішня справа закрита, вас тепер мучило питання, що ж таке було необхідне Пекорі, що вона вдалася до таких заходів, щоб вас збити з пантелику та заплутати. Ви були впевнені, що дуже скоро ви про неї почуєте знову…"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Stage BONUS
|
||||||
|
@app.on_message(
|
||||||
|
~filters.scheduled & filters.command(["konami"], prefixes=["/"]) & filters.private
|
||||||
|
)
|
||||||
|
async def cmd_event_bonus(app: Client, msg: Message):
|
||||||
|
if not await stage_passer(4, -1, msg.from_user):
|
||||||
|
return
|
||||||
|
|
||||||
|
await msg.reply_photo(
|
||||||
|
path.join("assets", "event_easter_2023", "stage_bonus.jpg"),
|
||||||
|
caption="""Раптом, стіна почала рухатися, відкриваючи вам прохід. Ви повільно зайшли всередину і побачили якусь дівчину із кролячими вухами. Помітивши вас, вона повернулась і, посміхаючись, промовила:
|
||||||
|
|
||||||
|
- Вибач, але твоє яйце знаходиться в іншій печері. Тут тільки я і мій друг - П'ятнична Ніч.
|
||||||
|
|
||||||
|
Відвернувшись від вас, вона продовжила спілкуватися з великоднім яйцем, а ви, не бажаючи їй заважати, спішно покинули печеру і повернулися до найпершої розвилки.
|
||||||
|
|
||||||
|
__(Введіть команду /next для продовження сюжету.)__""",
|
||||||
|
)
|
255
modules/handlers/analytics_group.py
Normal file
255
modules/handlers/analytics_group.py
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from polyglot.detect import Detector
|
||||||
|
from pyrogram import filters
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from pyrogram.enums import MessageEntityType, PollType
|
||||||
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from modules import custom_filters
|
||||||
|
from modules.database import col_analytics_group
|
||||||
|
from modules.logging import logWrite
|
||||||
|
from modules.utils import configGet
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_general
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.chat(configGet("users", "groups"))
|
||||||
|
)
|
||||||
|
async def msg_destination_group(app: Client, msg: Message):
|
||||||
|
analytics_entry = {
|
||||||
|
"id": msg.id,
|
||||||
|
"user": msg.from_user.id,
|
||||||
|
"date": datetime.now(),
|
||||||
|
"reply": {
|
||||||
|
"id": msg.reply_to_message_id,
|
||||||
|
"top_id": msg.reply_to_top_message_id,
|
||||||
|
"user": None
|
||||||
|
if msg.reply_to_message is None
|
||||||
|
else msg.reply_to_message.from_user.id,
|
||||||
|
},
|
||||||
|
"forward": {
|
||||||
|
"id": msg.forward_from_message_id,
|
||||||
|
"chat": None if msg.forward_from_chat is None else msg.forward_from_chat.id,
|
||||||
|
"user": None if msg.forward_from is None else msg.forward_from.id,
|
||||||
|
"date": msg.forward_date,
|
||||||
|
},
|
||||||
|
"media_spoilered": msg.has_media_spoiler,
|
||||||
|
"entities": {"links": [], "mentions": []},
|
||||||
|
"text": None,
|
||||||
|
"language": None,
|
||||||
|
"language_confidence": None,
|
||||||
|
"animation": None,
|
||||||
|
"audio": None,
|
||||||
|
"contact": None,
|
||||||
|
"document": None,
|
||||||
|
"location": None,
|
||||||
|
"photo": None,
|
||||||
|
"poll": None,
|
||||||
|
"sticker": None,
|
||||||
|
"venue": None,
|
||||||
|
"video": None,
|
||||||
|
"videonote": None,
|
||||||
|
"voice": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.text is not None or msg.caption is not None:
|
||||||
|
text = msg.text if msg.text is not None else msg.caption
|
||||||
|
analytics_entry["text"] = text
|
||||||
|
|
||||||
|
if msg.entities is not None or msg.caption_entities is not None:
|
||||||
|
entities = (
|
||||||
|
msg.entities if msg.entities is not None else msg.caption_entities
|
||||||
|
)
|
||||||
|
for entity in entities:
|
||||||
|
if entity.type == MessageEntityType.TEXT_LINK:
|
||||||
|
analytics_entry["entities"]["links"].append(entity.url)
|
||||||
|
elif entity.type == MessageEntityType.URL:
|
||||||
|
analytics_entry["entities"]["links"].append(
|
||||||
|
text[entity.offset : entity.offset + entity.length]
|
||||||
|
)
|
||||||
|
elif entity.type == MessageEntityType.TEXT_MENTION:
|
||||||
|
analytics_entry["entities"]["mentions"].append(entity.user.id)
|
||||||
|
elif entity.type == MessageEntityType.MENTION:
|
||||||
|
analytics_entry["entities"]["mentions"].append(
|
||||||
|
text[entity.offset : entity.offset + entity.length]
|
||||||
|
)
|
||||||
|
|
||||||
|
lang = Detector(text, quiet=True).language
|
||||||
|
|
||||||
|
analytics_entry["language"] = lang.code
|
||||||
|
analytics_entry["language_confidence"] = lang.confidence
|
||||||
|
|
||||||
|
if lang.code == "ru":
|
||||||
|
logWrite(
|
||||||
|
f"Message '{text}' from {msg.from_user.first_name} ({msg.from_user.id}) is fucking russian [confidence {lang.confidence}]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if msg.animation is not None:
|
||||||
|
analytics_entry["animation"] = {
|
||||||
|
"id": msg.animation.file_id,
|
||||||
|
"duration": msg.animation.duration,
|
||||||
|
"height": msg.animation.height,
|
||||||
|
"width": msg.animation.width,
|
||||||
|
"file_name": msg.animation.file_name,
|
||||||
|
"mime_type": msg.animation.mime_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.audio is not None:
|
||||||
|
analytics_entry["audio"] = {
|
||||||
|
"id": msg.audio.file_id,
|
||||||
|
"title": msg.audio.title,
|
||||||
|
"performer": msg.audio.performer,
|
||||||
|
"duration": msg.audio.duration,
|
||||||
|
"file_name": msg.audio.file_name,
|
||||||
|
"file_size": msg.audio.file_size,
|
||||||
|
"mime_type": msg.audio.mime_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.contact is not None:
|
||||||
|
analytics_entry["contact"] = {
|
||||||
|
"id": msg.contact.user_id,
|
||||||
|
"first_name": msg.contact.first_name,
|
||||||
|
"last_name": msg.contact.last_name,
|
||||||
|
"phone_number": msg.contact.phone_number,
|
||||||
|
"vcard": msg.contact.vcard,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.document is not None:
|
||||||
|
analytics_entry["document"] = {
|
||||||
|
"id": msg.document.file_id,
|
||||||
|
"file_name": msg.document.file_name,
|
||||||
|
"file_size": msg.document.file_size,
|
||||||
|
"mime_type": msg.document.mime_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.location is not None:
|
||||||
|
analytics_entry["location"] = {
|
||||||
|
"longitude": msg.location.longitude,
|
||||||
|
"latitude": msg.location.latitude,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.photo is not None:
|
||||||
|
thumbnails = []
|
||||||
|
for thumbail in msg.photo.thumbs:
|
||||||
|
thumbnails.append(
|
||||||
|
{
|
||||||
|
"id": thumbail.file_id,
|
||||||
|
"height": thumbail.height,
|
||||||
|
"width": thumbail.width,
|
||||||
|
"file_size": thumbail.file_size,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
analytics_entry["photo"] = {
|
||||||
|
"id": msg.photo.file_id,
|
||||||
|
"height": msg.photo.height,
|
||||||
|
"width": msg.photo.width,
|
||||||
|
"file_size": msg.photo.file_size,
|
||||||
|
"thumbnails": thumbnails,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.poll is not None:
|
||||||
|
options = []
|
||||||
|
for option in msg.poll.options:
|
||||||
|
options.append(option.text)
|
||||||
|
analytics_entry["poll"] = {
|
||||||
|
"id": msg.poll.id,
|
||||||
|
"question": msg.poll.question,
|
||||||
|
"open_period": msg.poll.open_period,
|
||||||
|
"close_date": msg.poll.close_date,
|
||||||
|
"options": options,
|
||||||
|
"correct_option": msg.poll.correct_option_id,
|
||||||
|
"explanation": msg.poll.explanation,
|
||||||
|
"anonymous": msg.poll.is_anonymous,
|
||||||
|
"multiple_answers": msg.poll.allows_multiple_answers,
|
||||||
|
"quiz": True if msg.poll.type == PollType.QUIZ else False,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.sticker is not None:
|
||||||
|
thumbnails = []
|
||||||
|
for thumbail in msg.sticker.thumbs:
|
||||||
|
thumbnails.append(
|
||||||
|
{
|
||||||
|
"id": thumbail.file_id,
|
||||||
|
"height": thumbail.height,
|
||||||
|
"width": thumbail.width,
|
||||||
|
"file_size": thumbail.file_size,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
analytics_entry["sticker"] = {
|
||||||
|
"id": msg.sticker.file_id,
|
||||||
|
"emoji": msg.sticker.emoji,
|
||||||
|
"set_name": msg.sticker.set_name,
|
||||||
|
"animated": msg.sticker.is_animated,
|
||||||
|
"video": msg.sticker.is_video,
|
||||||
|
"height": msg.sticker.height,
|
||||||
|
"width": msg.sticker.width,
|
||||||
|
"file_name": msg.sticker.file_name,
|
||||||
|
"file_size": msg.sticker.file_size,
|
||||||
|
"mime_type": msg.sticker.mime_type,
|
||||||
|
"thumbnails": thumbnails,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.venue is not None:
|
||||||
|
analytics_entry["venue"] = {
|
||||||
|
"title": msg.venue.title,
|
||||||
|
"address": msg.venue.address,
|
||||||
|
"longitude": msg.venue.location.longitude,
|
||||||
|
"latitude": msg.venue.location.latitude,
|
||||||
|
"foursquare_id": msg.venue.foursquare_id,
|
||||||
|
"foursquare_type": msg.venue.foursquare_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.video is not None:
|
||||||
|
thumbnails = []
|
||||||
|
for thumbail in msg.video.thumbs:
|
||||||
|
thumbnails.append(
|
||||||
|
{
|
||||||
|
"id": thumbail.file_id,
|
||||||
|
"height": thumbail.height,
|
||||||
|
"width": thumbail.width,
|
||||||
|
"file_size": thumbail.file_size,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
analytics_entry["video"] = {
|
||||||
|
"id": msg.video.file_id,
|
||||||
|
"duration": msg.video.duration,
|
||||||
|
"height": msg.video.height,
|
||||||
|
"width": msg.video.width,
|
||||||
|
"file_name": msg.video.file_name,
|
||||||
|
"file_size": msg.video.file_size,
|
||||||
|
"mime_type": msg.video.mime_type,
|
||||||
|
"thumbnails": thumbnails,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.video_note is not None:
|
||||||
|
thumbnails = []
|
||||||
|
for thumbail in msg.video_note.thumbs:
|
||||||
|
thumbnails.append(
|
||||||
|
{
|
||||||
|
"id": thumbail.file_id,
|
||||||
|
"height": thumbail.height,
|
||||||
|
"width": thumbail.width,
|
||||||
|
"file_size": thumbail.file_size,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
analytics_entry["videonote"] = {
|
||||||
|
"id": msg.video_note.file_id,
|
||||||
|
"duration": msg.video_note.duration,
|
||||||
|
"length": msg.video_note.length,
|
||||||
|
"file_size": msg.video_note.file_size,
|
||||||
|
"mime_type": msg.video_note.mime_type,
|
||||||
|
"thumbnails": thumbnails,
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.voice is not None:
|
||||||
|
analytics_entry["voice"] = {
|
||||||
|
"id": msg.voice.file_id,
|
||||||
|
"duration": msg.voice.duration,
|
||||||
|
"file_size": msg.voice.file_size,
|
||||||
|
"mime_type": msg.voice.mime_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
col_analytics_group.insert_one(analytics_entry)
|
@ -3,29 +3,49 @@ 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, ForceReply, Message
|
from pyrogram.types import (
|
||||||
|
ReplyKeyboardRemove,
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ForceReply,
|
||||||
|
Message,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from pyrogram.enums.parse_mode import ParseMode
|
from pyrogram.enums.parse_mode import ParseMode
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import all_locales, configGet, locale, logWrite
|
from modules.utils import all_locales, configGet, locale, logWrite
|
||||||
from modules.handlers.welcome import welcome_pass
|
from modules.handlers.welcome import welcome_pass
|
||||||
from modules.database import col_tmp
|
from modules.database import col_tmp, col_applications
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Confirmation =================================================================================================================
|
|
||||||
confirmation_1 = []
|
confirmation_1 = []
|
||||||
for pattern in all_locales("confirm", "keyboard"):
|
for pattern in all_locales("confirm", "keyboard"):
|
||||||
confirmation_1.append(pattern[0][0])
|
confirmation_1.append(pattern[0][0])
|
||||||
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.private & filters.command(confirmation_1, prefixes=[""]))
|
|
||||||
async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "sponsorship", "unknown"] = "unknown"):
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
(custom_filters.enabled_applications | custom_filters.enabled_sponsorships)
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(confirmation_1, prefixes=[""])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def confirm_yes(
|
||||||
|
app: Client,
|
||||||
|
msg: Message,
|
||||||
|
kind: Literal["application", "sponsorship", "unknown"] = "unknown",
|
||||||
|
):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
if configGet("enabled", "features", "applications") is True:
|
if configGet("enabled", "features", "applications") is True:
|
||||||
|
if (kind == "application") or (
|
||||||
if (kind == "application") or ((holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True)):
|
(holo_user.application_state()[0] == "fill")
|
||||||
|
and (holo_user.application_state()[1] is True)
|
||||||
tmp_application = col_tmp.find_one({"user": holo_user.id, "type": "application"})
|
):
|
||||||
|
tmp_application = col_tmp.find_one(
|
||||||
|
{"user": holo_user.id, "type": "application"}
|
||||||
|
)
|
||||||
|
|
||||||
if tmp_application is None:
|
if tmp_application is None:
|
||||||
logWrite(f"Application of {holo_user.id} is nowhere to be found.")
|
logWrite(f"Application of {holo_user.id} is nowhere to be found.")
|
||||||
@ -34,68 +54,120 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s
|
|||||||
if tmp_application["sent"] is True:
|
if tmp_application["sent"] is True:
|
||||||
return
|
return
|
||||||
|
|
||||||
await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove())
|
await msg.reply_text(
|
||||||
|
locale("application_sent", "message"),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
|
||||||
application_content = []
|
application_content = []
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
for question in tmp_application['application']:
|
for question in tmp_application["application"]:
|
||||||
|
|
||||||
if i == 2:
|
if i == 2:
|
||||||
age = relativedelta(datetime.now(), tmp_application['application']['2'])
|
age = relativedelta(
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
|
datetime.now(), tmp_application["application"]["2"]
|
||||||
|
)
|
||||||
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)"
|
||||||
|
)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
if tmp_application['application']['3']['countryCode'] == "UA":
|
if tmp_application["application"]["3"]["countryCode"] == "UA":
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
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']})")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']} ({tmp_application['application']['3']['adminName1']}, {tmp_application['application']['3']['countryName']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application'][question]}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application'][question]}"
|
||||||
|
)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if tmp_application["reapply"]:
|
if (
|
||||||
await app.send_message(chat_id=configGet("admin", "groups"), text=(locale("reapply_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
|
tmp_application["reapply"] is True
|
||||||
|
and col_applications.find_one({"user": holo_user.id}) is not None
|
||||||
|
):
|
||||||
|
await app.send_message(
|
||||||
|
chat_id=configGet("admin", "groups"),
|
||||||
|
text=(locale("reapply_got", "message")).format(
|
||||||
|
str(holo_user.id),
|
||||||
|
msg.from_user.first_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("reapply_yes", "button")),
|
||||||
|
callback_data=f"reapply_yes_{holo_user.id}",
|
||||||
|
)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text=str(locale("reapply_no", "button")), callback_data=f"reapply_no_{holo_user.id}")
|
InlineKeyboardButton(
|
||||||
]
|
text=str(locale("reapply_no", "button")),
|
||||||
|
callback_data=f"reapply_no_{holo_user.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
]
|
]
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await app.send_message(chat_id=configGet("admin", "groups"), text=(locale("application_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
|
await app.send_message(
|
||||||
|
chat_id=configGet("admin", "groups"),
|
||||||
|
text=(locale("application_got", "message")).format(
|
||||||
|
str(holo_user.id),
|
||||||
|
msg.from_user.first_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_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_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}",
|
||||||
|
)
|
||||||
],
|
],
|
||||||
[
|
|
||||||
InlineKeyboardButton(text=str(locale("sub_russian", "button")), callback_data=f"sub_russian_{holo_user.id}")
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
logWrite(f"User {holo_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"
|
||||||
|
)
|
||||||
|
|
||||||
col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}})
|
col_tmp.update_one(
|
||||||
|
{"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}}
|
||||||
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if configGet("enabled", "features", "sponsorships") is True:
|
if configGet("enabled", "features", "sponsorships") is True:
|
||||||
|
if (kind == "sponsorship") or (
|
||||||
if (kind == "sponsorship") or ((holo_user.sponsorship_state()[0] == "fill") and (holo_user.sponsorship_state()[1] is True)):
|
(holo_user.sponsorship_state()[0] == "fill")
|
||||||
|
and (holo_user.sponsorship_state()[1] is True)
|
||||||
tmp_sponsorship = col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})
|
):
|
||||||
|
tmp_sponsorship = col_tmp.find_one(
|
||||||
|
{"user": holo_user.id, "type": "sponsorship"}
|
||||||
|
)
|
||||||
|
|
||||||
if tmp_sponsorship is None:
|
if tmp_sponsorship is None:
|
||||||
logWrite(f"Sponsorship of {holo_user.id} is nowhere to be found.")
|
logWrite(f"Sponsorship of {holo_user.id} is nowhere to be found.")
|
||||||
@ -104,58 +176,113 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s
|
|||||||
if tmp_sponsorship["sent"] is True:
|
if tmp_sponsorship["sent"] is True:
|
||||||
return
|
return
|
||||||
|
|
||||||
await msg.reply_text(locale("sponsorship_sent", "message"), reply_markup=ReplyKeyboardRemove())
|
await msg.reply_text(
|
||||||
|
locale("sponsorship_sent", "message"),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
|
||||||
sponsorship_content = []
|
sponsorship_content = []
|
||||||
|
|
||||||
for question in tmp_sponsorship['sponsorship']:
|
for question in tmp_sponsorship["sponsorship"]:
|
||||||
|
|
||||||
if question == "expires":
|
if question == "expires":
|
||||||
sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question].strftime('%d.%m.%Y')}")
|
sponsorship_content.append(
|
||||||
|
f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question].strftime('%d.%m.%Y')}"
|
||||||
|
)
|
||||||
elif question == "proof":
|
elif question == "proof":
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}")
|
sponsorship_content.append(
|
||||||
|
f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}"
|
||||||
|
)
|
||||||
|
|
||||||
await app.send_cached_media(chat_id=configGet("admin", "groups"), photo=tmp_sponsorship["sponsorship"]["proof"], caption=(locale("sponsor_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(sponsorship_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
|
await app.send_cached_media(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
tmp_sponsorship["sponsorship"]["proof"],
|
||||||
|
caption=(locale("sponsor_got", "message")).format(
|
||||||
|
str(holo_user.id),
|
||||||
|
msg.from_user.first_name,
|
||||||
|
msg.from_user.username,
|
||||||
|
"\n".join(sponsorship_content),
|
||||||
|
),
|
||||||
|
parse_mode=ParseMode.MARKDOWN,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text=str(locale("sponsor_yes", "button")), callback_data=f"sponsor_yes_{holo_user.id}")
|
InlineKeyboardButton(
|
||||||
|
text=str(locale("sponsor_yes", "button")),
|
||||||
|
callback_data=f"sponsor_yes_{holo_user.id}",
|
||||||
|
)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text=str(locale("sponsor_no", "button")), callback_data=f"sponsor_no_{holo_user.id}")
|
InlineKeyboardButton(
|
||||||
]
|
text=str(locale("sponsor_no", "button")),
|
||||||
|
callback_data=f"sponsor_no_{holo_user.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
]
|
]
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# remove(f"tmp{sep}{filename}.jpg")
|
# remove(f"tmp{sep}{filename}.jpg")
|
||||||
|
|
||||||
logWrite(f"User {holo_user.id} sent his sponsorship application and it will now be reviewed")
|
logWrite(
|
||||||
|
f"User {holo_user.id} sent his sponsorship application and it will now be reviewed"
|
||||||
|
)
|
||||||
|
|
||||||
col_tmp.update_one({"user": holo_user.id, "type": "sponsorship"}, {"$set": {"sent": True}})
|
col_tmp.update_one(
|
||||||
|
{"user": holo_user.id, "type": "sponsorship"}, {"$set": {"sent": True}}
|
||||||
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
confirmation_2 = []
|
confirmation_2 = []
|
||||||
for pattern in all_locales("confirm", "keyboard"):
|
for pattern in all_locales("confirm", "keyboard"):
|
||||||
confirmation_2.append(pattern[1][0])
|
confirmation_2.append(pattern[1][0])
|
||||||
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.private & filters.command(confirmation_2, prefixes=[""]))
|
|
||||||
async def confirm_no(app: Client, msg: Message, kind: Literal["application", "sponsorship", "unknown"] = "unknown"):
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
(custom_filters.enabled_applications | custom_filters.enabled_sponsorships)
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(confirmation_2, prefixes=[""])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def confirm_no(
|
||||||
|
app: Client,
|
||||||
|
msg: Message,
|
||||||
|
kind: Literal["application", "sponsorship", "unknown"] = "unknown",
|
||||||
|
):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
if configGet("enabled", "features", "applications") is True:
|
if configGet("enabled", "features", "applications") is True:
|
||||||
if (kind == "application") or ((holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True)):
|
if (kind == "application") or (
|
||||||
|
(holo_user.application_state()[0] == "fill")
|
||||||
|
and (holo_user.application_state()[1] is True)
|
||||||
|
):
|
||||||
holo_user.application_restart()
|
holo_user.application_restart()
|
||||||
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"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if configGet("enabled", "features", "sponsorships") is True:
|
if configGet("enabled", "features", "sponsorships") is True:
|
||||||
if (kind == "sponsorship") or ((holo_user.sponsorship_state()[0] == "fill") and (holo_user.sponsorship_state()[1] is True)):
|
if (kind == "sponsorship") or (
|
||||||
|
(holo_user.sponsorship_state()[0] == "fill")
|
||||||
|
and (holo_user.sponsorship_state()[1] is True)
|
||||||
|
):
|
||||||
holo_user.sponsorship_restart()
|
holo_user.sponsorship_restart()
|
||||||
await app.send_message(holo_user.id, locale(f"sponsor1", "message", locale=holo_user.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale))))
|
await app.send_message(
|
||||||
logWrite(f"User {msg.from_user.id} restarted the sponsorship application due to typo in it")
|
holo_user.id,
|
||||||
|
locale(f"sponsor1", "message", locale=holo_user.locale),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=str(
|
||||||
|
locale(f"sponsor1", "force_reply", locale=holo_user.locale)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {msg.from_user.id} restarted the sponsorship application due to typo in it"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
# ==============================================================================================================================
|
|
@ -9,46 +9,75 @@ from modules.database import col_applications
|
|||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Contact getting ==============================================================================================================
|
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.contact & filters.private & (custom_filters.allowed | custom_filters.admin))
|
|
||||||
async def get_contact(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.contact
|
||||||
|
& filters.private
|
||||||
|
& (custom_filters.allowed | custom_filters.admin)
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def get_contact(app: Client, msg: Message):
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
if msg.contact.user_id != None:
|
if msg.contact.user_id != None:
|
||||||
|
|
||||||
application = col_applications.find_one({"user": msg.contact.user_id})
|
application = col_applications.find_one({"user": msg.contact.user_id})
|
||||||
|
|
||||||
if application is None:
|
if application is None:
|
||||||
logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists")
|
logWrite(
|
||||||
await msg.reply_text(locale("contact_invalid", "message", locale=holo_user.locale))
|
f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("contact_invalid", "message", locale=holo_user.locale)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
application_content = []
|
application_content = []
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
for question in application['application']:
|
for question in application["application"]:
|
||||||
|
|
||||||
if i == 2:
|
if i == 2:
|
||||||
age = relativedelta(datetime.now(), application['application']['2'])
|
age = relativedelta(datetime.now(), application["application"]["2"])
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)"
|
||||||
|
)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
if application['application']['3']['countryCode'] == "UA":
|
if application["application"]["3"]["countryCode"] == "UA":
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application'][question]}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application'][question]}"
|
||||||
|
)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
application_status = locale("application_status_accepted", "message", locale=holo_user.locale).format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M"))
|
application_status = locale(
|
||||||
|
"application_status_accepted", "message", locale=holo_user.locale
|
||||||
|
).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}")
|
logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id}")
|
||||||
await msg.reply_text(locale("contact", "message", locale=holo_user.locale).format(str(msg.contact.user_id), "\n".join(application_content), application_status))
|
await msg.reply_text(
|
||||||
|
locale("contact", "message", locale=holo_user.locale).format(
|
||||||
|
str(msg.contact.user_id),
|
||||||
|
"\n".join(application_content),
|
||||||
|
application_status,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logWrite(f"User {holo_user.id} requested application of someone but user is not telegram user")
|
logWrite(
|
||||||
await msg.reply_text(locale("contact_not_member", "message", locale=holo_user.locale))
|
f"User {holo_user.id} requested application of someone but user is not telegram user"
|
||||||
# ==============================================================================================================================
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("contact_not_member", "message", locale=holo_user.locale)
|
||||||
|
)
|
||||||
|
@ -1,44 +1,68 @@
|
|||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
from app import app, isAnAdmin
|
from app import app, isAnAdmin
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from ftfy import fix_text
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import Message, ForceReply, InlineKeyboardMarkup, InlineKeyboardButton
|
from pyrogram.types import (
|
||||||
|
Message,
|
||||||
|
ForceReply,
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ReplyKeyboardRemove,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import configGet, logWrite, locale, all_locales
|
from modules.utils import configGet, logWrite, locale, all_locales
|
||||||
from modules.database import col_messages, col_spoilers
|
from modules.database import col_messages, col_spoilers
|
||||||
|
from modules import custom_filters
|
||||||
|
|
||||||
|
|
||||||
async def message_involved(msg: Message) -> bool:
|
async def message_involved(msg: Message) -> bool:
|
||||||
message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id})
|
message = col_messages.find_one(
|
||||||
|
{
|
||||||
|
"destination.id": msg.reply_to_message.id,
|
||||||
|
"destination.chat": msg.reply_to_message.chat.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
if message is not None:
|
if message is not None:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def message_context(msg: Message) -> tuple:
|
async def message_context(msg: Message) -> tuple:
|
||||||
message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id})
|
message = col_messages.find_one(
|
||||||
|
{
|
||||||
|
"destination.id": msg.reply_to_message.id,
|
||||||
|
"destination.chat": msg.reply_to_message.chat.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
if message is not None:
|
if message is not None:
|
||||||
return message["origin"]["chat"], message["origin"]["id"]
|
return message["origin"]["chat"], message["origin"]["id"]
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
# Any other input ==============================================================================================================
|
|
||||||
@app.on_message(~ filters.scheduled & filters.private)
|
@app.on_message(
|
||||||
|
~filters.scheduled
|
||||||
|
& (filters.private | filters.chat(configGet("admin", "groups")))
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
async def any_stage(app: Client, msg: Message):
|
async def any_stage(app: Client, msg: Message):
|
||||||
|
|
||||||
if msg.via_bot is None:
|
if msg.via_bot is None:
|
||||||
|
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
if (msg.reply_to_message is not None) and (await message_involved(msg)):
|
if (msg.reply_to_message is not None) and (await message_involved(msg)):
|
||||||
|
|
||||||
context = await message_context(msg)
|
context = await message_context(msg)
|
||||||
context_message = await app.get_messages(context[0], context[1])
|
context_message = await app.get_messages(context[0], context[1])
|
||||||
|
|
||||||
destination_user = HoloUser(context_message.from_user)
|
destination_user = HoloUser(context_message.from_user)
|
||||||
|
|
||||||
|
if destination_user is None:
|
||||||
|
return
|
||||||
|
|
||||||
await destination_user.message(
|
await destination_user.message(
|
||||||
origin=context_message,
|
origin=context_message,
|
||||||
context=msg,
|
context=msg,
|
||||||
text=msg.text,
|
text=str(msg.text),
|
||||||
caption=msg.caption,
|
caption=msg.caption,
|
||||||
photo=msg.photo,
|
photo=msg.photo,
|
||||||
video=msg.video,
|
video=msg.video,
|
||||||
@ -46,115 +70,324 @@ async def any_stage(app: Client, msg: Message):
|
|||||||
animation=msg.animation,
|
animation=msg.animation,
|
||||||
voice=msg.voice,
|
voice=msg.voice,
|
||||||
adm_origin=await isAnAdmin(context_message.from_user.id),
|
adm_origin=await isAnAdmin(context_message.from_user.id),
|
||||||
adm_context=await isAnAdmin(msg.from_user.id)
|
adm_context=await isAnAdmin(msg.from_user.id),
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if msg.text is not None:
|
if msg.chat.id == configGet("admin", "groups"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if msg.text is not None:
|
||||||
if configGet("enabled", "features", "applications") is True:
|
if configGet("enabled", "features", "applications") is True:
|
||||||
await holo_user.application_next(msg.text, msg=msg)
|
await holo_user.application_next(str(msg.text), msg=msg)
|
||||||
|
|
||||||
if configGet("enabled", "features", "sponsorships") is True:
|
if configGet("enabled", "features", "sponsorships") is True:
|
||||||
|
await holo_user.sponsorship_next(str(msg.text), msg)
|
||||||
await holo_user.sponsorship_next(msg.text, msg)
|
|
||||||
|
|
||||||
if msg.photo is not None:
|
if msg.photo is not None:
|
||||||
await holo_user.sponsorship_next(msg.text, msg=msg, photo=msg.photo)
|
await holo_user.sponsorship_next(str(msg.text), msg=msg, photo=msg.photo)
|
||||||
|
|
||||||
if holo_user.application_state()[0] != "fill" and holo_user.sponsorship_state()[0] != "fill":
|
if (
|
||||||
|
holo_user.application_state()[0] != "fill"
|
||||||
|
and holo_user.sponsorship_state()[0] != "fill"
|
||||||
|
):
|
||||||
|
if configGet("enabled", "features", "spoilers") is False:
|
||||||
|
return
|
||||||
|
|
||||||
spoiler = col_spoilers.find_one( {"user": msg.from_user.id, "completed": False} )
|
spoiler = col_spoilers.find_one(
|
||||||
|
{"user": msg.from_user.id, "completed": False}
|
||||||
|
)
|
||||||
|
|
||||||
if spoiler is None:
|
if spoiler is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if spoiler["category"] is None:
|
if spoiler["category"] is None:
|
||||||
|
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
# Find category in all locales
|
# Find category in all locales
|
||||||
for lc in all_locales("spoiler_categories", "message"):
|
for lc in all_locales("spoiler_categories", "message"):
|
||||||
for key in lc:
|
for key in lc:
|
||||||
if lc[key] == msg.text:
|
if lc[key] == str(msg.text):
|
||||||
found = True
|
found = True
|
||||||
category = key
|
category = key
|
||||||
|
|
||||||
if found is False:
|
if found is False:
|
||||||
await msg.reply_text(locale("spoiler_incorrect_category", "message", locale=msg.from_user))
|
await msg.reply_text(
|
||||||
|
locale(
|
||||||
|
"spoiler_incorrect_category",
|
||||||
|
"message",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
col_spoilers.find_one_and_update( {"_id": spoiler["_id"]}, {"$set": {"category": category}} )
|
col_spoilers.find_one_and_update(
|
||||||
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
|
{"_id": spoiler["_id"]}, {"$set": {"category": category}}
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("spoiler_send_description", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=locale(
|
||||||
|
"spoiler_description", "force_reply", locale=msg.from_user
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if spoiler["description"] is None and (spoiler["photo"] is None and spoiler["video"] is None and spoiler["animation"] is None and spoiler["text"] is None):
|
if spoiler["description"] is None and (
|
||||||
|
spoiler["photo"] is None
|
||||||
|
and spoiler["video"] is None
|
||||||
|
and spoiler["audio"] is None
|
||||||
|
and spoiler["animation"] is None
|
||||||
|
and spoiler["text"] is None
|
||||||
|
):
|
||||||
# for lc in all_locales("spoiler_description", "keyboard"):
|
# for lc in all_locales("spoiler_description", "keyboard"):
|
||||||
# if msg.text == lc[-1][0]:
|
# if msg.text == lc[-1][0]:
|
||||||
# await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
|
# await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
|
||||||
# return
|
# return
|
||||||
|
|
||||||
if msg.text != "-":
|
msg.text = fix_text(str(msg.text))
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": msg.text}} )
|
if len(str(msg.text)) > 1024:
|
||||||
else:
|
await msg.reply_text(
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": ""}} )
|
locale(
|
||||||
|
"spoiler_description_too_long",
|
||||||
|
"message",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=locale(
|
||||||
|
"spoiler_description",
|
||||||
|
"force_reply",
|
||||||
|
locale=msg.from_user,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
col_spoilers.find_one_and_update(
|
||||||
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{"$set": {"description": msg.text}},
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"Adding description '{msg.text}' to {msg.from_user.id}'s spoiler")
|
logWrite(
|
||||||
await msg.reply_text(locale("spoiler_using_description", "message", locale=msg.from_user).format(msg.text), reply_markup=ForceReply(placeholder=locale("spoiler_content", "force_reply", locale=msg.from_user)))
|
f"Adding description '{str(msg.text)}' to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale(
|
||||||
|
"spoiler_using_description", "message", locale=msg.from_user
|
||||||
|
).format(msg.text),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=locale(
|
||||||
|
"spoiler_content", "force_reply", locale=msg.from_user
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
ready = False
|
ready = False
|
||||||
|
|
||||||
if msg.photo is not None:
|
if msg.photo is not None:
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"photo": msg.photo.file_id, "caption": msg.caption, "completed": True}} )
|
col_spoilers.find_one_and_update(
|
||||||
logWrite(f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler")
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"photo": msg.photo.file_id,
|
||||||
|
"caption": msg.caption,
|
||||||
|
"completed": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
ready = True
|
ready = True
|
||||||
|
|
||||||
if msg.video is not None:
|
if msg.video is not None:
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"video": msg.video.file_id, "caption": msg.caption, "completed": True}} )
|
col_spoilers.find_one_and_update(
|
||||||
logWrite(f"Adding video with id {msg.video.file_id} to {msg.from_user.id}'s spoiler")
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"video": msg.video.file_id,
|
||||||
|
"caption": msg.caption,
|
||||||
|
"completed": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding audio with id {msg.video.file_id} to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
|
ready = True
|
||||||
|
|
||||||
|
if msg.audio is not None:
|
||||||
|
col_spoilers.find_one_and_update(
|
||||||
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"audio": msg.audio.file_id,
|
||||||
|
"caption": msg.caption,
|
||||||
|
"completed": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding video with id {msg.audio.file_id} to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
ready = True
|
ready = True
|
||||||
|
|
||||||
if msg.animation is not None:
|
if msg.animation is not None:
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"animation": msg.animation.file_id, "caption": msg.caption, "completed": True}} )
|
col_spoilers.find_one_and_update(
|
||||||
logWrite(f"Adding animation with id {msg.animation.file_id} to {msg.from_user.id}'s spoiler")
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"animation": msg.animation.file_id,
|
||||||
|
"caption": msg.caption,
|
||||||
|
"completed": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding animation with id {msg.animation.file_id} to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
ready = True
|
ready = True
|
||||||
|
|
||||||
if msg.document is not None:
|
if msg.document is not None:
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"document": msg.document.file_id, "caption": msg.caption, "completed": True}} )
|
col_spoilers.find_one_and_update(
|
||||||
logWrite(f"Adding document with id {msg.document.file_id} to {msg.from_user.id}'s spoiler")
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"document": msg.document.file_id,
|
||||||
|
"caption": msg.caption,
|
||||||
|
"completed": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding document with id {msg.document.file_id} to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
ready = True
|
ready = True
|
||||||
|
|
||||||
if spoiler["photo"] is None and spoiler["video"] is None and spoiler["animation"] is None and spoiler["document"] is None and spoiler["text"] is None:
|
if (
|
||||||
|
spoiler["photo"] is None
|
||||||
|
and spoiler["video"] is None
|
||||||
|
and spoiler["audio"] is None
|
||||||
|
and spoiler["animation"] is None
|
||||||
|
and spoiler["document"] is None
|
||||||
|
and spoiler["text"] is None
|
||||||
|
):
|
||||||
if msg.text is not None:
|
if msg.text is not None:
|
||||||
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"text": msg.text, "completed": True}} )
|
col_spoilers.find_one_and_update(
|
||||||
logWrite(f"Adding text '{msg.text}' to {msg.from_user.id}'s spoiler")
|
{"user": msg.from_user.id, "completed": False},
|
||||||
|
{"$set": {"text": str(msg.text), "completed": True}},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"Adding text '{str(msg.text)}' to {msg.from_user.id}'s spoiler"
|
||||||
|
)
|
||||||
ready = True
|
ready = True
|
||||||
|
|
||||||
if ready is True:
|
if ready is True:
|
||||||
await msg.reply_text(locale("spoiler_ready", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_send", "button", locale=msg.from_user), switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}")]]))
|
await msg.reply_text(
|
||||||
|
locale("spoiler_ready", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
if configGet("allow_external", "features", "spoilers") is True:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("spoiler_send", "message", locale=msg.from_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_preview",
|
||||||
|
"button",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
callback_data=f"sid_{spoiler['_id'].__str__()}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_send_chat",
|
||||||
|
"button",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
callback_data=f"shc_{spoiler['_id'].__str__()}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_send_other",
|
||||||
|
"button",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("spoiler_send", "message", locale=msg.from_user),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_preview",
|
||||||
|
"button",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
callback_data=f"sid_{spoiler['_id'].__str__()}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_send_chat",
|
||||||
|
"button",
|
||||||
|
locale=msg.from_user,
|
||||||
|
),
|
||||||
|
callback_data=f"shc_{spoiler['_id'].__str__()}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await msg.reply_text(locale("spoiler_incorrect_content", "message", locale=msg.from_user))
|
await msg.reply_text(
|
||||||
|
locale("spoiler_incorrect_content", "message", locale=msg.from_user)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.on_message(~ filters.scheduled & filters.group)
|
@app.on_message(~filters.scheduled & filters.group)
|
||||||
async def message_in_group(app: Client, msg: Message):
|
async def message_in_group(app: Client, msg: Message):
|
||||||
if (msg.chat is not None) and (msg.via_bot is not None):
|
if (msg.chat is not None) and (msg.via_bot is not None):
|
||||||
if (msg.via_bot.id == (await app.get_me()).id) and (msg.chat.id == configGet("users", "groups")):
|
if (msg.via_bot.id == (await app.get_me()).id) and (
|
||||||
if msg.text.startswith(locale("spoiler_described", "message").split()[0]) or msg.text.startswith(locale("spoiler_empty", "message").split()[0]):
|
msg.chat.id == configGet("users", "groups")
|
||||||
|
):
|
||||||
|
if str(msg.text).startswith(
|
||||||
|
locale("spoiler_described", "message").split()[0]
|
||||||
|
):
|
||||||
logWrite(f"User {msg.from_user.id} sent spoiler to user's group")
|
logWrite(f"User {msg.from_user.id} sent spoiler to user's group")
|
||||||
try:
|
try:
|
||||||
logWrite("Forwarding spoiler to admin's group")
|
logWrite("Forwarding spoiler to admin's group")
|
||||||
await msg.copy(configGet("admin", "groups"), disable_notification=True)
|
await msg.copy(
|
||||||
|
configGet("admin", "groups"), disable_notification=True
|
||||||
|
)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not forward spoiler to admin's group due to '{exp}': {print_exc()}")
|
logWrite(
|
||||||
|
f"Could not forward spoiler to admin's group due to '{exp}': {print_exc()}"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
if configGet("remove_application_time") > 0:
|
if configGet("remove_application_time") > 0:
|
||||||
logWrite(f"User {msg.from_user.id} requested application in destination group, removing in {configGet('remove_application_time')} minutes")
|
logWrite(
|
||||||
await asyncio.sleep(configGet("remove_application_time")*60)
|
f"User {msg.from_user.id} requested application in destination group, removing in {configGet('remove_application_time')} minutes"
|
||||||
|
)
|
||||||
|
await asyncio.sleep(configGet("remove_application_time") * 60)
|
||||||
await msg.delete()
|
await msg.delete()
|
||||||
logWrite(f"Removed application requested by {msg.from_user.id} in destination group")
|
logWrite(
|
||||||
# ==============================================================================================================================
|
f"Removed application requested by {msg.from_user.id} in destination group"
|
||||||
|
)
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
from app import app, isAnAdmin
|
|
||||||
from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton, ChatMemberUpdated
|
|
||||||
from pyrogram.client import Client
|
|
||||||
from modules.utils import configGet, locale
|
|
||||||
from modules.logging import logWrite
|
|
||||||
from classes.holo_user import HoloUser
|
|
||||||
from modules import custom_filters
|
|
||||||
|
|
||||||
# Filter users on join =========================================================================================================
|
|
||||||
@app.on_chat_member_updated(custom_filters.enabled_invites_check, group=configGet("users", "groups"))
|
|
||||||
#@app.on_message(filters.new_chat_members, group=configGet("users", "groups"))
|
|
||||||
async def filter_join(app: Client, member: ChatMemberUpdated):
|
|
||||||
|
|
||||||
if member.invite_link != None:
|
|
||||||
|
|
||||||
holo_user = HoloUser(member.from_user)
|
|
||||||
|
|
||||||
if (holo_user.link is not None) and (holo_user.link == member.invite_link.invite_link):
|
|
||||||
logWrite(f"User {holo_user.id} joined destination group with correct link {holo_user.link}")
|
|
||||||
return
|
|
||||||
|
|
||||||
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", "groups"), 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_reject", "button")), callback_data=f"sus_reject_{member.from_user.id}")
|
|
||||||
]
|
|
||||||
]
|
|
||||||
))
|
|
||||||
await app.restrict_chat_member(member.chat.id, member.from_user.id, permissions=ChatPermissions(
|
|
||||||
can_send_messages=False,
|
|
||||||
can_send_media_messages=False,
|
|
||||||
can_send_other_messages=False,
|
|
||||||
can_send_polls=False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# ==============================================================================================================================
|
|
164
modules/handlers/group_member_update.py
Normal file
164
modules/handlers/group_member_update.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from app import app, isAnAdmin
|
||||||
|
from pyrogram.types import (
|
||||||
|
ChatPermissions,
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
ChatMemberUpdated,
|
||||||
|
)
|
||||||
|
from pyrogram.client import Client
|
||||||
|
from modules.utils import configGet, locale
|
||||||
|
from modules import custom_filters
|
||||||
|
from modules.logging import logWrite
|
||||||
|
from modules.database import col_applications
|
||||||
|
from classes.holo_user import HoloUser
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_chat_member_updated(
|
||||||
|
custom_filters.enabled_invites_check, group=configGet("users", "groups")
|
||||||
|
)
|
||||||
|
# @app.on_message(filters.new_chat_members, group=configGet("users", "groups"))
|
||||||
|
async def filter_join(app: Client, member: ChatMemberUpdated):
|
||||||
|
if member.invite_link != None:
|
||||||
|
holo_user = HoloUser(member.from_user)
|
||||||
|
|
||||||
|
if (holo_user.link is not None) and (
|
||||||
|
holo_user.link == member.invite_link.invite_link
|
||||||
|
):
|
||||||
|
logWrite(
|
||||||
|
f"User {holo_user.id} joined destination group with correct link {holo_user.link}"
|
||||||
|
)
|
||||||
|
|
||||||
|
application = col_applications.find_one({"user": holo_user.id})
|
||||||
|
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
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
locale("joined_application", "message").format(
|
||||||
|
member.from_user.first_name,
|
||||||
|
member.from_user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
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}"
|
||||||
|
)
|
||||||
|
|
||||||
|
application = col_applications.find_one({"user": holo_user.id})
|
||||||
|
|
||||||
|
if application is None:
|
||||||
|
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
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
locale("joined_application", "message").format(
|
||||||
|
member.from_user.first_name,
|
||||||
|
member.from_user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
logWrite(
|
||||||
|
f"User {holo_user.id} joined destination group with stolen/unapproved link {holo_user.link}"
|
||||||
|
)
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
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_reject", "button")),
|
||||||
|
callback_data=f"sus_reject_{member.from_user.id}",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await app.restrict_chat_member(
|
||||||
|
member.chat.id,
|
||||||
|
member.from_user.id,
|
||||||
|
permissions=ChatPermissions(
|
||||||
|
can_send_messages=False,
|
||||||
|
can_send_media_messages=False,
|
||||||
|
can_send_other_messages=False,
|
||||||
|
can_send_polls=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if member.new_chat_member is None:
|
||||||
|
await app.send_message(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
locale("user_left", "message").format(
|
||||||
|
member.old_chat_member.user.first_name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f"User {member.old_chat_member.user.first_name} ({member.old_chat_member.user.id}) left the destination group"
|
||||||
|
)
|
||||||
|
return
|
@ -7,7 +7,13 @@ from modules.logging import logWrite
|
|||||||
from modules.utils import configGet, locale
|
from modules.utils import configGet, locale
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
@app.on_message(custom_filters.enabled_dinovoice & ~filters.scheduled & filters.voice & filters.chat(configGet("users", "groups")))
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_dinovoice
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.voice
|
||||||
|
& filters.chat(configGet("users", "groups"))
|
||||||
|
)
|
||||||
async def voice_message(app: Client, msg: Message):
|
async def voice_message(app: Client, msg: Message):
|
||||||
logWrite(f"User {msg.from_user.id} sent voice message in destination group")
|
logWrite(f"User {msg.from_user.id} sent voice message in destination group")
|
||||||
await msg.reply_text(choice(locale("voice_message", "message")))
|
await msg.reply_text(choice(locale("voice_message", "message")))
|
@ -6,14 +6,21 @@ from classes.holo_user import HoloUser
|
|||||||
from modules.utils import all_locales, locale, logWrite
|
from modules.utils import all_locales, locale, logWrite
|
||||||
from modules import custom_filters
|
from modules import custom_filters
|
||||||
|
|
||||||
# Welcome check ================================================================================================================
|
|
||||||
welcome_1 = []
|
welcome_1 = []
|
||||||
for pattern in all_locales("welcome", "keyboard"):
|
for pattern in all_locales("welcome", "keyboard"):
|
||||||
welcome_1.append(pattern[0][0])
|
welcome_1.append(pattern[0][0])
|
||||||
for pattern in all_locales("return", "keyboard"):
|
for pattern in all_locales("return", "keyboard"):
|
||||||
welcome_1.append(pattern[0][0])
|
welcome_1.append(pattern[0][0])
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(welcome_1, prefixes=[""]))
|
|
||||||
async def welcome_pass(app: Client, msg: Message, once_again: bool = True) -> None:
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(welcome_1, prefixes=[""])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def welcome_pass(app: Client, msg: Message, once_again: bool = False) -> None:
|
||||||
"""Set user's stage to 1 and start a fresh application
|
"""Set user's stage to 1 and start a fresh application
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
@ -27,17 +34,40 @@ async def welcome_pass(app: Client, msg: Message, once_again: bool = True) -> No
|
|||||||
|
|
||||||
holo_user = HoloUser(msg.from_user)
|
holo_user = HoloUser(msg.from_user)
|
||||||
|
|
||||||
holo_user.application_restart()
|
if once_again is False:
|
||||||
|
holo_user.application_restart()
|
||||||
|
|
||||||
|
if once_again is True:
|
||||||
|
logWrite(f"User {msg.from_user.id} confirmed starting the application")
|
||||||
|
else:
|
||||||
|
logWrite(
|
||||||
|
f"User {msg.from_user.id} confirmed starting the application once again"
|
||||||
|
)
|
||||||
|
await msg.reply_text(
|
||||||
|
locale("question1", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ForceReply(
|
||||||
|
placeholder=locale("question1", "force_reply", locale=msg.from_user)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
logWrite(f"User {msg.from_user.id} confirmed starting the application")
|
|
||||||
await msg.reply_text(locale("question1", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("question1", "force_reply", locale=msg.from_user)))
|
|
||||||
|
|
||||||
welcome_2 = []
|
welcome_2 = []
|
||||||
for pattern in all_locales("welcome", "keyboard"):
|
for pattern in all_locales("welcome", "keyboard"):
|
||||||
welcome_2.append(pattern[1][0])
|
welcome_2.append(pattern[1][0])
|
||||||
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(welcome_2, prefixes=[""]))
|
|
||||||
async def welcome_reject(app: Client, msg: Message):
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_message(
|
||||||
|
custom_filters.enabled_applications
|
||||||
|
& ~filters.scheduled
|
||||||
|
& filters.private
|
||||||
|
& filters.command(welcome_2, prefixes=[""])
|
||||||
|
& ~custom_filters.banned
|
||||||
|
)
|
||||||
|
async def welcome_reject(app: Client, msg: Message):
|
||||||
logWrite(f"User {msg.from_user.id} rejected to start the application")
|
logWrite(f"User {msg.from_user.id} rejected to start the application")
|
||||||
await msg.reply_text(locale("goodbye", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("return", "keyboard", locale=msg.from_user), resize_keyboard=True))
|
await msg.reply_text(
|
||||||
# ==============================================================================================================================
|
locale("goodbye", "message", locale=msg.from_user),
|
||||||
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
|
locale("return", "keyboard", locale=msg.from_user), resize_keyboard=True
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -4,92 +4,168 @@ all inline queries that bot receives"""
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from os import path, sep
|
from os import path, sep
|
||||||
from app import app, isAnAdmin
|
from app import app, isAnAdmin
|
||||||
from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent, InlineQuery, InlineKeyboardMarkup, InlineKeyboardButton
|
from pyrogram.types import (
|
||||||
|
InlineQueryResultArticle,
|
||||||
|
InputTextMessageContent,
|
||||||
|
InlineQuery,
|
||||||
|
InlineKeyboardMarkup,
|
||||||
|
InlineKeyboardButton,
|
||||||
|
)
|
||||||
from pyrogram.client import Client
|
from pyrogram.client import Client
|
||||||
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.errors.holo_user import UserNotFoundError, UserInvalidError
|
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import configGet, locale
|
from modules.logging import logWrite
|
||||||
|
from modules.utils import configGet, jsonLoad, locale
|
||||||
from modules.database import col_applications, col_spoilers
|
from modules.database import col_applications, col_spoilers
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
from bson.errors import InvalidId
|
from bson.errors import InvalidId
|
||||||
|
|
||||||
|
|
||||||
@app.on_inline_query()
|
@app.on_inline_query()
|
||||||
async def inline_answer(client: Client, inline_query: InlineQuery):
|
async def inline_answer(client: Client, inline_query: InlineQuery):
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
if inline_query.query.startswith("spoiler:"):
|
if configGet("allow_external", "features", "spoilers") is True:
|
||||||
|
if inline_query.query.startswith("spoiler:"):
|
||||||
|
try:
|
||||||
|
spoil = col_spoilers.find_one(
|
||||||
|
{"_id": ObjectId(inline_query.query.removeprefix("spoiler:"))}
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
if spoil is not None:
|
||||||
|
desc = locale(
|
||||||
spoil = col_spoilers.find_one( {"_id": ObjectId(inline_query.query.removeprefix("spoiler:"))} )
|
"spoiler_described",
|
||||||
|
"message",
|
||||||
if spoil is not None:
|
locale=inline_query.from_user,
|
||||||
|
).format(
|
||||||
desc = locale("spoiler_empty", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories")) if spoil["description"] == "" else locale("spoiler_described", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories"), spoil["description"])
|
locale(spoil["category"], "message", "spoiler_categories"),
|
||||||
|
spoil["description"],
|
||||||
results = [
|
|
||||||
InlineQueryResultArticle(
|
|
||||||
title=locale("title", "inline", "spoiler", locale=inline_query.from_user),
|
|
||||||
description=locale("description", "inline", "spoiler", locale=inline_query.from_user),
|
|
||||||
input_message_content=InputTextMessageContent(desc, disable_web_page_preview=True),
|
|
||||||
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_view", "button", locale=inline_query.from_user), callback_data=f'sid_{inline_query.query.removeprefix("spoiler:")}')]])
|
|
||||||
)
|
)
|
||||||
]
|
|
||||||
|
|
||||||
except InvalidId:
|
results = [
|
||||||
results = []
|
InlineQueryResultArticle(
|
||||||
|
title=locale(
|
||||||
|
"title",
|
||||||
|
"inline",
|
||||||
|
"spoiler",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
),
|
||||||
|
description=locale(
|
||||||
|
"description",
|
||||||
|
"inline",
|
||||||
|
"spoiler",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
),
|
||||||
|
input_message_content=InputTextMessageContent(
|
||||||
|
desc, disable_web_page_preview=True
|
||||||
|
),
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(
|
||||||
|
locale(
|
||||||
|
"spoiler_view",
|
||||||
|
"button",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
),
|
||||||
|
callback_data=f'sid_{inline_query.query.removeprefix("spoiler:")}',
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
except InvalidId:
|
||||||
|
results = []
|
||||||
|
|
||||||
await inline_query.answer(
|
await inline_query.answer(results=results)
|
||||||
results=results
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if inline_query.chat_type in [ChatType.CHANNEL]:
|
if inline_query.chat_type in [ChatType.CHANNEL]:
|
||||||
await inline_query.answer(
|
await inline_query.answer(
|
||||||
results=[
|
results=[
|
||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
title=locale("title", "inline", "not_pm", locale=inline_query.from_user),
|
title=locale(
|
||||||
input_message_content=InputTextMessageContent(
|
"title", "inline", "not_pm", locale=inline_query.from_user
|
||||||
locale("message_content", "inline", "not_pm", locale=inline_query.from_user)
|
),
|
||||||
),
|
input_message_content=InputTextMessageContent(
|
||||||
description=locale("description", "inline", "not_pm", locale=inline_query.from_user)
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"not_pm",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
description=locale(
|
||||||
|
"description", "inline", "not_pm", locale=inline_query.from_user
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
results_forbidden = [
|
||||||
|
InlineQueryResultArticle(
|
||||||
|
title=locale("title", "inline", "forbidden", locale=inline_query.from_user),
|
||||||
|
input_message_content=InputTextMessageContent(
|
||||||
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"forbidden",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
description=locale(
|
||||||
|
"description", "inline", "forbidden", locale=inline_query.from_user
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
holo_user = HoloUser(inline_query.from_user)
|
holo_user = HoloUser(inline_query.from_user)
|
||||||
except (UserNotFoundError, UserInvalidError):
|
except (UserNotFoundError, UserInvalidError):
|
||||||
await inline_query.answer(
|
logWrite(
|
||||||
results=[
|
f"Could not find application of {inline_query.from_user.id}, ignoring inline query",
|
||||||
InlineQueryResultArticle(
|
debug=True,
|
||||||
title=locale("title", "inline", "forbidden", locale=inline_query.from_user),
|
|
||||||
input_message_content=InputTextMessageContent(
|
|
||||||
locale("message_content", "inline", "forbidden", locale=inline_query.from_user)
|
|
||||||
),
|
|
||||||
description=locale("description", "inline", "forbidden", locale=inline_query.from_user)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
await inline_query.answer(results=results_forbidden)
|
||||||
return
|
return
|
||||||
|
|
||||||
if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True):
|
if path.exists(path.join(configGet("cache", "locations"), "group_members")) and (
|
||||||
|
inline_query.from_user.id
|
||||||
|
not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))
|
||||||
|
):
|
||||||
|
if path.exists(path.join(configGet("cache", "locations"), "admins")) and (
|
||||||
|
inline_query.from_user.id
|
||||||
|
not in jsonLoad(path.join(configGet("cache", "locations"), "admins"))
|
||||||
|
):
|
||||||
|
logWrite(
|
||||||
|
f"{inline_query.from_user.id} is not an admin and not in members group, ignoring inline query",
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
await inline_query.answer(results=results_forbidden)
|
||||||
|
return
|
||||||
|
|
||||||
max_results = configGet("inline_preview_count") if inline_query.query != "" else 200
|
if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True):
|
||||||
|
max_results = (
|
||||||
|
configGet("inline_preview_count") if inline_query.query != "" else 200
|
||||||
|
)
|
||||||
|
|
||||||
list_of_users = []
|
list_of_users = []
|
||||||
async for m in app.get_chat_members(configGet("users", "groups"), limit=max_results, filter=ChatMembersFilter.SEARCH, query=inline_query.query):
|
async for m in app.get_chat_members(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
limit=max_results,
|
||||||
|
filter=ChatMembersFilter.SEARCH,
|
||||||
|
query=inline_query.query,
|
||||||
|
):
|
||||||
list_of_users.append(m)
|
list_of_users.append(m)
|
||||||
|
|
||||||
for match in list_of_users:
|
for match in list_of_users:
|
||||||
|
|
||||||
application = col_applications.find_one({"user": match.user.id})
|
application = col_applications.find_one({"user": match.user.id})
|
||||||
|
|
||||||
if application is None:
|
if application is None:
|
||||||
@ -98,34 +174,63 @@ async def inline_answer(client: Client, inline_query: InlineQuery):
|
|||||||
application_content = []
|
application_content = []
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
for question in application['application']:
|
for question in application["application"]:
|
||||||
|
|
||||||
if i == 2:
|
if i == 2:
|
||||||
age = relativedelta(datetime.now(), application['application']['2'])
|
age = relativedelta(datetime.now(), application["application"]["2"])
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)"
|
||||||
|
)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
if application['application']['3']['countryCode'] == "UA":
|
if application["application"]["3"]["countryCode"] == "UA":
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application'][question]}")
|
application_content.append(
|
||||||
|
f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application'][question]}"
|
||||||
|
)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if match.user.photo != None:
|
if match.user.photo != None:
|
||||||
try:
|
try:
|
||||||
if not path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}'):
|
if not path.exists(
|
||||||
print(f'Downloaded avatar {match.user.photo.big_file_id} of {match.user.id} and uploaded to {configGet("api")}/?avatar_id={match.user.photo.big_file_id}', flush=True)
|
f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}'
|
||||||
await app.download_media(match.user.photo.big_file_id, file_name=f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}')
|
):
|
||||||
|
print(
|
||||||
|
f'Downloaded avatar {match.user.photo.big_file_id} of {match.user.id} and uploaded to {configGet("api")}/avatars/{match.user.photo.big_file_id}',
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
await app.download_media(
|
||||||
|
match.user.photo.big_file_id,
|
||||||
|
file_name=f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}',
|
||||||
|
)
|
||||||
results.append(
|
results.append(
|
||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
title=str(match.user.first_name),
|
title=str(match.user.first_name),
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content))
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(
|
||||||
|
match.user.first_name,
|
||||||
|
match.user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username),
|
description=locale(
|
||||||
thumb_url=f'{configGet("api")}/?avatar_id={match.user.photo.big_file_id}'
|
"description",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(match.user.first_name, match.user.username),
|
||||||
|
thumb_url=f'{configGet("api")}/avatars/{match.user.photo.big_file_id}',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -133,9 +238,23 @@ async def inline_answer(client: Client, inline_query: InlineQuery):
|
|||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
title=str(match.user.first_name),
|
title=str(match.user.first_name),
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content))
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(
|
||||||
|
match.user.first_name,
|
||||||
|
match.user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username)
|
description=locale(
|
||||||
|
"description",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(match.user.first_name, match.user.username),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@ -143,9 +262,23 @@ async def inline_answer(client: Client, inline_query: InlineQuery):
|
|||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
title=str(match.user.first_name),
|
title=str(match.user.first_name),
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content))
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(
|
||||||
|
match.user.first_name,
|
||||||
|
match.user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username)
|
description=locale(
|
||||||
|
"description",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(match.user.first_name, match.user.username),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -153,13 +286,24 @@ async def inline_answer(client: Client, inline_query: InlineQuery):
|
|||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
title=str(match.user.first_name),
|
title=str(match.user.first_name),
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content))
|
locale(
|
||||||
|
"message_content",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(
|
||||||
|
match.user.first_name,
|
||||||
|
match.user.username,
|
||||||
|
"\n".join(application_content),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username)
|
description=locale(
|
||||||
|
"description",
|
||||||
|
"inline",
|
||||||
|
"user",
|
||||||
|
locale=inline_query.from_user,
|
||||||
|
).format(match.user.first_name, match.user.username),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
await inline_query.answer(
|
await inline_query.answer(results=results, cache_time=10, is_personal=True)
|
||||||
results=results,
|
|
||||||
cache_time=10
|
|
||||||
)
|
|
||||||
|
@ -5,12 +5,13 @@ from shutil import copyfileobj
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
with open(getcwd()+path.sep+"config.json", "r", encoding='utf8') as file:
|
with open(getcwd() + path.sep + "config.json", "r", encoding="utf8") as file:
|
||||||
json_contents = loads(file.read())
|
json_contents = loads(file.read())
|
||||||
log_size = json_contents["logging"]["size"]
|
log_size = json_contents["logging"]["size"]
|
||||||
log_folder = json_contents["logging"]["location"]
|
log_folder = json_contents["logging"]["location"]
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
# 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
|
"""Check size of latest.log file and rotate it if needed
|
||||||
@ -30,15 +31,24 @@ def checkSize(debug=False):
|
|||||||
makedirs(log_folder, exist_ok=True)
|
makedirs(log_folder, exist_ok=True)
|
||||||
log = stat(path.join(log_folder, log_file))
|
log = stat(path.join(log_folder, log_file))
|
||||||
if (log.st_size / 1024) > log_size:
|
if (log.st_size / 1024) > log_size:
|
||||||
with open(path.join(log_folder, log_file), 'rb') as f_in:
|
with open(path.join(log_folder, log_file), "rb") as f_in:
|
||||||
with gzipopen(path.join(log_folder, f'{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.log.gz'), 'wb') as f_out:
|
with gzipopen(
|
||||||
|
path.join(
|
||||||
|
log_folder,
|
||||||
|
f'{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.log.gz',
|
||||||
|
),
|
||||||
|
"wb",
|
||||||
|
) as f_out:
|
||||||
copyfileobj(f_in, f_out)
|
copyfileobj(f_in, f_out)
|
||||||
print(f'Copied {path.join(log_folder, datetime.now().strftime("%d.%m.%Y_%H:%M:%S"))}.log.gz')
|
print(
|
||||||
open(path.join(log_folder, log_file), 'w').close()
|
f'Copied {path.join(log_folder, datetime.now().strftime("%d.%m.%Y_%H:%M:%S"))}.log.gz'
|
||||||
|
)
|
||||||
|
open(path.join(log_folder, log_file), "w").close()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f'Log file {path.join(log_folder, log_file)} does not exist')
|
print(f"Log file {path.join(log_folder, log_file)} does not exist")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Append string to log
|
# Append string to log
|
||||||
def logAppend(message: str, debug=False):
|
def logAppend(message: str, debug=False):
|
||||||
"""Write message to log file
|
"""Write message to log file
|
||||||
@ -58,10 +68,11 @@ def logAppend(message: str, debug=False):
|
|||||||
else:
|
else:
|
||||||
log_file = "latest.log"
|
log_file = "latest.log"
|
||||||
|
|
||||||
log = open(path.join(log_folder, log_file), 'a')
|
log = open(path.join(log_folder, log_file), "a")
|
||||||
log.write(f'{message_formatted}\n')
|
log.write(f"{message_formatted}\n")
|
||||||
log.close()
|
log.close()
|
||||||
|
|
||||||
|
|
||||||
# Print to stdout and then to log
|
# Print to stdout and then to log
|
||||||
def logWrite(message: str, debug=False):
|
def logWrite(message: str, debug=False):
|
||||||
"""Write message to stdout and log file
|
"""Write message to stdout and log file
|
||||||
@ -71,5 +82,5 @@ def logWrite(message: str, debug=False):
|
|||||||
* debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`.
|
* 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)
|
@ -1,68 +1,125 @@
|
|||||||
"""Automatically register commands and execute
|
"""Automatically register commands and execute
|
||||||
some scheduled tasks is the main idea of this module"""
|
some scheduled tasks is the main idea of this module"""
|
||||||
|
|
||||||
|
from asyncio import sleep
|
||||||
from os import listdir, makedirs, path, sep
|
from os import listdir, makedirs, path, sep
|
||||||
|
from traceback import format_exc
|
||||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from ujson import dumps
|
from ujson import dumps
|
||||||
from app import app
|
from app import app
|
||||||
from pyrogram.types import BotCommand, BotCommandScopeChat
|
from pyrogram.types import (
|
||||||
|
BotCommand,
|
||||||
|
BotCommandScopeChat,
|
||||||
|
BotCommandScopeChatAdministrators,
|
||||||
|
)
|
||||||
from pyrogram.errors import bad_request_400
|
from pyrogram.errors import bad_request_400
|
||||||
from pyrogram.enums.chat_members_filter import ChatMembersFilter
|
from pyrogram.enums.chat_members_filter import ChatMembersFilter
|
||||||
from classes.holo_user import HoloUser
|
from classes.holo_user import HoloUser
|
||||||
from modules.utils import configGet, jsonSave, locale, logWrite
|
from modules.utils import configGet, jsonLoad, jsonSave, locale, logWrite
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from modules.database import col_applications, col_sponsorships
|
from modules.database import (
|
||||||
|
col_applications,
|
||||||
|
col_sponsorships,
|
||||||
|
col_youtube,
|
||||||
|
col_warnings,
|
||||||
|
)
|
||||||
|
from xmltodict import parse
|
||||||
|
from requests import get
|
||||||
|
|
||||||
scheduler = AsyncIOScheduler()
|
scheduler = AsyncIOScheduler()
|
||||||
|
|
||||||
if configGet("enabled", "scheduler", "cache_members"):
|
if configGet("enabled", "scheduler", "cache_members"):
|
||||||
@scheduler.scheduled_job(trigger="interval", seconds=configGet("interval", "scheduler", "cache_members"))
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="interval", seconds=configGet("interval", "scheduler", "cache_members")
|
||||||
|
)
|
||||||
async def cache_group_members():
|
async def cache_group_members():
|
||||||
list_of_users = []
|
list_of_users = []
|
||||||
async for member in app.get_chat_members(configGet("users", "groups")):
|
async for member in app.get_chat_members(configGet("users", "groups")):
|
||||||
list_of_users.append(member.user.id)
|
list_of_users.append(member.user.id)
|
||||||
makedirs("cache", exist_ok=True)
|
makedirs(configGet("cache", "locations"), exist_ok=True)
|
||||||
jsonSave(list_of_users, path.join(configGet("cache", "locations"), "group_members"))
|
jsonSave(
|
||||||
|
list_of_users, path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
)
|
||||||
|
if configGet("debug") is True:
|
||||||
|
logWrite("User group caching performed", debug=True)
|
||||||
|
|
||||||
|
|
||||||
if configGet("enabled", "scheduler", "cache_admins"):
|
if configGet("enabled", "scheduler", "cache_admins"):
|
||||||
@scheduler.scheduled_job(trigger="interval", seconds=configGet("interval", "scheduler", "cache_admins"))
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="interval", seconds=configGet("interval", "scheduler", "cache_admins")
|
||||||
|
)
|
||||||
async def cache_admins():
|
async def cache_admins():
|
||||||
list_of_users = []
|
list_of_users = []
|
||||||
async for member in app.get_chat_members(configGet("admin", "groups")):
|
async for member in app.get_chat_members(configGet("admin", "groups")):
|
||||||
list_of_users.append(member.user.id)
|
list_of_users.append(member.user.id)
|
||||||
makedirs("cache", exist_ok=True)
|
makedirs(configGet("cache", "locations"), exist_ok=True)
|
||||||
jsonSave(list_of_users, path.join(configGet("cache", "locations"), "admins"))
|
jsonSave(list_of_users, path.join(configGet("cache", "locations"), "admins"))
|
||||||
|
if configGet("debug") is True:
|
||||||
|
logWrite("Admin group caching performed", debug=True)
|
||||||
|
|
||||||
|
|
||||||
# Cache the avatars of group members
|
# Cache the avatars of group members
|
||||||
if configGet("enabled", "scheduler", "cache_avatars"):
|
if configGet("enabled", "scheduler", "cache_avatars"):
|
||||||
@scheduler.scheduled_job(trigger="date", run_date=datetime.now()+timedelta(seconds=10))
|
|
||||||
@scheduler.scheduled_job(trigger="interval", hours=configGet("interval", "scheduler", "cache_avatars"))
|
@scheduler.scheduled_job(
|
||||||
|
trigger="date", run_date=datetime.now() + timedelta(seconds=15)
|
||||||
|
)
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="interval", hours=configGet("interval", "scheduler", "cache_avatars")
|
||||||
|
)
|
||||||
async def cache_avatars():
|
async def cache_avatars():
|
||||||
list_of_users = []
|
list_of_users = []
|
||||||
async for member in app.get_chat_members(configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=""):
|
async for member in app.get_chat_members(
|
||||||
|
configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=""
|
||||||
|
):
|
||||||
list_of_users.append(member.user)
|
list_of_users.append(member.user)
|
||||||
for user in list_of_users:
|
for user in list_of_users:
|
||||||
if user.photo != None:
|
if user.photo != None:
|
||||||
if not path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{user.photo.big_file_id}'):
|
if not path.exists(
|
||||||
print(f'Pre-cached avatar {user.photo.big_file_id} of {user.id}', flush=True)
|
f'{configGet("cache", "locations")}{sep}avatars{sep}{user.photo.big_file_id}'
|
||||||
await app.download_media(user.photo.big_file_id, file_name=path.join(configGet("cache", "locations"), "avatars", user.photo.big_file_id))
|
):
|
||||||
|
print(
|
||||||
|
f"Pre-cached avatar {user.photo.big_file_id} of {user.id}",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
await app.download_media(
|
||||||
|
user.photo.big_file_id,
|
||||||
|
file_name=path.join(
|
||||||
|
configGet("cache", "locations"),
|
||||||
|
"avatars",
|
||||||
|
user.photo.big_file_id,
|
||||||
|
),
|
||||||
|
)
|
||||||
logWrite("Avatars caching performed")
|
logWrite("Avatars caching performed")
|
||||||
|
|
||||||
|
|
||||||
# Check for birthdays
|
# Check for birthdays
|
||||||
if configGet("enabled", "features", "applications") is True:
|
if configGet("enabled", "features", "applications") is True:
|
||||||
if configGet("enabled", "scheduler", "birthdays") is True:
|
if configGet("enabled", "scheduler", "birthdays") is True:
|
||||||
@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():
|
for entry in col_applications.find():
|
||||||
if entry["application"]["2"].strftime("%d.%m") == datetime.now().strftime("%d.%m"):
|
if entry["application"]["2"].strftime(
|
||||||
|
"%d.%m"
|
||||||
|
) == datetime.now().strftime("%d.%m"):
|
||||||
try:
|
try:
|
||||||
|
if entry["user"] not in jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
):
|
||||||
|
continue
|
||||||
tg_user = await app.get_users(entry["user"])
|
tg_user = await app.get_users(entry["user"])
|
||||||
await app.send_message( configGet("admin", "groups"), 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
|
await app.send_message(configGet("admin", "groups"), 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")
|
logWrite(f"Notified admins about {entry['user']}'s birthday")
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not find user {entry['user']} to send a message about birthday due to '{exp}'")
|
logWrite(
|
||||||
|
f"Could not find user {entry['user']} to send a message about birthday due to '{exp}'"
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
logWrite("Birthdays check performed")
|
logWrite("Birthdays check performed")
|
||||||
|
|
||||||
@ -70,45 +127,131 @@ if configGet("enabled", "features", "applications") is True:
|
|||||||
# Check for expired sponsorships
|
# Check for expired sponsorships
|
||||||
if configGet("enabled", "features", "sponsorships") is True:
|
if configGet("enabled", "features", "sponsorships") is True:
|
||||||
if configGet("enabled", "scheduler", "sponsorships") is True:
|
if configGet("enabled", "scheduler", "sponsorships") is True:
|
||||||
@scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "sponsorships"))
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="cron", hour=configGet("time", "scheduler", "sponsorships")
|
||||||
|
)
|
||||||
async def check_sponsors():
|
async def check_sponsors():
|
||||||
for entry in col_sponsorships.find({"sponsorship.expires": {"$lt": datetime.now()+timedelta(days=2)}}):
|
for entry in col_sponsorships.find(
|
||||||
|
{"sponsorship.expires": {"$lt": datetime.now() + timedelta(days=3)}}
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
|
if entry["user"] not in jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
):
|
||||||
|
continue
|
||||||
tg_user = await app.get_users(entry["user"])
|
tg_user = await app.get_users(entry["user"])
|
||||||
until_expiry = relativedelta(datetime.now(), entry["sponsorship"]["expires"]).days
|
until_expiry = (
|
||||||
await app.send_message( tg_user, locale("sponsorships_expires", "message").format(until_expiry) ) # type: ignore
|
abs(
|
||||||
logWrite(f"Notified user that sponsorship expires in {until_expiry} days")
|
relativedelta(
|
||||||
|
datetime.now(), entry["sponsorship"]["expires"]
|
||||||
|
).days
|
||||||
|
)
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
await app.send_message(tg_user.id, locale("sponsorships_expires", "message").format(until_expiry)) # type: ignore
|
||||||
|
logWrite(
|
||||||
|
f"Notified user {entry['user']} that sponsorship expires in {until_expiry} days"
|
||||||
|
)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not find user {entry['user']} notify about sponsorship expiry due to '{exp}'")
|
logWrite(
|
||||||
|
f"Could not find user {entry['user']} notify about sponsorship expiry due to '{exp}'"
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
for entry in col_sponsorships.find({"sponsorship.expires": {"$lt": datetime.now()}}):
|
for entry in col_sponsorships.find(
|
||||||
|
{
|
||||||
|
"sponsorship.expires": {
|
||||||
|
"$lt": datetime.now()
|
||||||
|
- timedelta(
|
||||||
|
days=configGet("grayout_days", "scheduler", "sponsorships")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
holo_user = HoloUser(entry["user"])
|
holo_user = HoloUser(entry["user"])
|
||||||
await app.send_message( entry["user"], locale("sponsorships_expired", "message") ) # type: ignore
|
|
||||||
await holo_user.label_reset(configGet("users", "groups"))
|
|
||||||
col_sponsorships.find_one_and_delete({"user": holo_user.id})
|
col_sponsorships.find_one_and_delete({"user": holo_user.id})
|
||||||
|
if entry["user"] not in jsonLoad(
|
||||||
|
path.join(configGet("cache", "locations"), "group_members")
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
await app.send_message(entry["user"], locale("sponsorships_expired", "message")) # type: ignore
|
||||||
|
await holo_user.label_reset(configGet("users", "groups"))
|
||||||
try:
|
try:
|
||||||
tg_user = await app.get_users(entry["user"])
|
tg_user = await app.get_users(entry["user"])
|
||||||
logWrite(f"Notified user that sponsorship expired")
|
logWrite(
|
||||||
|
f"Notified user {entry['user']} that sponsorship expired"
|
||||||
|
)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not find user {entry['user']} notify about sponsorship expired due to '{exp}'")
|
logWrite(
|
||||||
|
f"Could not find user {entry['user']} notify about sponsorship expired due to '{exp}'"
|
||||||
|
)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not reset label of user {entry['user']} due to '{exp}'")
|
logWrite(
|
||||||
|
f"Could not reset label of user {entry['user']} due to '{exp}'"
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
logWrite("Sponsorships check performed")
|
logWrite("Sponsorships check performed")
|
||||||
|
|
||||||
|
|
||||||
# Register all bot commands
|
# Revoke old warnings
|
||||||
@scheduler.scheduled_job(trigger="date", run_date=datetime.now()+timedelta(seconds=3))
|
if configGet("enabled", "features", "warnings") is True:
|
||||||
async def commands_register():
|
if configGet("enabled", "scheduler", "warnings_revocation") is True:
|
||||||
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="date", run_date=datetime.now() + timedelta(seconds=10)
|
||||||
|
)
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="interval",
|
||||||
|
hours=configGet("interval", "scheduler", "warnings_revocation"),
|
||||||
|
)
|
||||||
|
async def revoke_warnings():
|
||||||
|
for warning in list(
|
||||||
|
col_warnings.find(
|
||||||
|
{
|
||||||
|
"active": True,
|
||||||
|
"date": {"$lt": datetime.now() - timedelta(days=90)},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
):
|
||||||
|
if (
|
||||||
|
col_warnings.count_documents(
|
||||||
|
{
|
||||||
|
"user": warning["user"],
|
||||||
|
"active": True,
|
||||||
|
"date": {"$gt": datetime.now() - timedelta(days=90)},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
== 0
|
||||||
|
):
|
||||||
|
col_warnings.update_one(
|
||||||
|
{"_id": warning["_id"]},
|
||||||
|
{"$set": {"active": False, "revoke_date": datetime.now()}},
|
||||||
|
)
|
||||||
|
logWrite(
|
||||||
|
f'Revoked warning {str(warning["_id"])} of user {warning["user"]} because no active warnings for the last 90 days found.'
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
configGet("admin", "groups"),
|
||||||
|
locale("warning_revoked_auto", "message").format(
|
||||||
|
warning["user"], warning["date"].strftime("%d.%m.%Y")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Register all bot commands
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="date", run_date=datetime.now() + timedelta(seconds=10)
|
||||||
|
)
|
||||||
|
async def commands_register():
|
||||||
commands = {
|
commands = {
|
||||||
"users": [],
|
"users": [],
|
||||||
"admins": [],
|
"admins": [],
|
||||||
"owner": [],
|
"owner": [],
|
||||||
"group_users": [],
|
"group_users": [],
|
||||||
"group_admins": [],
|
"group_admins": [],
|
||||||
"locales": {}
|
"group_users_admins": [],
|
||||||
|
"locales": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
commands_raw = {
|
commands_raw = {
|
||||||
@ -117,7 +260,8 @@ async def commands_register():
|
|||||||
"owner": [],
|
"owner": [],
|
||||||
"group_users": [],
|
"group_users": [],
|
||||||
"group_admins": [],
|
"group_admins": [],
|
||||||
"locales": {}
|
"group_users_admins": [],
|
||||||
|
"locales": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_locales = []
|
valid_locales = []
|
||||||
@ -131,7 +275,8 @@ async def commands_register():
|
|||||||
"admins": [],
|
"admins": [],
|
||||||
"owner": [],
|
"owner": [],
|
||||||
"group_users": [],
|
"group_users": [],
|
||||||
"group_admins": []
|
"group_admins": [],
|
||||||
|
"group_users_admins": [],
|
||||||
}
|
}
|
||||||
if configGet("debug") is True:
|
if configGet("debug") is True:
|
||||||
commands_raw["locales"][".".join(entry.split(".")[:-1])] = {
|
commands_raw["locales"][".".join(entry.split(".")[:-1])] = {
|
||||||
@ -139,15 +284,14 @@ async def commands_register():
|
|||||||
"admins": [],
|
"admins": [],
|
||||||
"owner": [],
|
"owner": [],
|
||||||
"group_users": [],
|
"group_users": [],
|
||||||
"group_admins": []
|
"group_admins": [],
|
||||||
|
"group_users_admins": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
config_modules = configGet("features")
|
config_modules = configGet("features")
|
||||||
config_commands = configGet("commands")
|
config_commands = configGet("commands")
|
||||||
|
|
||||||
|
|
||||||
for command in config_commands:
|
for command in config_commands:
|
||||||
|
|
||||||
enabled = False
|
enabled = False
|
||||||
|
|
||||||
for module in config_commands[command]["modules"]:
|
for module in config_commands[command]["modules"]:
|
||||||
@ -155,27 +299,31 @@ async def commands_register():
|
|||||||
enabled = True
|
enabled = True
|
||||||
|
|
||||||
if enabled is False:
|
if enabled is False:
|
||||||
if configGet("debug") is True:
|
logWrite(f"Not registering {command} at all", debug=True)
|
||||||
logWrite(f"Not registering {command} at all")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for permission in config_commands[command]["permissions"]:
|
for permission in config_commands[command]["permissions"]:
|
||||||
|
commands[permission].append(
|
||||||
commands[permission].append(BotCommand(command, locale("commands")[command]))
|
BotCommand(command, locale("commands")[command])
|
||||||
|
)
|
||||||
|
|
||||||
if configGet("debug") is True:
|
if configGet("debug") is True:
|
||||||
commands_raw[permission].append({f"{command}": locale("commands")[command]})
|
commands_raw[permission].append(
|
||||||
|
{f"{command}": locale("commands")[command]}
|
||||||
|
)
|
||||||
logWrite(f"Registering {command} for {permission}")
|
logWrite(f"Registering {command} for {permission}")
|
||||||
|
|
||||||
for lc in valid_locales:
|
for lc in valid_locales:
|
||||||
|
commands["locales"][lc][permission].append(
|
||||||
commands["locales"][lc][permission].append(BotCommand(command, locale("commands", locale=lc)[command]))
|
BotCommand(command, locale("commands", locale=lc)[command])
|
||||||
|
)
|
||||||
|
|
||||||
if configGet("debug") is True:
|
if configGet("debug") is True:
|
||||||
commands_raw["locales"][lc][permission].append({f"{command}": locale("commands", locale=lc)[command]})
|
commands_raw["locales"][lc][permission].append(
|
||||||
|
{f"{command}": locale("commands", locale=lc)[command]}
|
||||||
|
)
|
||||||
logWrite(f"Registering {command} for {permission} [{lc}]")
|
logWrite(f"Registering {command} for {permission} [{lc}]")
|
||||||
|
|
||||||
|
|
||||||
# Registering user commands
|
# Registering user commands
|
||||||
await app.set_bot_commands(commands["users"])
|
await app.set_bot_commands(commands["users"])
|
||||||
logWrite("Registered user commands for default locale")
|
logWrite("Registered user commands for default locale")
|
||||||
@ -188,35 +336,129 @@ async def commands_register():
|
|||||||
# Registering admin commands
|
# Registering admin commands
|
||||||
for admin in configGet("admins"):
|
for admin in configGet("admins"):
|
||||||
try:
|
try:
|
||||||
await app.set_bot_commands(commands["admins"]+commands["users"], scope=BotCommandScopeChat(chat_id=admin))
|
await app.set_bot_commands(
|
||||||
|
commands["admins"] + commands["users"],
|
||||||
|
scope=BotCommandScopeChat(chat_id=admin),
|
||||||
|
)
|
||||||
logWrite(f"Registered admin commands for admin {admin}")
|
logWrite(f"Registered admin commands for admin {admin}")
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Registering owner commands
|
# Registering owner commands
|
||||||
try:
|
try:
|
||||||
await app.set_bot_commands(commands["admins"]+commands["owner"]+commands["users"], scope=BotCommandScopeChat(chat_id=configGet("owner")))
|
await app.set_bot_commands(
|
||||||
|
commands["admins"] + commands["owner"] + commands["users"],
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("owner")),
|
||||||
|
)
|
||||||
for lc in valid_locales:
|
for lc in valid_locales:
|
||||||
await app.set_bot_commands(commands["locales"][lc]["admins"]+commands["locales"][lc]["owner"]+commands["locales"][lc]["users"], scope=BotCommandScopeChat(chat_id=configGet("owner")))
|
await app.set_bot_commands(
|
||||||
|
commands["locales"][lc]["admins"]
|
||||||
|
+ commands["locales"][lc]["owner"]
|
||||||
|
+ commands["locales"][lc]["users"],
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("owner")),
|
||||||
|
)
|
||||||
logWrite(f"Registered admin commands for owner {configGet('owner')}")
|
logWrite(f"Registered admin commands for owner {configGet('owner')}")
|
||||||
except bad_request_400.PeerIdInvalid:
|
except bad_request_400.PeerIdInvalid:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Registering admin group commands
|
# Registering admin group commands
|
||||||
try:
|
try:
|
||||||
await app.set_bot_commands(commands["group_admins"], scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")))
|
await app.set_bot_commands(
|
||||||
|
commands["group_admins"],
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")),
|
||||||
|
)
|
||||||
logWrite("Registered admin group commands for default locale")
|
logWrite("Registered admin group commands for default locale")
|
||||||
except bad_request_400.ChannelInvalid:
|
except bad_request_400.ChannelInvalid:
|
||||||
logWrite(f"Could not register commands for admin group. Bot is likely not in the group.")
|
logWrite(
|
||||||
|
f"Could not register commands for admin group. Bot is likely not in the group."
|
||||||
|
)
|
||||||
|
|
||||||
# Registering destination group commands
|
# Registering destination group commands
|
||||||
try:
|
try:
|
||||||
await app.set_bot_commands(commands["group_users"], scope=BotCommandScopeChat(chat_id=configGet("users", "groups")))
|
await app.set_bot_commands(
|
||||||
|
commands["group_users"],
|
||||||
|
scope=BotCommandScopeChat(chat_id=configGet("users", "groups")),
|
||||||
|
)
|
||||||
logWrite("Registered destination group commands")
|
logWrite("Registered destination group commands")
|
||||||
except bad_request_400.ChannelInvalid:
|
except bad_request_400.ChannelInvalid:
|
||||||
logWrite(f"Could not register commands for destination group. Bot is likely not in the group.")
|
logWrite(
|
||||||
|
f"Could not register commands for destination group. Bot is likely not in the group."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Registering destination group admin commands
|
||||||
|
try:
|
||||||
|
await app.set_bot_commands(
|
||||||
|
commands["group_users_admins"],
|
||||||
|
scope=BotCommandScopeChatAdministrators(
|
||||||
|
chat_id=configGet("users", "groups")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logWrite("Registered destination group admin commands")
|
||||||
|
except bad_request_400.ChannelInvalid:
|
||||||
|
logWrite(
|
||||||
|
f"Could not register admin commands for destination group. Bot is likely not in the group."
|
||||||
|
)
|
||||||
|
|
||||||
if configGet("debug") is True:
|
if configGet("debug") is True:
|
||||||
print(commands, flush=True)
|
print(commands, flush=True)
|
||||||
logWrite(f"Complete commands registration:\n{dumps(commands_raw, indent=4, ensure_ascii=False, encode_html_chars=False)}")
|
logWrite(
|
||||||
|
f"Complete commands registration:\n{dumps(commands_raw, indent=4, ensure_ascii=False, encode_html_chars=False)}",
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if configGet("enabled", "scheduler", "channels_monitor"):
|
||||||
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
trigger="interval",
|
||||||
|
minutes=configGet("interval", "scheduler", "channels_monitor"),
|
||||||
|
)
|
||||||
|
async def channels_monitor():
|
||||||
|
for channel in configGet("channels", "scheduler", "channels_monitor"):
|
||||||
|
if configGet("debug") is True:
|
||||||
|
logWrite(
|
||||||
|
f'Processing videos of {channel["name"]} ({channel["id"]})',
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
req = get(
|
||||||
|
f'https://www.youtube.com/feeds/videos.xml?channel_id={channel["id"]}'
|
||||||
|
)
|
||||||
|
parsed = parse(req.content)
|
||||||
|
if "feed" not in parsed:
|
||||||
|
continue
|
||||||
|
if "entry" not in parsed["feed"]:
|
||||||
|
continue
|
||||||
|
for entry in parsed["feed"]["entry"]:
|
||||||
|
if "yt:videoId" not in entry:
|
||||||
|
continue
|
||||||
|
if (
|
||||||
|
col_youtube.find_one(
|
||||||
|
{"channel": channel["id"], "video": entry["yt:videoId"]}
|
||||||
|
)
|
||||||
|
is None
|
||||||
|
):
|
||||||
|
col_youtube.insert_one(
|
||||||
|
{
|
||||||
|
"channel": channel["id"],
|
||||||
|
"video": entry["yt:videoId"],
|
||||||
|
"date": datetime.fromisoformat(entry["published"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await app.send_message(
|
||||||
|
configGet("users", "groups"),
|
||||||
|
locale("youtube_video", "message").format(
|
||||||
|
channel["name"],
|
||||||
|
channel["link"],
|
||||||
|
entry["title"],
|
||||||
|
entry["link"]["@href"],
|
||||||
|
),
|
||||||
|
disable_web_page_preview=False,
|
||||||
|
)
|
||||||
|
await sleep(2)
|
||||||
|
except Exception as exp:
|
||||||
|
logWrite(
|
||||||
|
f'Could not get last videos of {channel["name"]} ({channel["id"]}) due to {exp}: {format_exc()}'
|
||||||
|
)
|
||||||
|
if configGet("debug") is True:
|
||||||
|
logWrite("Admin group caching performed", debug=True)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Literal, Union
|
from typing import Any, Literal, Tuple, Union
|
||||||
from uuid import uuid1
|
from uuid import uuid1
|
||||||
from requests import get
|
from requests import get
|
||||||
from pyrogram.enums.chat_type import ChatType
|
from pyrogram.enums.chat_type import ChatType
|
||||||
@ -16,23 +16,29 @@ from classes.errors.geo import PlaceNotFoundError
|
|||||||
|
|
||||||
from modules.logging import logWrite
|
from modules.logging import logWrite
|
||||||
|
|
||||||
|
|
||||||
def jsonLoad(filename):
|
def jsonLoad(filename):
|
||||||
"""Loads arg1 as json and returns its contents"""
|
"""Loads arg1 as json and returns its contents"""
|
||||||
with open(filename, "r", encoding='utf8') as file:
|
with open(filename, "r", encoding="utf8") as file:
|
||||||
try:
|
try:
|
||||||
output = loads(file.read())
|
output = loads(file.read())
|
||||||
except JSONDecodeError:
|
except JSONDecodeError:
|
||||||
logWrite(f"Could not load json file {filename}: file seems to be incorrect!\n{print_exc()}")
|
logWrite(
|
||||||
|
f"Could not load json file {filename}: file seems to be incorrect!\n{print_exc()}"
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logWrite(f"Could not load json file {filename}: file does not seem to exist!\n{print_exc()}")
|
logWrite(
|
||||||
|
f"Could not load json file {filename}: file does not seem to exist!\n{print_exc()}"
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def jsonSave(contents, filename):
|
def jsonSave(contents, filename):
|
||||||
"""Dumps dict/list arg1 to file arg2"""
|
"""Dumps dict/list arg1 to file arg2"""
|
||||||
try:
|
try:
|
||||||
with open(filename, "w", encoding='utf8') as file:
|
with open(filename, "w", encoding="utf8") as file:
|
||||||
file.write(dumps(contents, ensure_ascii=False, indent=4))
|
file.write(dumps(contents, ensure_ascii=False, indent=4))
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
logWrite(f"Could not save json file {filename}: {exp}\n{print_exc()}")
|
logWrite(f"Could not save json file {filename}: {exp}\n{print_exc()}")
|
||||||
@ -52,6 +58,7 @@ def nested_set(dic, keys, value, create_missing=True):
|
|||||||
d[keys[-1]] = value
|
d[keys[-1]] = value
|
||||||
return dic
|
return dic
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -69,7 +76,10 @@ def configSet(keys: list, value: Any, file: str = "config", create_missing=True)
|
|||||||
this_dict = jsonLoad("config_debug.json")
|
this_dict = jsonLoad("config_debug.json")
|
||||||
file = "config_debug"
|
file = "config_debug"
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Debug mode is set but config_debug.json is not there! Falling back to config.json", flush=True)
|
print(
|
||||||
|
"Debug mode is set but config_debug.json is not there! Falling back to config.json",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
filepath = f"data{sep}users{sep}"
|
filepath = f"data{sep}users{sep}"
|
||||||
this_dict = jsonLoad(f"{filepath}{file}.json")
|
this_dict = jsonLoad(f"{filepath}{file}.json")
|
||||||
@ -78,6 +88,7 @@ def configSet(keys: list, value: Any, file: str = "config", create_missing=True)
|
|||||||
jsonSave(this_dict, f"{filepath}{file}.json")
|
jsonSave(this_dict, f"{filepath}{file}.json")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
@ -91,13 +102,19 @@ def configGet(key: str, *args: str, file: str = "config"):
|
|||||||
try:
|
try:
|
||||||
this_dict = jsonLoad("config.json")
|
this_dict = jsonLoad("config.json")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Config file not found! Copy config_example.json to config.json, configure it and rerun the bot!", flush=True)
|
print(
|
||||||
|
"Config file not found! Copy config_example.json to config.json, configure it and rerun the bot!",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
exit()
|
exit()
|
||||||
if this_dict["debug"] is True:
|
if this_dict["debug"] is True:
|
||||||
try:
|
try:
|
||||||
this_dict = jsonLoad("config_debug.json")
|
this_dict = jsonLoad("config_debug.json")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Debug mode is set but config_debug.json is not there! Falling back to config.json", flush=True)
|
print(
|
||||||
|
"Debug mode is set but config_debug.json is not there! Falling back to config.json",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
this_dict = jsonLoad(f"data{sep}users{sep}{file}.json")
|
this_dict = jsonLoad(f"data{sep}users{sep}{file}.json")
|
||||||
this_key = this_dict
|
this_key = this_dict
|
||||||
@ -105,6 +122,7 @@ 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: Union[str, User] = configGet("locale")) -> Any:
|
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:
|
||||||
@ -126,7 +144,9 @@ def locale(key: str, *args: str, locale: Union[str, User] = configGet("locale"))
|
|||||||
this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{locale}.json')
|
this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{locale}.json')
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
try:
|
try:
|
||||||
this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json')
|
this_dict = jsonLoad(
|
||||||
|
f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json'
|
||||||
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"'
|
return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"'
|
||||||
|
|
||||||
@ -139,6 +159,7 @@ def locale(key: str, *args: str, locale: Union[str, User] = configGet("locale"))
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"'
|
return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"'
|
||||||
|
|
||||||
|
|
||||||
def all_locales(key: str, *args: str) -> list:
|
def all_locales(key: str, *args: str) -> list:
|
||||||
"""Get value of the provided key and path in all available locales
|
"""Get value of the provided key and path in all available locales
|
||||||
|
|
||||||
@ -174,6 +195,7 @@ def all_locales(key: str, *args: str) -> list:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def find_location(query: str) -> dict:
|
def find_location(query: str) -> dict:
|
||||||
"""Find location on geonames.org by query. Search is made with feature classes A and P.
|
"""Find location on geonames.org by query. Search is made with feature classes A and P.
|
||||||
|
|
||||||
@ -187,12 +209,20 @@ def find_location(query: str) -> dict:
|
|||||||
* `dict`: One instance of geonames response
|
* `dict`: One instance of geonames response
|
||||||
"""
|
"""
|
||||||
try:
|
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()
|
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()
|
||||||
return result["geonames"][0]
|
return result["geonames"][0]
|
||||||
except (ValueError, KeyError, IndexError):
|
except (ValueError, KeyError, IndexError):
|
||||||
raise PlaceNotFoundError(query)
|
raise PlaceNotFoundError(query)
|
||||||
|
|
||||||
def create_tmp(bytedata: Union[bytes, bytearray], kind: Union[Literal["image", "video"], None] = None) -> str:
|
|
||||||
|
def create_tmp(
|
||||||
|
bytedata: Union[bytes, bytearray],
|
||||||
|
kind: Union[Literal["image", "video"], None] = None,
|
||||||
|
) -> str:
|
||||||
"""Create temporary file to help uploading it
|
"""Create temporary file to help uploading it
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
@ -212,7 +242,8 @@ def create_tmp(bytedata: Union[bytes, bytearray], kind: Union[Literal["image", "
|
|||||||
file.write(bytedata)
|
file.write(bytedata)
|
||||||
return path.join("tmp", filename)
|
return path.join("tmp", filename)
|
||||||
|
|
||||||
async def download_tmp(app: Client, file_id: str) -> bytes:
|
|
||||||
|
async def download_tmp(app: Client, file_id: str) -> Tuple[str, bytes]:
|
||||||
"""Download file by its ID and return its bytes
|
"""Download file by its ID and return its bytes
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
@ -220,33 +251,40 @@ async def download_tmp(app: Client, file_id: str) -> bytes:
|
|||||||
* file_id (`str`): File's unique id
|
* file_id (`str`): File's unique id
|
||||||
|
|
||||||
### Returns:
|
### Returns:
|
||||||
* `bytes`: Bytes of downloaded file
|
* `Tuple[str, bytes]`: First is a filepath and the second is file's bytes
|
||||||
"""
|
"""
|
||||||
filename = str(uuid1())
|
filename = str(uuid1())
|
||||||
makedirs("tmp", exist_ok=True)
|
makedirs("tmp", exist_ok=True)
|
||||||
await app.download_media(file_id, path.join("tmp", filename))
|
await app.download_media(file_id, path.join("tmp", filename))
|
||||||
with open(path.join("tmp", filename), "rb") as f:
|
with open(path.join("tmp", filename), "rb") as f:
|
||||||
bytedata = f.read()
|
bytedata = f.read()
|
||||||
return bytedata
|
return path.join("tmp", filename), bytedata
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from psutil import Process
|
from psutil import Process
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
# print(locale("deps_missing", "console", locale=configGet("locale")), flush=True)
|
# print(locale("deps_missing", "console", locale=configGet("locale")), flush=True)
|
||||||
print("Missing dependencies! Please install all needed dependencies and run the bot again!")
|
print(
|
||||||
|
"Missing dependencies! Please install all needed dependencies and run the bot again!"
|
||||||
|
)
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
def killProc(pid):
|
def killProc(pid):
|
||||||
if osname == "posix":
|
if osname == "posix":
|
||||||
from signal import SIGKILL
|
from signal import SIGKILL
|
||||||
|
|
||||||
kill(pid, SIGKILL)
|
kill(pid, SIGKILL)
|
||||||
else:
|
else:
|
||||||
p = Process(pid)
|
p = Process(pid)
|
||||||
p.kill()
|
p.kill()
|
||||||
|
|
||||||
|
|
||||||
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]):
|
async def find_user(app: Client, query: Union[str, int]):
|
||||||
try:
|
try:
|
||||||
result = await app.get_users(int(query))
|
result = await app.get_users(int(query))
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
APScheduler==3.9.1.post1
|
aiocsv==1.2.4
|
||||||
fastapi==0.88.0
|
aiofiles~=23.1.0
|
||||||
psutil==5.9.4
|
apscheduler==3.10.1
|
||||||
|
convopyro==0.5
|
||||||
|
ftfy~=6.1.1
|
||||||
|
psutil~=5.9.5
|
||||||
|
polyglot~=16.7.4
|
||||||
|
pyicu~=2.11
|
||||||
|
pycld2==0.41
|
||||||
pymongo==4.3.3
|
pymongo==4.3.3
|
||||||
Pyrogram~=2.0.93
|
pyrogram==2.0.104
|
||||||
requests==2.28.1
|
|
||||||
tgcrypto==1.2.5
|
|
||||||
python_dateutil==2.8.2
|
python_dateutil==2.8.2
|
||||||
starlette==0.23.0
|
pykeyboard==0.1.5
|
||||||
ujson==5.6.0
|
requests==2.29.0
|
||||||
|
tgcrypto==1.2.5
|
||||||
|
ujson~=5.7.0
|
||||||
|
xmltodict==0.13.0
|
29
validation/bans.json
Normal file
29
validation/bans.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"$jsonSchema": {
|
||||||
|
"required": [
|
||||||
|
"user",
|
||||||
|
"admin",
|
||||||
|
"date"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"user": {
|
||||||
|
"bsonType": [
|
||||||
|
"int",
|
||||||
|
"long"
|
||||||
|
],
|
||||||
|
"description": "Telegram ID of user"
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"bsonType": [
|
||||||
|
"int",
|
||||||
|
"long"
|
||||||
|
],
|
||||||
|
"description": "Telegram ID of admin"
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"bsonType": "date",
|
||||||
|
"description": "Date and time of getting"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
"description",
|
"description",
|
||||||
"photo",
|
"photo",
|
||||||
"video",
|
"video",
|
||||||
|
"audio",
|
||||||
"animation",
|
"animation",
|
||||||
"document",
|
"document",
|
||||||
"caption",
|
"caption",
|
||||||
@ -38,6 +39,10 @@
|
|||||||
"bsonType": ["string", "null"],
|
"bsonType": ["string", "null"],
|
||||||
"description": "Spoilered video"
|
"description": "Spoilered video"
|
||||||
},
|
},
|
||||||
|
"audio": {
|
||||||
|
"bsonType": ["string", "null"],
|
||||||
|
"description": "Spoilered audio"
|
||||||
|
},
|
||||||
"animation": {
|
"animation": {
|
||||||
"bsonType": ["string", "null"],
|
"bsonType": ["string", "null"],
|
||||||
"description": "Spoilered animation/GIF"
|
"description": "Spoilered animation/GIF"
|
||||||
|
@ -4,15 +4,23 @@
|
|||||||
"user",
|
"user",
|
||||||
"admin",
|
"admin",
|
||||||
"date",
|
"date",
|
||||||
"reason"
|
"reason",
|
||||||
|
"active",
|
||||||
|
"revoke_date"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"user": {
|
"user": {
|
||||||
"bsonType": ["int", "long"],
|
"bsonType": [
|
||||||
|
"int",
|
||||||
|
"long"
|
||||||
|
],
|
||||||
"description": "Telegram ID of user"
|
"description": "Telegram ID of user"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"bsonType": ["int", "long"],
|
"bsonType": [
|
||||||
|
"int",
|
||||||
|
"long"
|
||||||
|
],
|
||||||
"description": "Telegram ID of admin"
|
"description": "Telegram ID of admin"
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
@ -22,6 +30,17 @@
|
|||||||
"reason": {
|
"reason": {
|
||||||
"bsonType": "string",
|
"bsonType": "string",
|
||||||
"description": "Broken rule or admin's comment"
|
"description": "Broken rule or admin's comment"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"bsonType": "bool",
|
||||||
|
"description": "Whether warning is still present"
|
||||||
|
},
|
||||||
|
"revoke_date": {
|
||||||
|
"bsonType": [
|
||||||
|
"date",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"description": "Date when warning got inactive"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user