Compare commits

...

6 Commits

Author SHA1 Message Date
Profitroll
664284a6f8 Integrated previous commits 2023-02-17 21:55:38 +01:00
Profitroll
bd9917fb17 Replaced user block logic 2023-02-17 21:54:52 +01:00
Profitroll
68ea087963 Integrated interval-based schedule 2023-02-17 21:54:30 +01:00
Profitroll
d1813856d9 Imported callback "nothing" 2023-02-17 21:54:14 +01:00
Profitroll
cf204577e4 Added external address for links 2023-02-17 21:53:57 +01:00
Profitroll
68c887999e Divided admins and owner 2023-02-17 21:53:43 +01:00
15 changed files with 113 additions and 73 deletions

View File

@@ -17,6 +17,8 @@ class PosterClient(Client):
def __init__(self, name: str, **kwargs): # type: ignore
super().__init__(name, **kwargs)
self.owner = configGet("owner")
self.admins = configGet("admins")+[configGet("owner")]
async def submit_photo(self, id: str) -> Union[Message, None]:
@@ -40,7 +42,7 @@ class PosterClient(Client):
response = await upload_pic(str(filepath))
if response[0] is False:
if len(response[1]) > 0:
raise SubmissionDuplicatesError(str(filepath), response[1])
col_submitted.find_one_and_update({"_id": ObjectId(id)}, {"$set": {"done": True}})

17
classes/user.py Normal file
View File

@@ -0,0 +1,17 @@
from datetime import datetime
from modules.database import col_banned
class PosterUser():
def __init__(self, id: int):
self.id = id
def is_blocked(self) -> bool:
return False if col_banned.find_one({"user": self.id}) is None else True
def block(self) -> None:
if col_banned.find_one({"user": self.id}) is None:
col_banned.insert_one({"user": self.id, "date": datetime.now()})
def unblock(self) -> None:
col_banned.find_one_and_delete({"user": self.id})

View File

@@ -3,7 +3,8 @@
"locale": "en",
"locale_log": "en",
"locale_fallback": "en",
"admin": 0,
"owner": 0,
"admins": [],
"bot": {
"api_id": 0,
"api_hash": "",
@@ -46,7 +47,8 @@
"channel": 0,
"silent": false,
"move_sent": false,
"interval": 1,
"use_interval": false,
"interval": "1h30m",
"extensions": {
"photo": [
"jpg",
@@ -74,6 +76,7 @@
],
"api": {
"address": "http://localhost:8054",
"address_external": "https://photos.domain.com",
"username": "",
"password": "",
"album": ""
@@ -105,6 +108,8 @@
"rules"
],
"commands_admin": [
"import",
"export",
"reboot"
]
}

View File

@@ -64,7 +64,7 @@ async def upload_pic(filepath: str, token: Union[str, None] = None) -> Tuple[boo
duplicates = []
if "duplicates" in response.json():
for duplicate in response.json()["duplicates"]:
duplicates.append(f'{configGet("address", "posting", "api")}/photos/{duplicate["id"]}')
duplicates.append(f'{configGet("address_external", "posting", "api")}/photos/{duplicate["id"]}')
return True, duplicates
except:
return False, []

View File

@@ -30,4 +30,5 @@ async def register_commands(app: PosterClient):
for command in configGet("commands_admin"):
commands_admin_list.append(BotCommand(command, locale(command, "commands_admin", locale=configGet("locale"))))
await app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=configGet("admin")))
for admin in app.admins:
await app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=admin))

View File

@@ -1,5 +1,6 @@
from datetime import datetime, timedelta
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from pytimeparse.timeparse import timeparse
from modules.utils import configGet
from modules.sender import send_content
from modules.commands_register import register_commands
@@ -8,10 +9,11 @@ from modules.app import app
scheduler = AsyncIOScheduler()
if configGet("post", "mode"):
# for entry in configGet("time", "posting"):
# dt_obj = datetime.strptime(entry, "%H:%M")
# Is only used for debug now!
scheduler.add_job(send_content, "interval", seconds=30, args=[app])
# scheduler.add_job(send_content, "cron", hour=dt_obj.hour, minute=dt_obj.minute, args=[app])
if configGet("use_interval", "posting"):
scheduler.add_job(send_content, "interval", seconds=timeparse(configGet("interval", "posting")), args=[app])
else:
for entry in configGet("time", "posting"):
dt_obj = datetime.strptime(entry, "%H:%M")
scheduler.add_job(send_content, "cron", hour=dt_obj.hour, minute=dt_obj.minute, args=[app])
scheduler.add_job(register_commands, "date", run_date=datetime.now()+timedelta(seconds=10), args=[app])

