format Black

This commit is contained in:
Rykov7
2023-02-22 18:53:12 +03:00
parent 23a93b5dbd
commit d0cf0762c8
13 changed files with 356 additions and 205 deletions
+129 -73
View File
@@ -14,181 +14,222 @@ from .config import *
@bot.edited_message_handler(func=in_spam_list) @bot.edited_message_handler(func=in_spam_list)
@bot.message_handler(func=in_spam_list) @bot.message_handler(func=in_spam_list)
def moderate_messages(message: types.Message): def moderate_messages(message: types.Message):
""" Ban user and delete their message. """ """Ban user and delete their message."""
logging.warning(f'[BAN] {message.from_user.id} {message.from_user.username} - {message.text}') logging.warning(
f"[BAN] {message.from_user.id} {message.from_user.username} - {message.text}"
)
bot.delete_message(message.chat.id, message.id) bot.delete_message(message.chat.id, message.id)
bot.ban_chat_member(message.chat.id, message.from_user.id) bot.ban_chat_member(message.chat.id, message.from_user.id)
with shelve.open(f'{DATA}{message.chat.id}') as s: with shelve.open(f"{DATA}{message.chat.id}") as s:
s['Banned'] += 1 s["Banned"] += 1
@bot.message_handler(func=in_caption_spam_list, content_types=['video']) @bot.message_handler(func=in_caption_spam_list, content_types=["video"])
def catch_videos(message: types.Message): def catch_videos(message: types.Message):
"""Catch offensive videos""" """Catch offensive videos"""
logging.warning(f'[BAN] {message.from_user.id} {message.from_user.first_name} - {message.video.file_name}') logging.warning(
f"[BAN] {message.from_user.id} {message.from_user.first_name} - {message.video.file_name}"
)
bot.delete_message(message.chat.id, message.id) bot.delete_message(message.chat.id, message.id)
bot.ban_chat_member(message.chat.id, message.from_user.id) bot.ban_chat_member(message.chat.id, message.from_user.id)
with shelve.open(f'{DATA}{message.chat.id}') as s: with shelve.open(f"{DATA}{message.chat.id}") as s:
s['Banned'] += 1 s["Banned"] += 1
@bot.edited_message_handler(func=in_delete_list) @bot.edited_message_handler(func=in_delete_list)
@bot.message_handler(func=in_delete_list) @bot.message_handler(func=in_delete_list)
def delete_message(message: types.Message): def delete_message(message: types.Message):
""" Delete unwanted message. """ """Delete unwanted message."""
bot.delete_message(message.chat.id, message.id) bot.delete_message(message.chat.id, message.id)
with shelve.open(f'{DATA}{message.chat.id}') as s: with shelve.open(f"{DATA}{message.chat.id}") as s:
s['Deleted'] += 1 s["Deleted"] += 1
""" [ COMMANDS ] """ """ [ COMMANDS ] """
@bot.message_handler(commands=['start', 'links', 'ссылки']) @bot.message_handler(commands=["start", "links", "ссылки"])
def start(message: types.Message): def start(message: types.Message):
""" What to begin with. """ """What to begin with."""
log_msg = f'[START] {message.from_user.id} {message.from_user.first_name}' log_msg = f"[START] {message.from_user.id} {message.from_user.first_name}"
logging.warning(log_msg) logging.warning(log_msg)
markup = types.InlineKeyboardMarkup([[RULES], [FAQ], [LIB]], 1) markup = types.InlineKeyboardMarkup([[RULES], [FAQ], [LIB]], 1)
send_or_reply(message, "Начни с прочтения", reply_markup=markup) send_or_reply(message, "Начни с прочтения", reply_markup=markup)
@bot.message_handler(commands=['rules', 'rule', 'r', 'правила', 'правило', 'п']) @bot.message_handler(commands=["rules", "rule", "r", "правила", "правило", "п"])
def send_rules(message): def send_rules(message):
markup = types.InlineKeyboardMarkup([[RULES]], 1) markup = types.InlineKeyboardMarkup([[RULES]], 1)
args = message.text.split() args = message.text.split()
if len(args) > 1 and args[-1].isdigit() and 0 < int(args[-1]): if len(args) > 1 and args[-1].isdigit() and 0 < int(args[-1]):
send_or_reply(message, f'<b>Правило {args[-1]}</b>\n<i>{rules.fetch_rule(args[-1])}</i>', reply_markup=markup) send_or_reply(
message,
f"<b>Правило {args[-1]}</b>\n<i>{rules.fetch_rule(args[-1])}</i>",
reply_markup=markup,
)
else: else:
send_or_reply(message, '...', reply_markup=markup) send_or_reply(message, "...", reply_markup=markup)
@bot.message_handler(commands=['faq', 'чзв']) @bot.message_handler(commands=["faq", "чзв"])
def send_faq(message): def send_faq(message):
markup = types.InlineKeyboardMarkup([[FAQ]], 1) markup = types.InlineKeyboardMarkup([[FAQ]], 1)
send_or_reply(message, '...', reply_markup=markup) send_or_reply(message, "...", reply_markup=markup)
@bot.message_handler(commands=['lib', 'library', 'books', 'книги', 'библиотека']) @bot.message_handler(commands=["lib", "library", "books", "книги", "библиотека"])
def send_lib(message): def send_lib(message):
markup = types.InlineKeyboardMarkup([[LIB]], 1) markup = types.InlineKeyboardMarkup([[LIB]], 1)
send_or_reply(message, '...', reply_markup=markup) send_or_reply(message, "...", reply_markup=markup)
@bot.message_handler(commands=['lutz', 'лутц']) @bot.message_handler(commands=["lutz", "лутц"])
def send_lutz(message): def send_lutz(message):
bot.send_document(message.chat.id, bot.send_document(
document='BQACAgQAAxkBAAPBYsWJG9Ml0fPrnbU9UyzTQiQSuHkAAjkDAAIstCxSkuRbXAlcqeQpBA', message.chat.id,
caption="вот, не позорься") document="BQACAgQAAxkBAAPBYsWJG9Ml0fPrnbU9UyzTQiQSuHkAAjkDAAIstCxSkuRbXAlcqeQpBA",
caption="вот, не позорься",
)
@bot.message_handler(commands=['bdmtss', 'бдмтсс']) @bot.message_handler(commands=["bdmtss", "бдмтсс"])
def send_bdmtss_audio(message): def send_bdmtss_audio(message):
bot.send_voice(message.chat.id, 'AwACAgIAAxkBAAIJrWOg2WUvLwrf7ahyJxQHB8_nqllwAAL5JQAC2_IJSbhfQIO5YnVmLAQ') bot.send_voice(
message.chat.id,
"AwACAgIAAxkBAAIJrWOg2WUvLwrf7ahyJxQHB8_nqllwAAL5JQAC2_IJSbhfQIO5YnVmLAQ",
)
@bot.message_handler(commands=['tr', 'тр']) @bot.message_handler(commands=["tr", "тр"])
def translate_layout(message): def translate_layout(message):
if message.reply_to_message and message.reply_to_message.text: if message.reply_to_message and message.reply_to_message.text:
if message.reply_to_message.text[0] in RUS: if message.reply_to_message.text[0] in RUS:
bot.send_message(message.chat.id, message.reply_to_message.text.translate(RUS_ENG_TABLE)) bot.send_message(
message.chat.id, message.reply_to_message.text.translate(RUS_ENG_TABLE)
)
else: else:
bot.send_message(message.chat.id, message.reply_to_message.text.translate(ENG_RUS_TABLE)) bot.send_message(
message.chat.id, message.reply_to_message.text.translate(ENG_RUS_TABLE)
)
@bot.message_handler(commands=['quote', 'цитата']) @bot.message_handler(commands=["quote", "цитата"])
def stan_speak(message): def stan_speak(message):
bot.send_message(message.chat.id, stan.speak(0)) bot.send_message(message.chat.id, stan.speak(0))
@bot.message_handler(commands=['tsya', 'тся', 'ться']) @bot.message_handler(commands=["tsya", "тся", "ться"])
def send_tsya(message: types.Message): def send_tsya(message: types.Message):
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton('🧑🏼‍🎓 Читать правило', url='https://tsya.ru/'), row_width=1) markup.add(
send_or_reply(message, '<i>-тся</i> и <i>-ться</i> в глаголах', reply_markup=markup) types.InlineKeyboardButton("🧑🏼‍🎓 Читать правило", url="https://tsya.ru/"),
row_width=1,
)
send_or_reply(message, "<i>-тся</i> и <i>-ться</i> в глаголах", reply_markup=markup)
@bot.message_handler(commands=['nometa', 'номета']) @bot.message_handler(commands=["nometa", "номета"])
def send_nometa(message: types.Message): def send_nometa(message: types.Message):
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton('❓ nometa.xyz', url='https://nometa.xyz/ru.html'), row_width=1) markup.add(
send_or_reply(message, """Не задавай мета-вопросов вроде: types.InlineKeyboardButton("❓ nometa.xyz", url="https://nometa.xyz/ru.html"),
row_width=1,
)
send_or_reply(
message,
"""Не задавай мета-вопросов вроде:
<i> «Можно задать вопрос?» <i> «Можно задать вопрос?»
«Кто-нибудь пользовался .. ?» «Кто-нибудь пользовался .. ?»
«Привет, мне нужна помощь по .. !»</i> «Привет, мне нужна помощь по .. !»</i>
Просто спроси сразу! И чем лучше объяснишь проблему, тем вероятнее получишь помощь.""", reply_markup=markup) Просто спроси сразу! И чем лучше объяснишь проблему, тем вероятнее получишь помощь.""",
reply_markup=markup,
)
@bot.message_handler(commands=['neprivet', 'непривет']) @bot.message_handler(commands=["neprivet", "непривет"])
def send_neprivet(message: types.Message): def send_neprivet(message: types.Message):
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton('👋 Непривет', url='https://neprivet.com/'), row_width=1) markup.add(
send_or_reply(message, 'Пожалуйста, не пишите просто «Привет» в чате.', reply_markup=markup) types.InlineKeyboardButton("👋 Непривет", url="https://neprivet.com/"),
row_width=1,
)
send_or_reply(
message, "Пожалуйста, не пишите просто «Привет» в чате.", reply_markup=markup
)
@bot.message_handler(commands=['nojob', 'ноджоб']) @bot.message_handler(commands=["nojob", "ноджоб"])
def send_nojob(message): def send_nojob(message):
logging.warning('Sent no job') logging.warning("Sent no job")
answer = """Мы здесь не для того, чтобы за тебя решать задачи. answer = """Мы здесь не для того, чтобы за тебя решать задачи.
Здесь помогают по конкретным вопросам в <u>ТВОЁМ</u> коде, поэтому тебе нужно показать код, который ты написал сам и объяснить где и почему застрял... всё просто. 🤷🏼️""" Здесь помогают по конкретным вопросам в <u>ТВОЁМ</u> коде, поэтому тебе нужно показать код, который ты написал сам и \
объяснить где и почему застрял... всё просто. 🤷🏼️"""
send_or_reply(message, answer) send_or_reply(message, answer)
@bot.message_handler(commands=['nobot', 'нобот']) @bot.message_handler(commands=["nobot", "нобот"])
def nobot(message: types.Message): def nobot(message: types.Message):
answer = """<b>Внимание</b>: answer = """<b>Внимание</b>:
Телеграм бот <i>не должен</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, <code>работу с модулями</code>, <code>основы веб-технологий</code>, <code>асинхронное программирование</code> и <code>отладку</code> до начала работы с Телеграм ботами. Существует много ресурсов для этого в интернете.""" Телеграм бот <i>не должен</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, \
<code>работу с модулями</code>, <code>основы веб-технологий</code>, <code>асинхронное программирование</code> и \
<code>отладку</code> до начала работы с Телеграм ботами. Существует много ресурсов для этого в интернете."""
send_or_reply(message, answer) send_or_reply(message, answer)
@bot.message_handler(commands=['nogui', 'ногуи']) @bot.message_handler(commands=["nogui", "ногуи"])
def nogui(message: types.Message): def nogui(message: types.Message):
answer = """<b>Внимание</b>: answer = """<b>Внимание</b>:
GUI приложение <i>не должно</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, <code>работу с модулями</code>, <code>циклы событий</code> и <code>отладку</code> до начала работы с какими-либо GUI-фреймворками. Существует много ресурсов для этого в интернете.""" GUI приложение <i>не должно</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, \
<code>работу с модулями</code>, <code>циклы событий</code> и <code>отладку</code> до начала работы с какими-либо \
GUI-фреймворками. Существует много ресурсов для этого в интернете."""
send_or_reply(message, answer) send_or_reply(message, answer)
@bot.message_handler(commands=['g', 'г']) @bot.message_handler(commands=["g", "г"])
def google_it(message: types.Message): def google_it(message: types.Message):
""" Google it! """ """Google it!"""
query = f'<i>{detect_args(message)}</i>' query = f"<i>{detect_args(message)}</i>"
get_query = 'https://www.google.com/search?q=' + represent_as_get(message) get_query = "https://www.google.com/search?q=" + represent_as_get(message)
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton('🔍 Google Поиск', url=get_query), row_width=1) markup.add(types.InlineKeyboardButton("🔍 Google Поиск", url=get_query), row_width=1)
send_or_reply(message, f'<i>Ищем «{query}»...</i>', reply_markup=markup) send_or_reply(message, f"<i>Ищем «{query}»...</i>", reply_markup=markup)
""" [ ADMIN PANEL ] """ """ [ ADMIN PANEL ] """
@bot.message_handler(func=is_admin, commands=['ddel']) @bot.message_handler(func=is_admin, commands=["ddel"])
def delete_user(message: types.Message): def delete_user(message: types.Message):
if message.reply_to_message: if message.reply_to_message:
bot.delete_message(message.chat.id, message.id) bot.delete_message(message.chat.id, message.id)
bot.delete_message(message.chat.id, message.reply_to_message.id) bot.delete_message(message.chat.id, message.reply_to_message.id)
logging.warning( logging.warning(
f'[DEL (M)] {message.reply_to_message.from_user.id} {message.reply_to_message.from_user.first_name} - {message.reply_to_message.text}') f"[DEL (M)] {message.reply_to_message.from_user.id} {message.reply_to_message.from_user.first_name} - \
{message.reply_to_message.text}"
)
@bot.message_handler(func=is_admin, commands=['bban']) @bot.message_handler(func=is_admin, commands=["bban"])
def ban_user(message: types.Message): def ban_user(message: types.Message):
if message.reply_to_message: if message.reply_to_message:
bot.delete_message(message.chat.id, message.id) bot.delete_message(message.chat.id, message.id)
bot.delete_message(message.chat.id, message.reply_to_message.id) bot.delete_message(message.chat.id, message.reply_to_message.id)
bot.ban_chat_member(message.chat.id, message.reply_to_message.from_user.id) bot.ban_chat_member(message.chat.id, message.reply_to_message.from_user.id)
logging.warning( logging.warning(
f'[BAN (M)] {message.reply_to_message.from_user.id} {message.reply_to_message.from_user.first_name} - {message.reply_to_message.text}') f"[BAN (M)] {message.reply_to_message.from_user.id} {message.reply_to_message.from_user.first_name} - \
{message.reply_to_message.text}"
)
@bot.message_handler(func=is_admin, commands=['unban_id']) @bot.message_handler(func=is_admin, commands=["unban_id"])
def unban_user(message: types.Message): def unban_user(message: types.Message):
if message.text.split()[-1].isdigit(): if message.text.split()[-1].isdigit():
user_id = int(message.text.split()[-1]) user_id = int(message.text.split()[-1])
bot.unban_chat_member(PYTHONCHATRU, user_id) bot.unban_chat_member(PYTHONCHATRU, user_id)
logging.warning(f'[UNBAN (M)] {user_id}') logging.warning(f"[UNBAN (M)] {user_id}")
""" [ INLINE ] """ """ [ INLINE ] """
@@ -196,14 +237,19 @@ def unban_user(message: types.Message):
@bot.inline_handler(lambda query: True) @bot.inline_handler(lambda query: True)
def default_query(inline_query): def default_query(inline_query):
""" Inline the Zen of Python. """ """Inline the Zen of Python."""
zen = [] zen = []
for id_p, phrase in enumerate(ZEN): for id_p, phrase in enumerate(ZEN):
q = inline_query.query.casefold() q = inline_query.query.casefold()
if phrase.casefold().startswith(q) or ' ' + q in phrase.casefold(): if phrase.casefold().startswith(q) or " " + q in phrase.casefold():
zen.append(types.InlineQueryResultArticle( zen.append(
f"{id_p}", f'The Zen of Python #{id_p + 1}', types.InputTextMessageContent( types.InlineQueryResultArticle(
f"{phrase}"), description=phrase)) f"{id_p}",
f"The Zen of Python #{id_p + 1}",
types.InputTextMessageContent(f"{phrase}"),
description=phrase,
)
)
bot.answer_inline_query(inline_query.id, zen, cache_time=1200) bot.answer_inline_query(inline_query.id, zen, cache_time=1200)
@@ -211,10 +257,20 @@ def default_query(inline_query):
""" [ COUNTER ] """ """ [ COUNTER ] """
@bot.message_handler(content_types=['text', 'sticker', 'photo', 'animation', 'video', 'audio', 'document'], @bot.message_handler(
chat_types=['supergroup', 'group']) content_types=[
"text",
"sticker",
"photo",
"animation",
"video",
"audio",
"document",
],
chat_types=["supergroup", "group"],
)
def handle_msg(message: types.Message): def handle_msg(message: types.Message):
""" Count messages, Stan. """ """Count messages, Stan."""
update_stats(message) update_stats(message)
stan.act(message) stan.act(message)
@@ -222,13 +278,13 @@ def handle_msg(message: types.Message):
""" [ WEBHOOK ] """ """ [ WEBHOOK ] """
@app.route(f"/bot{TOKEN}/", methods=['POST']) @app.route(f"/bot{TOKEN}/", methods=["POST"])
def webhook(): def webhook():
""" Parse POST requests from Telegram. """ """Parse POST requests from Telegram."""
if request.headers.get('content-type') == 'application/json': if request.headers.get("content-type") == "application/json":
json_string = request.get_data().decode('utf-8') json_string = request.get_data().decode("utf-8")
update = types.Update.de_json(json_string) update = types.Update.de_json(json_string)
bot.process_new_updates([update]) bot.process_new_updates([update])
return '' return ""
else: else:
abort(403) abort(403)
+15 -6
View File
@@ -1,19 +1,28 @@
from telebot.types import LabeledPrice, Message, PreCheckoutQuery from telebot.types import LabeledPrice, Message, PreCheckoutQuery
from ..config import YOOPAY, bot from ..config import YOOPAY, bot
prices = [LabeledPrice('Сумма', 100_00)] prices = [LabeledPrice("Сумма", 100_00)]
@bot.message_handler(commands=['donate']) @bot.message_handler(commands=["donate"])
def request_invoice(message: Message): def request_invoice(message: Message):
bot.send_invoice(message.chat.id, 'Поддержать проект', 'Stan', 'donate_stan', provider_token=YOOPAY, bot.send_invoice(
currency='RUB', prices=prices, message.chat.id,
"Поддержать проект",
"Stan",
"donate_stan",
provider_token=YOOPAY,
currency="RUB",
prices=prices,
provider_data='{"capture": true}', provider_data='{"capture": true}',
max_tip_amount=500_000_00, max_tip_amount=500_000_00,
suggested_tip_amounts=[150_00, 300_00, 500_00, 1_000_00], capture=True, suggested_tip_amounts=[150_00, 300_00, 500_00, 1_000_00],
capture=True,
) )
@bot.pre_checkout_query_handler(func=lambda a: True) @bot.pre_checkout_query_handler(func=lambda a: True)
def process_pre_checkout(q: PreCheckoutQuery): def process_pre_checkout(q: PreCheckoutQuery):
bot.answer_pre_checkout_query(q.id, True, 'Извините, пожертвования больше не принимаем!') bot.answer_pre_checkout_query(
q.id, True, "Извините, пожертвования больше не принимаем!"
)
+5 -3
View File
@@ -2,9 +2,11 @@ from urllib.request import urlopen
def my_ip(): def my_ip():
ip_service = 'https://icanhazip.com' ip_service = "https://icanhazip.com"
ip = urlopen(ip_service, ) ip = urlopen(
return ip.read().decode('utf-8') ip_service,
)
return ip.read().decode("utf-8")
def me(message): def me(message):
+24 -17
View File
@@ -10,20 +10,20 @@ from ..filters import is_admin
from .get import me, my_ip from .get import me, my_ip
@bot.message_handler(commands=['me']) @bot.message_handler(commands=["me"])
def command_me(message): def command_me(message):
""" Send info about user and chat id [Service]. """ """Send info about user and chat id [Service]."""
bot.send_message(message.chat.id, me(message)) bot.send_message(message.chat.id, me(message))
@bot.message_handler(func=is_admin, commands=['ip']) @bot.message_handler(func=is_admin, commands=["ip"])
def get_ip(message): def get_ip(message):
bot.send_message(message.chat.id, my_ip()) bot.send_message(message.chat.id, my_ip())
@bot.message_handler(commands=['remind']) @bot.message_handler(commands=["remind"])
def remind_manually(message): def remind_manually(message):
""" Remind holidays manually. """ """Remind holidays manually."""
args = message.text.split() args = message.text.split()
if len(args) > 1: if len(args) > 1:
try: try:
@@ -33,38 +33,45 @@ def remind_manually(message):
else: else:
reminder.remind(message.chat.id, today) reminder.remind(message.chat.id, today)
else: else:
bot.send_message(message.chat.id, f"<b>Формат даты: MM-DD-YYYY</b>\n\n" bot.send_message(
message.chat.id,
f"<b>Формат даты: MM-DD-YYYY</b>\n\n"
f"Примеры:\n" f"Примеры:\n"
f"/remind 09-12-2024\n" f"/remind 09-12-2024\n"
f"/remind 09-13-2022") f"/remind 09-13-2022",
)
@bot.message_handler(func=is_admin, commands=['jobs']) @bot.message_handler(func=is_admin, commands=["jobs"])
def list_jobs(message): def list_jobs(message):
""" List all the jobs in schedule. """ """List all the jobs in schedule."""
bot.send_message(ADMIN_ID, reminder.print_get_jobs()) bot.send_message(ADMIN_ID, reminder.print_get_jobs())
@bot.message_handler(func=is_admin, commands=['stats']) @bot.message_handler(func=is_admin, commands=["stats"])
def send_stats(message: types.Message): def send_stats(message: types.Message):
if len(message.text.split()) == 1: if len(message.text.split()) == 1:
rep = report.create_report_text(message.chat.id) rep = report.create_report_text(message.chat.id)
if rep: if rep:
bot.send_message(message.chat.id, rep) bot.send_message(message.chat.id, rep)
else: else:
bot.send_message(message.chat.id, report.create_report_text(message.text.split()[-1])) bot.send_message(
message.chat.id, report.create_report_text(message.text.split()[-1])
)
@bot.message_handler(func=is_admin, commands=['reset_stats'], chat_types=['supergroup', 'group']) @bot.message_handler(
func=is_admin, commands=["reset_stats"], chat_types=["supergroup", "group"]
)
def send_stats(message: types.Message): def send_stats(message: types.Message):
logging.warning('reset_stats') logging.warning("reset_stats")
report.reset_report_stats(message.chat.id) report.reset_report_stats(message.chat.id)
bot.send_message(message.chat.id, report.reset_report_stats(message.chat.id)) bot.send_message(message.chat.id, report.reset_report_stats(message.chat.id))
@bot.message_handler(func=is_admin, commands=['reload']) @bot.message_handler(func=is_admin, commands=["reload"])
def send_stats(message): def send_stats(message):
logging.warning('Reloading...') logging.warning("Reloading...")
reloader.reload_modules() reloader.reload_modules()
logging.warning('Reloaded!!!') logging.warning("Reloaded!!!")
bot.send_message(message.chat.id, 'Reloaded successfully') bot.send_message(message.chat.id, "Reloaded successfully")
+63 -28
View File
@@ -5,54 +5,89 @@ from flask import Flask
from telebot import TeleBot, logger, types from telebot import TeleBot, logger, types
from dotenv import load_dotenv from dotenv import load_dotenv
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s', datefmt='%Y.%m.%d %H:%M:%S') logging.basicConfig(
level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%Y.%m.%d %H:%M:%S"
)
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
logging.critical('STAN STARTED!') logging.critical("STAN STARTED!")
load_dotenv() load_dotenv()
TOKEN = os.environ.get('LUTZPYBOT', 'Token not in ENVIRON') TOKEN = os.environ.get("LUTZPYBOT", "Token not in ENVIRON")
YOOPAY = os.environ.get('YOOKASSA') YOOPAY = os.environ.get("YOOKASSA")
bot = TeleBot(TOKEN, 'HTML', disable_web_page_preview=True, allow_sending_without_reply=True, bot = TeleBot(
colorful_logs=True) TOKEN,
"HTML",
disable_web_page_preview=True,
allow_sending_without_reply=True,
colorful_logs=True,
)
app = Flask(__name__) app = Flask(__name__)
DATA = 'data/chat' DATA = "data/chat"
ADMIN_ID = 280887861 # Rykov7 ADMIN_ID = 280887861 # Rykov7
PYTHONCHATRU = -1001338616632 # pythonchatru PYTHONCHATRU = -1001338616632 # pythonchatru
URL_RX = re.compile(r'\w+\.\w+/\w+') URL_RX = re.compile(r"\w+\.\w+/\w+")
ALLOWED_WORDS = ['paste', 'nekobin', 'github', 'google', 'nometa', 'python', 'django', 'flask', 'fastapi', 'wiki', ALLOWED_WORDS = [
'stackoverflow', 'habr', 'medium', 'youtu', 'stepik', 'telegra', '#rtfm', 'support', "paste",
'jetbrains', ] "nekobin",
"github",
"google",
"nometa",
"python",
"django",
"flask",
"fastapi",
"wiki",
"stackoverflow",
"habr",
"medium",
"youtu",
"stepik",
"telegra",
"#rtfm",
"support",
"jetbrains",
]
WHITEIDS = {int(i) for i in os.environ.get('whiteids').split(',')} WHITEIDS = {int(i) for i in os.environ.get("whiteids").split(",")}
ROLLBACK = {int(i) for i in os.environ.get('rollback').split(',')} ROLLBACK = {int(i) for i in os.environ.get("rollback").split(",")}
RUS = """ёйцукенгшщзхъфывапролджэячсмитьбю.Ё!"№;%:?ЙЦУКЕНГШЩЗХЪ/ФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,""" RUS = """ёйцукенгшщзхъфывапролджэячсмитьбю.Ё!"№;%:?ЙЦУКЕНГШЩЗХЪ/ФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,"""
ENG = """`qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?""" ENG = """`qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?"""
RUS_ENG_TABLE = str.maketrans(RUS, ENG) RUS_ENG_TABLE = str.maketrans(RUS, ENG)
ENG_RUS_TABLE = str.maketrans(ENG, RUS) ENG_RUS_TABLE = str.maketrans(ENG, RUS)
RULES = types.InlineKeyboardButton('🟡 Правила чата', url='https://telegra.ph/pythonchatru-07-07') RULES = types.InlineKeyboardButton(
FAQ = types.InlineKeyboardButton('🔵 Частые вопросы', url='https://telegra.ph/faq-10-07-4') "🟡 Правила чата", url="https://telegra.ph/pythonchatru-07-07"
LIB = types.InlineKeyboardButton('📚 Книги', url='https://telegra.ph/what-to-read-10-06') )
FAQ = types.InlineKeyboardButton(
"🔵 Частые вопросы", url="https://telegra.ph/faq-10-07-4"
)
LIB = types.InlineKeyboardButton("📚 Книги", url="https://telegra.ph/what-to-read-10-06")
SPAM = ['me.sv/', 'tg.sv/', 'goo.by/', 'go.sv/', 'intim.video/', 'uclck.ru/'] SPAM = ["me.sv/", "tg.sv/", "goo.by/", "go.sv/", "intim.video/", "uclck.ru/"]
NON_GRATA = ['дудар', 'хауди', 'dudar'] NON_GRATA = ["дудар", "хауди", "dudar"]
BAN_WORDS = ['GREEN'] BAN_WORDS = ["GREEN"]
ZEN = ['Beautiful is better than ugly.', 'Explicit is better than implicit.', 'Simple is better than complex.', ZEN = [
'Complex is better than complicated.', 'Flat is better than nested.', 'Sparse is better than dense.', "Beautiful is better than ugly.",
'Readability counts.', "Explicit is better than implicit.",
"Simple is better than complex.",
"Complex is better than complicated.",
"Flat is better than nested.",
"Sparse is better than dense.",
"Readability counts.",
"Special cases aren't special enough to break the rules. Although practicality beats purity.", "Special cases aren't special enough to break the rules. Although practicality beats purity.",
'Errors should never pass silently. Unless explicitly silenced.', "Errors should never pass silently. Unless explicitly silenced.",
'In the face of ambiguity, refuse the temptation to guess.', "In the face of ambiguity, refuse the temptation to guess.",
'There should be one — and preferably only one — obvious way to do it.', "There should be one — and preferably only one — obvious way to do it.",
'Now is better than never. Although never is often better than *right* now.', "Now is better than never. Although never is often better than *right* now.",
"If the implementation is hard to explain, it's a bad idea.", "If the implementation is hard to explain, it's a bad idea.",
'If the implementation is easy to explain, it may be a good idea.', "If the implementation is easy to explain, it may be a good idea.",
"Namespaces are one honking great idea — let's do more of those!"] "Namespaces are one honking great idea — let's do more of those!",
]
+12 -7
View File
@@ -2,7 +2,7 @@ from .config import *
def in_spam_list(message: types.Message) -> bool: def in_spam_list(message: types.Message) -> bool:
""" Check for mentioning unwanted persons in text. """ """Check for mentioning unwanted persons in text."""
if message.from_user.id not in WHITEIDS: if message.from_user.id not in WHITEIDS:
for url in SPAM: for url in SPAM:
if url in message.text.casefold(): if url in message.text.casefold():
@@ -10,7 +10,7 @@ def in_spam_list(message: types.Message) -> bool:
def in_caption_spam_list(type_message: types.Message) -> bool: def in_caption_spam_list(type_message: types.Message) -> bool:
""" Check for mentioning unwanted words in caption. """ """Check for mentioning unwanted words in caption."""
for phrase in BAN_WORDS: for phrase in BAN_WORDS:
if type_message.caption and phrase in type_message.caption: if type_message.caption and phrase in type_message.caption:
return True return True
@@ -24,21 +24,26 @@ def in_not_allowed(word_list, msg):
def in_delete_list(type_message: types.Message) -> bool: def in_delete_list(type_message: types.Message) -> bool:
""" Check for URLs in message and delete. """ """Check for URLs in message and delete."""
if type_message.from_user.id not in WHITEIDS: if type_message.from_user.id not in WHITEIDS:
if URL_RX.search(type_message.text) and in_not_allowed(ALLOWED_WORDS, type_message.text): if URL_RX.search(type_message.text) and in_not_allowed(
logging.info(f'[DEL] {type_message.from_user.id} {type_message.from_user.first_name} - {type_message.text}') ALLOWED_WORDS, type_message.text
):
logging.info(
f"[DEL] {type_message.from_user.id} {type_message.from_user.first_name} - {type_message.text}"
)
return True return True
if type_message.entities: if type_message.entities:
for entity in type_message.entities: for entity in type_message.entities:
if entity.url and in_not_allowed(ALLOWED_WORDS, entity.url): if entity.url and in_not_allowed(ALLOWED_WORDS, entity.url):
logging.info( logging.info(
f'[DEL] {type_message.from_user.id} {type_message.from_user.first_name} - Entity ({entity.url})') f"[DEL] {type_message.from_user.id} {type_message.from_user.first_name} - Entity ({entity.url})"
)
return True return True
def is_nongrata(type_message: types.Message) -> bool: def is_nongrata(type_message: types.Message) -> bool:
""" Check for non grata persons. """ """Check for non grata persons."""
for phrase in NON_GRATA: for phrase in NON_GRATA:
if phrase in type_message.text.casefold(): if phrase in type_message.text.casefold():
return True return True
+13 -8
View File
@@ -16,19 +16,24 @@ def detect_args(message: types.Message):
if len(message.text.split()) == 1: if len(message.text.split()) == 1:
return message.reply_to_message.text return message.reply_to_message.text
else: else:
return ' '.join(message.text.split()[1:]) return " ".join(message.text.split()[1:])
else: else:
if len(message.text.split()) > 1: if len(message.text.split()) > 1:
return ' '.join(message.text.split()[1:]) return " ".join(message.text.split()[1:])
def update_stats(message: types.Message): def update_stats(message: types.Message):
with shelve.open(f'{DATA}{message.chat.id}', writeback=True) as s: with shelve.open(f"{DATA}{message.chat.id}", writeback=True) as s:
if 'Messages' not in s: if "Messages" not in s:
report.reset_report_stats(message.chat.id) report.reset_report_stats(message.chat.id)
if message.from_user.id not in s['Messages']: if message.from_user.id not in s["Messages"]:
s['Messages'][message.from_user.id] = {'User': message.from_user, 'Count': 1} s["Messages"][message.from_user.id] = {
logging.warning(f'CNTR {message.chat.id}: {message.from_user.first_name} ({message.from_user.id})') "User": message.from_user,
"Count": 1,
}
logging.warning(
f"CNTR {message.chat.id}: {message.from_user.first_name} ({message.from_user.id})"
)
else: else:
s['Messages'][message.from_user.id]['Count'] += 1 s["Messages"][message.from_user.id]["Count"] += 1
+10 -10
View File
@@ -15,28 +15,28 @@ def scheduler():
time.sleep(300) time.sleep(300)
@repeat(every().day.at('07:00'), PYTHONCHATRU, None) @repeat(every().day.at("07:00"), PYTHONCHATRU, None)
def remind(chat_to_repeat, today): def remind(chat_to_repeat, today):
""" Remind holiday. """ """Remind holiday."""
if not today: if not today:
today = dt.today() today = dt.today()
with open('holidays.csv', newline='', encoding='utf-8') as holidays_file: with open("holidays.csv", newline="", encoding="utf-8") as holidays_file:
holidays = tuple(csv.reader(holidays_file))[1:] holidays = tuple(csv.reader(holidays_file))[1:]
for entry in holidays: for entry in holidays:
date, holiday, description = entry date, holiday, description = entry
if today.year % 4 == 0 and holiday == 'День программиста': if today.year % 4 == 0 and holiday == "День программиста":
date = '09-12-1000' # instead of 09-13-1000 in non-leap-year date = "09-12-1000" # instead of 09-13-1000 in non-leap-year
date = dt.strptime(date, "%m-%d-%Y") date = dt.strptime(date, "%m-%d-%Y")
if today.month == date.month and today.day == date.day: if today.month == date.month and today.day == date.day:
notification = f'🎉 Сегодня <b><u>{holiday.upper()}</u></b>!\ notification = f"🎉 Сегодня <b><u>{holiday.upper()}</u></b>!\
\n\n{description}.' \n\n{description}."
if date.year != 1000: if date.year != 1000:
age = today.year - date.year age = today.year - date.year
notification += f'\n\n🥳 <i>{age}-ая годовщина</i>' notification += f"\n\n🥳 <i>{age}-ая годовщина</i>"
bot.send_message(chat_to_repeat, notification) bot.send_message(chat_to_repeat, notification)
@repeat(every().day.at('06:00'), PYTHONCHATRU) @repeat(every().day.at("06:00"), PYTHONCHATRU)
def stat_report(chat_to_repeat): def stat_report(chat_to_repeat):
rep = report.create_report_text(PYTHONCHATRU) rep = report.create_report_text(PYTHONCHATRU)
if rep: if rep:
@@ -48,7 +48,7 @@ def print_get_jobs():
all_jobs = get_jobs() all_jobs = get_jobs()
text = f"├ <b>Jobs:</b> {str(len(all_jobs))}\ text = f"├ <b>Jobs:</b> {str(len(all_jobs))}\
\n├ {dt.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" \n├ {dt.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
text += '<i>' + str(all_jobs) + '</i>' text += "<i>" + str(all_jobs) + "</i>"
return text return text
+27 -18
View File
@@ -4,31 +4,40 @@ from .config import DATA, ROLLBACK
def create_report_text(chat_id): def create_report_text(chat_id):
report = '' report = ""
top_users = '' top_users = ""
flooders = [] flooders = []
if os.path.exists(f'{DATA}{chat_id}.db'): if os.path.exists(f"{DATA}{chat_id}.db"):
with shelve.open(f'{DATA}{chat_id}', writeback=True) as s: with shelve.open(f"{DATA}{chat_id}", writeback=True) as s:
for user_id in ROLLBACK: for user_id in ROLLBACK:
if user_id in s['Messages'] and s['Messages'][user_id]['Count'] > 10: if user_id in s["Messages"] and s["Messages"][user_id]["Count"] > 10:
s['Messages'][user_id]['Count'] //= 3 s["Messages"][user_id]["Count"] //= 3
for n in range(min(3, len(s['Messages']))): for n in range(min(3, len(s["Messages"]))):
top_user = s['Messages'][ top_user = s["Messages"][
sorted(s['Messages'], key=lambda a: s['Messages'][a]['Count'], reverse=True)[n]] sorted(
if top_user['Count'] >= 5: s["Messages"],
key=lambda a: s["Messages"][a]["Count"],
reverse=True,
)[n]
]
if top_user["Count"] >= 5:
flooders.append(top_user) flooders.append(top_user)
for i, flooder in enumerate(flooders): for i, flooder in enumerate(flooders):
user = flooder["User"] user = flooder["User"]
name = f"{user.first_name} {user.last_name}" if user.last_name else user.first_name name = (
f"{user.first_name} {user.last_name}"
if user.last_name
else user.first_name
)
top_users += f'\n {i + 1}. {name} [<code>{flooder["Count"]}</code>]' top_users += f'\n {i + 1}. {name} [<code>{flooder["Count"]}</code>]'
if len(flooders) >= 3 or s['Banned'] or s['Deleted']: if len(flooders) >= 3 or s["Banned"] or s["Deleted"]:
report = f"<code>Hello, World!</code>\n" report = f"<code>Hello, World!</code>\n"
if len(flooders) >= 3: if len(flooders) >= 3:
report += f"\n<b>Топ</b> 🐍{top_users}\n" report += f"\n<b>Топ</b> 🐍{top_users}\n"
if s['Banned'] or s['Deleted']: if s["Banned"] or s["Deleted"]:
report += f""" report += f"""
<b>Заблокировано</b> <b>Заблокировано</b>
├ Пользователей: <code>{s['Banned']}</code> ├ Пользователей: <code>{s['Banned']}</code>
@@ -36,14 +45,14 @@ def create_report_text(chat_id):
""" """
return report return report
else: else:
return f'Невозможно получить статистику.\n{DATA}{chat_id}.db не существует, возможно запрос в приватном чате. ' return f"Невозможно получить статистику.\n{DATA}{chat_id}.db не существует, возможно запрос в приватном чате. "
def reset_report_stats(chat_id): def reset_report_stats(chat_id):
with shelve.open(f'{DATA}{chat_id}') as s: with shelve.open(f"{DATA}{chat_id}") as s:
s['Messages'] = {} s["Messages"] = {}
s['Banned'] = 0 s["Banned"] = 0
s['Deleted'] = 0 s["Deleted"] = 0
return f"""Chat ID: {chat_id} return f"""Chat ID: {chat_id}
{s['Messages']=} {s['Messages']=}
+3 -3
View File
@@ -1,13 +1,13 @@
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from urllib.request import urlopen from urllib.request import urlopen
html = BeautifulSoup(urlopen('https://telegra.ph/pythonchatru-07-07'), 'lxml') html = BeautifulSoup(urlopen("https://telegra.ph/pythonchatru-07-07"), "lxml")
def fetch_rule(li): def fetch_rule(li):
li = int(li) li = int(li)
lis = html.find_all('li') lis = html.find_all("li")
if li <= len(lis): if li <= len(lis):
return lis[li - 1].text return lis[li - 1].text
else: else:
return f'Пока не придумали.' return f"Пока не придумали."
+46 -23
View File
@@ -9,14 +9,18 @@ from .filters import is_white, is_nongrata
def speak(chance_of): def speak(chance_of):
number = random.randint(0, chance_of) number = random.randint(0, chance_of)
if number == 0: if number == 0:
return random.choice([i.rstrip() for i in open('Stan.txt', 'r', encoding='utf8') if i]) return random.choice(
[i.rstrip() for i in open("Stan.txt", "r", encoding="utf8") if i]
)
def send_quote(after_sec, message, quote): def send_quote(after_sec, message, quote):
""" Pretend Reading, pretend Typing, send. """ """Pretend Reading, pretend Typing, send."""
if message.text: if message.text:
sleep(len(message.text) * 0.13 / 4) # Reading time is quarter of the same text writing time sleep(
bot.send_chat_action(message.chat.id, action='typing') len(message.text) * 0.13 / 4
) # Reading time is quarter of the same text writing time
bot.send_chat_action(message.chat.id, action="typing")
sleep(after_sec) # Typing time sleep(after_sec) # Typing time
bot.send_message(message.chat.id, quote) bot.send_message(message.chat.id, quote)
@@ -24,37 +28,56 @@ def send_quote(after_sec, message, quote):
def act(message): def act(message):
quote = speak(50) quote = speak(50)
if quote: if quote:
threading.Thread(target=send_quote, args=(len(quote) * 0.13, message, quote)).start() threading.Thread(
target=send_quote, args=(len(quote) * 0.13, message, quote)
).start()
@bot.message_handler(func=is_white, commands=['add']) @bot.message_handler(func=is_white, commands=["add"])
def add_stan_quote(message): def add_stan_quote(message):
if message.reply_to_message and message.reply_to_message.text: if message.reply_to_message and message.reply_to_message.text:
with open('Stan.txt', 'a', encoding='utf8') as stan_quotes: with open("Stan.txt", "a", encoding="utf8") as stan_quotes:
if message.reply_to_message.text not in (i.rstrip() for i in open('Stan.txt', 'r', encoding='utf8')): if message.reply_to_message.text not in (
stan_quotes.write(message.reply_to_message.text.replace('\n', ' ') + '\n') i.rstrip() for i in open("Stan.txt", "r", encoding="utf8")
bot.send_message(message.chat.id, ):
'✅ <b>Добавил</b>\n └ <i>' + message.reply_to_message.text.replace("\n", stan_quotes.write(
" ") + '</i>') message.reply_to_message.text.replace("\n", " ") + "\n"
)
bot.send_message(
message.chat.id,
"✅ <b>Добавил</b>\n └ <i>"
+ message.reply_to_message.text.replace("\n", " ")
+ "</i>",
)
else: else:
bot.send_message(message.chat.id, bot.send_message(
f'⛔️ <b>Не добавил</b>, есть токое\n └ <i>{message.reply_to_message.text}</i>') message.chat.id,
f"⛔️ <b>Не добавил</b>, есть токое\n └ <i>{message.reply_to_message.text}</i>",
)
@bot.message_handler(func=is_white, commands=['remove']) @bot.message_handler(func=is_white, commands=["remove"])
def remove_stan_quote(message): def remove_stan_quote(message):
if message.reply_to_message and message.reply_to_message.text: if message.reply_to_message and message.reply_to_message.text:
if message.reply_to_message.text in (i.rstrip() for i in open('Stan.txt', 'r', encoding='utf8')): if message.reply_to_message.text in (
quotes = list(open('Stan.txt', 'r', encoding='utf8')) i.rstrip() for i in open("Stan.txt", "r", encoding="utf8")
with open('Stan.txt', 'w', encoding='utf8') as stan_quotes: ):
quotes.remove(message.reply_to_message.text + '\n') quotes = list(open("Stan.txt", "r", encoding="utf8"))
with open("Stan.txt", "w", encoding="utf8") as stan_quotes:
quotes.remove(message.reply_to_message.text + "\n")
stan_quotes.writelines(quotes) stan_quotes.writelines(quotes)
bot.send_message(message.chat.id, f'✅ <b>Удалил</b>\n └ <i>{message.reply_to_message.text}</i>') bot.send_message(
message.chat.id,
f"✅ <b>Удалил</b>\n └ <i>{message.reply_to_message.text}</i>",
)
else: else:
bot.send_message(message.chat.id, f'⛔️ <b>Нет такого</b>\n └ <i>{message.reply_to_message.text}</i>') bot.send_message(
message.chat.id,
f"⛔️ <b>Нет такого</b>\n └ <i>{message.reply_to_message.text}</i>",
)
@bot.message_handler(func=is_nongrata) @bot.message_handler(func=is_nongrata)
def tease_nongrata(message: types.Message): def tease_nongrata(message: types.Message):
""" Reply to non grata mentions. """ """Reply to non grata mentions."""
bot.reply_to(message, f'у нас тут таких не любят') bot.reply_to(message, f"у нас тут таких не любят")
+1 -1
View File
@@ -1,7 +1,7 @@
"Date (mm-dd-yyyy)","Name","Description" "Date (mm-dd-yyyy)","Name","Description"
"02-20-1991","День рождения Python","Задумка по реализации языка появилась в конце 1980-х годов, а разработка его реализации началась в 1989 году сотрудником голландского института CWI Гвидо ван Россумом" "02-20-1991","День рождения Python","Задумка по реализации языка появилась в конце 1980-х годов, а разработка его реализации началась в 1989 году сотрудником голландского института CWI Гвидо ван Россумом"
"04-01-2010","День рождения Flask","Flask — фреймворк для создания веб-приложений на языке программирования Python. Создатель и основной автор — австрийский программист Армин Ронахер" "04-01-2010","День рождения Flask","Flask — фреймворк для создания веб-приложений на языке программирования Python. Создатель и основной автор — австрийский программист Армин Ронахер"
"04-04-1000","День веб-мастера","4 апреля — «404» — отмечают свой профессиональный праздник неутомимые веб-мастера и интернет-разработчики" "04-04-1000","День веб-разработчика","4 апреля — «404» — отмечают свой профессиональный праздник веб-разработчики"
"04-07-1994","День рождения Рунета","7 апреля 1994 года для России был зарегистрирован домен — .Ru — и внесен в международную базу данных национальных доменов верхнего уровня" "04-07-1994","День рождения Рунета","7 апреля 1994 года для России был зарегистрирован домен — .Ru — и внесен в международную базу данных национальных доменов верхнего уровня"
"07-21-2005","День рождения Django","Джанго — свободный фреймворк для веб-приложений на языке Python. Авторы: американский веб-разработчик Адриан Головатый и британский программист Саймон Уиллисон" "07-21-2005","День рождения Django","Джанго — свободный фреймворк для веб-приложений на языке Python. Авторы: американский веб-разработчик Адриан Головатый и британский программист Саймон Уиллисон"
"08-25-1991","День рождения Linux","Именно 25 августа 1991 года после нескольких месяцев разработки 21-летний студент Линус Торвальдс на конференции comp. os. minix заявил о создании рабочего прототипа новой ОС под названием Linux" "08-25-1991","День рождения Linux","Именно 25 августа 1991 года после нескольких месяцев разработки 21-летний студент Линус Торвальдс на конференции comp. os. minix заявил о создании рабочего прототипа новой ОС под названием Linux"
1 Date (mm-dd-yyyy) Name Description
2 02-20-1991 День рождения Python Задумка по реализации языка появилась в конце 1980-х годов, а разработка его реализации началась в 1989 году сотрудником голландского института CWI Гвидо ван Россумом
3 04-01-2010 День рождения Flask Flask — фреймворк для создания веб-приложений на языке программирования Python. Создатель и основной автор — австрийский программист Армин Ронахер
4 04-04-1000 День веб-мастера День веб-разработчика 4 апреля — «404» — отмечают свой профессиональный праздник неутомимые веб-мастера и интернет-разработчики 4 апреля — «404» — отмечают свой профессиональный праздник веб-разработчики
5 04-07-1994 День рождения Рунета 7 апреля 1994 года для России был зарегистрирован домен — .Ru — и внесен в международную базу данных национальных доменов верхнего уровня
6 07-21-2005 День рождения Django Джанго — свободный фреймворк для веб-приложений на языке Python. Авторы: американский веб-разработчик Адриан Головатый и британский программист Саймон Уиллисон
7 08-25-1991 День рождения Linux Именно 25 августа 1991 года после нескольких месяцев разработки 21-летний студент Линус Торвальдс на конференции comp. os. minix заявил о создании рабочего прототипа новой ОС под названием Linux
+1 -1
View File
@@ -1,4 +1,4 @@
from app.bot import app from app.bot import app
if __name__ == '__main__': if __name__ == "__main__":
app.run(debug=False) app.run(debug=False)