View File

@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import datetime
from os import makedirs, path
from shutil import copyfileobj, rmtree
from traceback import format_exc
@@ -22,7 +22,7 @@ async def send_content(app: PosterClient):
try:
token = await authorize()
except ValueError:
await app.send_message(configGet("admin"), locale("api_creds_invalid", "message", locale=configGet("locale")))
await app.send_message(app.owner, locale("api_creds_invalid", "message", locale=configGet("locale")))
return
try:
@@ -30,11 +30,11 @@ async def send_content(app: PosterClient):
except KeyError:
logWrite(locale("post_empty", "console", locale=configGet("locale")))
if configGet("error", "reports"):
await app.send_message(configGet("admin"), locale("api_queue_empty", "message", locale=configGet("locale")))
await app.send_message(app.owner, locale("api_queue_empty", "message", locale=configGet("locale")))
return
except ValueError:
if configGet("error", "reports"):
await app.send_message(configGet("admin"), locale("api_queue_error", "message", locale=configGet("locale")))
await app.send_message(app.owner, locale("api_queue_error", "message", locale=configGet("locale")))
return
response = get(f'{configGet("address", "posting", "api")}/photos/{pic[0]}', headers={"Authorization": f"Bearer {token}"}, stream=True)
@@ -42,7 +42,7 @@ async def send_content(app: PosterClient):
if response.status_code != 200:
logWrite(locale("post_invalid_pic", "console", locale=configGet("locale")).format(str(response.json())))
if configGet("error", "reports"):
await app.send_message(configGet("admin"), locale("post_invalid_pic", "message", locale=configGet("locale")).format(response.json()))
await app.send_message(app.owner, locale("post_invalid_pic", "message", locale=configGet("locale")).format(response.json()))
tmp_dir = str(uuid4())
@@ -91,13 +91,13 @@ async def send_content(app: PosterClient):
except Exception as exp:
logWrite(f"Could not send image {pic[1]} ({pic[0]}) due to {exp}")
if configGet("error", "reports"):
await app.send_message(configGet("admin"), locale("post_exception", "message", locale=configGet("locale")).format(exp, format_exc()))
await app.send_message(app.owner, locale("post_exception", "message", locale=configGet("locale")).format(exp, format_exc()))
# rmtree(path.join(configGet("tmp", "locations"), tmp_dir), ignore_errors=True)
return
col_sent.insert_one(
{
"date": datetime.now(tz=timezone.utc),
"date": datetime.now(),
"image": pic[0],
"filename": pic[1],
"channel": configGet("channel", "posting"),
@@ -114,7 +114,7 @@ async def send_content(app: PosterClient):
except Exception as exp:
logWrite(locale("post_exception", "console", locale=configGet("locale")).format(str(exp), format_exc()))
if configGet("error", "reports"):
await app.send_message(configGet("admin"), locale("post_exception", "message", locale=configGet("locale")).format(exp, format_exc()))
await app.send_message(app.owner, locale("post_exception", "message", locale=configGet("locale")).format(exp, format_exc()))
try:
rmtree(path.join(configGet("tmp", "locations"), tmp_dir), ignore_errors=True)
except:

View File

@@ -1,27 +1,18 @@
from datetime import datetime, timezone
from modules.app import app
from datetime import datetime
from modules.utils import configGet
from modules.database import col_users, col_banned
from modules.database import col_users
from pyrogram.types.user_and_chats import User
def subLimit(user: User) -> None:
if col_users.find_one_and_update({"user": user.id}, {"$set": {"cooldown": datetime.now(tz=timezone.utc)}}) is None:
col_users.insert_one({"user": user.id, "cooldown": datetime.now(tz=timezone.utc)})
if col_users.find_one_and_update({"user": user.id}, {"$set": {"cooldown": datetime.now()}}) is None:
col_users.insert_one({"user": user.id, "cooldown": datetime.now()})
def subLimited(user: User) -> bool:
if user.id == configGet("admin"):
if user.id in app.admins:
return False
else:
db_record = col_users.find_one({"user": user.id})
if db_record is None:
return False
return True if (datetime.now(tz=timezone.utc) - db_record["cooldown"].astimezone(timezone.utc)).total_seconds() < configGet("timeout", "submission") else False
def subBlocked(user: User) -> bool:
return False if col_banned.find_one({"user": user.id}) is None else True
def subBlock(user: User) -> None:
if col_banned.find_one({"user": user.id}) is None:
col_banned.insert_one({"user": user.id, "date": datetime.now(tz=timezone.utc)})
def subUnblock(user: User) -> None:
col_banned.find_one_and_delete({"user": user.id})
return True if (datetime.now() - db_record["cooldown"]).total_seconds() < configGet("timeout", "submission") else False

View File

@@ -1,11 +1,13 @@
from os import path
from shutil import rmtree
from pyrogram import filters
from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from classes.exceptions import SubmissionDuplicatesError, SubmissionUnavailableError
from classes.poster_client import PosterClient
from classes.user import PosterUser
from modules.app import app
from modules.submissions import subBlock, subUnblock
from modules.utils import configGet, locale
from modules.database import col_submitted
from bson import ObjectId
@@ -26,7 +28,7 @@ async def callback_query_yes(app: PosterClient, clb: CallbackQuery):
return
except SubmissionDuplicatesError as exp:
await clb.answer(text=locale("sub_duplicates_found", "callback", locale=user_locale), show_alert=True)
await clb.message.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)))
await clb.message.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)), quote=True)
return
if submission is not None:
@@ -37,7 +39,7 @@ async def callback_query_yes(app: PosterClient, clb: CallbackQuery):
await clb.answer(text=locale("sub_yes", "callback", locale=user_locale).format(fullclb[2]), show_alert=True)
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")], clb.message.reply_markup.inline_keyboard[1]] if len(clb.message.reply_markup.inline_keyboard) > 1 else [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
await clb.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(edited_markup))
# try:
# if configGet("api_based", "mode") is True:
@@ -71,39 +73,52 @@ async def callback_query_yes(app: PosterClient, clb: CallbackQuery):
@app.on_callback_query(filters.regex("sub_no_[\s\S]*"))
async def callback_query_no(app: PosterClient, clb: CallbackQuery):
fullclb = clb.data.split("_")
fullclb = str(clb.data).split("_")
user_locale = clb.from_user.language_code
db_entry = col_submitted.find_one_and_delete({"_id": ObjectId(fullclb[2])})
if db_entry["temp"]["uuid"] is not None:
if path.exists(path.join(configGet("data", "locations"), "submissions", db_entry["temp"]["uuid"])):
rmtree(path.join(configGet("data", "locations"), "submissions", db_entry["temp"]["uuid"]), ignore_errors=True)
try:
submission = await app.get_messages(int(fullclb[2]), int(fullclb[3]))
submission = await app.get_messages(db_entry["user"], db_entry["telegram"]["msg_id"])
except:
await clb.answer(text=locale("sub_msg_unavail", "message", locale=user_locale), show_alert=True)
return
await submission.reply_text(locale("sub_no", "message", locale=submission.from_user.language_code), quote=True)
await clb.answer(text=locale("sub_no", "callback", locale=user_locale).format(fullclb[2]), show_alert=True)
# edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
# await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")], clb.message.reply_markup.inline_keyboard[1]] if len(clb.message.reply_markup.inline_keyboard) > 1 else [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]]
await clb.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(edited_markup))
@app.on_callback_query(filters.regex("sub_block_[\s\S]*"))
async def callback_query_block(app: PosterClient, clb: CallbackQuery):
fullclb = clb.data.split("_")
fullclb = str(clb.data).split("_")
user_locale = clb.from_user.language_code
await app.send_message(int(fullclb[2]), locale("sub_msg_unavail", "message", locale=configGet("locale")))
subBlock(int(fullclb[2]))
await app.send_message(int(fullclb[2]), locale("sub_blocked", "message", locale=configGet("locale")))
PosterUser(int(fullclb[2])).block()
await clb.answer(text=locale("sub_block", "callback", locale=user_locale).format(fullclb[2]), show_alert=True)
edited_markup = [clb.message.reply_markup.inline_keyboard[0], [InlineKeyboardButton(text=str(locale("sub_unblock", "button")), callback_data=f"sub_unblock_{fullclb[2]}")]]
await clb.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(edited_markup))
# edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
# await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))
@app.on_callback_query(filters.regex("sub_unblock_[\s\S]*"))
async def callback_query_unblock(app: PosterClient, clb: CallbackQuery):
fullclb = clb.data.split("_")
fullclb = str(clb.data).split("_")
user_locale = clb.from_user.language_code
await app.send_message(int(fullclb[2]), locale("sub_msg_unavail", "message", locale=configGet("locale")))
subUnblock(int(fullclb[2]))
await app.send_message(int(fullclb[2]), locale("sub_unblocked", "message", locale=configGet("locale")))
PosterUser(int(fullclb[2])).unblock()
await clb.answer(text=locale("sub_unblock", "callback", locale=user_locale).format(fullclb[2]), show_alert=True)
edited_markup = [clb.message.reply_markup.inline_keyboard[0], [InlineKeyboardButton(text=str(locale("sub_block", "button")), callback_data=f"sub_block_{fullclb[2]}")]]
await clb.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(edited_markup))
# edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]
# await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup))

View File

@@ -12,7 +12,7 @@ from modules.utils import configGet, killProc, locale
@app.on_message(~ filters.scheduled & filters.command(["kill", "die", "reboot"], prefixes=["", "/"]))
async def cmd_kill(app: PosterClient, msg: Message):
if msg.from_user.id == configGet("admin"):
if msg.from_user.id in app.admins:
pid = getpid()
logWrite(locale("shutdown", "console", locale=configGet("locale")).format(str(pid)))
await msg.reply_text(locale("shutdown", "message", locale=configGet("locale")).format(str(pid)))

View File

@@ -1,18 +1,18 @@
from pyrogram import filters
from classes.poster_client import PosterClient
from pyrogram.types import Message
from modules.app import app
from modules.submissions import subBlocked
from modules.utils import configGet, jsonLoad, locale
from modules.utils import locale
from classes.user import PosterUser
from classes.poster_client import PosterClient
@app.on_message(~ filters.scheduled & filters.command(["start"], prefixes="/"))
async def cmd_start(app: PosterClient, msg: Message):
if subBlocked(msg.from_user) is False:
if PosterUser(msg.from_user.id).is_blocked() is False:
await msg.reply_text(locale("start", "message", locale=msg.from_user.language_code))
@app.on_message(~ filters.scheduled & filters.command(["rules", "help"], prefixes="/"))
async def cmd_rules(app: PosterClient, msg: Message):
if subBlocked(msg.from_user) is False:
if PosterUser(msg.from_user.id).is_blocked() is False:
await msg.reply_text(locale("rules", "message", locale=msg.from_user.language_code))

View File

@@ -12,12 +12,12 @@ from modules.utils import configGet, killProc, locale
@app.on_message(~ filters.scheduled & filters.command(["import"], prefixes=["", "/"]))
async def cmd_import(app: PosterClient, msg: Message):
if msg.from_user.id == configGet("admin"):
if msg.from_user.id in app.admins:
pass
@app.on_message(~ filters.scheduled & filters.command(["export"], prefixes=["", "/"]))
async def cmd_export(app: PosterClient, msg: Message):
if msg.from_user.id == configGet("admin"):
if msg.from_user.id in app.admins:
pass

View File

@@ -4,9 +4,10 @@ from traceback import format_exc
from uuid import uuid4
from pyrogram import filters
from pyrogram.client import Client
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
from pyrogram.enums.chat_action import ChatAction
from classes.exceptions import SubmissionDuplicatesError
from classes.poster_client import PosterClient
from modules.app import app
from modules.database import col_banned, col_submitted
@@ -16,14 +17,16 @@ from modules.utils import configGet, locale
from classes.enums.submission_types import SubmissionType
@app.on_message(~ filters.scheduled & filters.photo | filters.video | filters.animation | filters.document)
async def get_submission(_: Client, msg: Message):
@app.on_message(~filters.scheduled & filters.private & filters.photo | filters.video | filters.animation | filters.document)
async def get_submission(app: PosterClient, msg: Message):
try:
if col_banned.find_one( {"user": msg.from_user.id} ) is not None:
return
await app.send_chat_action(msg.chat.id, ChatAction.TYPING)
user_locale = msg.from_user.language_code
save_tmp = True
contents = None
@@ -74,7 +77,7 @@ async def get_submission(_: Client, msg: Message):
inserted = col_submitted.insert_one(
{
"user": msg.from_user.id,
"date": datetime.now(tz=timezone.utc),
"date": datetime.now(),
"done": False,
"type": contents[1].value,
"temp": {
@@ -97,7 +100,7 @@ async def get_submission(_: Client, msg: Message):
inserted = col_submitted.insert_one(
{
"user": msg.from_user.id,
"date": datetime.now(tz=timezone.utc),
"date": datetime.now(),
"done": False,
"type": contents[1].value,
"temp": {
@@ -143,31 +146,31 @@ async def get_submission(_: Client, msg: Message):
if msg.from_user.phone_number is not None:
caption += f" ({msg.from_user.phone_number})"
if msg.from_user.id == configGet("admin") and configGet("admins", "submission", "require_confirmation") is False:
if msg.from_user.id in app.admins and configGet("admins", "submission", "require_confirmation") is False:
try:
await app.submit_photo(str(inserted.inserted_id))
await msg.copy(configGet("admin"), caption=caption)
await msg.copy(app.owner, caption=caption)
return
except SubmissionDuplicatesError as exp:
await msg.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)))
await msg.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)), quote=True)
return
except Exception as exp:
await msg.reply_text(format_exc())
return
elif msg.from_user.id != configGet("admin") and configGet("users", "submission", "require_confirmation") is False:
elif msg.from_user.id not in app.admins and configGet("users", "submission", "require_confirmation") is False:
try:
await app.submit_photo(str(inserted.inserted_id))
await msg.copy(configGet("admin"), caption=caption)
await msg.copy(app.owner, caption=caption)
return
except SubmissionDuplicatesError as exp:
await msg.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)))
await msg.reply_text(locale("sub_media_duplicates_list", "message", locale=user_locale).format("\n".join(exp.duplicates)), quote=True)
return
except Exception as exp:
await app.send_message(configGet("admin"), f"User {msg.from_user.id} could not submit photo without additional confirmation due to:\n```\n{format_exc()}\n```")
await app.send_message(app.owner, f"User {msg.from_user.id} could not submit photo without additional confirmation due to:\n```\n{format_exc()}\n```")
await msg.reply_text("Could not upload this image. Admins are advised.")
return
if msg.from_user.id != configGet("admin"):
if msg.from_user.id not in app.admins:
buttons += [
[
InlineKeyboardButton(text=locale("sub_block", "button", locale=configGet("locale")), callback_data=f"sub_block_{msg.from_user.id}")
@@ -177,10 +180,12 @@ async def get_submission(_: Client, msg: Message):
# ]
]
await msg.reply_text(locale("sub_sent", "message", locale=user_locale), quote=True)
subLimit(msg.from_user)
await msg.copy(configGet("admin"), caption=caption, reply_markup=InlineKeyboardMarkup(buttons))
if msg.from_user.id != app.owner:
await msg.reply_text(locale("sub_sent", "message", locale=user_locale), quote=True)
await msg.copy(app.owner, caption=caption, reply_markup=InlineKeyboardMarkup(buttons))
except AttributeError:
logWrite(f"from_user in function get_submission does not seem to contain id")

View File

@@ -119,6 +119,7 @@ pid = getpid()
from plugins.commands.general import *
if configGet("submit", "mode"):
from plugins.callbacks.nothing import *
from plugins.callbacks.submission import *
from plugins.commands.mode_submit import *
from plugins.handlers.submission import *
@@ -174,7 +175,7 @@ if __name__ == "__main__":
app.start()
if configGet("startup", "reports"):
app.send_message(configGet("admin"), locale("startup", "message", locale=configGet("locale")).format(str(pid)))
app.send_message(app.owner, locale("startup", "message", locale=configGet("locale")).format(str(pid)))
if configGet("post", "mode"):
scheduler.start()
@@ -186,7 +187,7 @@ if __name__ == "__main__":
idle()
app.send_message(configGet("admin"), locale("shutdown", "message", locale=configGet("locale")).format(str(pid)))
app.send_message(app.owner, locale("shutdown", "message", locale=configGet("locale")).format(str(pid)))
logWrite(locale("shutdown", "console", locale=configGet("locale")).format(str(pid)))
killProc(pid)

View File

@@ -4,3 +4,4 @@ requests~=2.28.2
psutil~=5.9.4
pymongo~=4.3.3
pillow~=9.4.0
pytimeparse~=1.1.8