182 lines
5.6 KiB
Python
182 lines
5.6 KiB
Python
|
import os
|
||
|
import logging
|
||
|
|
||
|
from telegram import *
|
||
|
from telegram.ext import *
|
||
|
|
||
|
from ctftime_client import CTFTimeClient
|
||
|
from dbs import CTFDb, GroupDb
|
||
|
|
||
|
db = CTFDb()
|
||
|
groups = GroupDb()
|
||
|
|
||
|
TOKEN = os.environ['BOT_TOKEN']
|
||
|
|
||
|
# Enable logging
|
||
|
logging.basicConfig(format='%(asctime)s - %(name)s - \
|
||
|
%(levelname)s - %(message)s',
|
||
|
level=logging.INFO)
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
def error(bot, update, error):
|
||
|
logger.warning('Update "%s" caused error "%s"' % (update, error))
|
||
|
|
||
|
|
||
|
def start(bot, update):
|
||
|
"""Start the bot reminder about starting and announced CTF"""
|
||
|
groups.add(update.message.chat_id)
|
||
|
update.message.reply_text('Hi! I will notify you when new CTFs \
|
||
|
are announced and remind them!')
|
||
|
|
||
|
|
||
|
def stop(bot, update):
|
||
|
"""Start the bot reminder about starting and announced CTF"""
|
||
|
groups.remove(update.message.chat_id)
|
||
|
update.message.reply_text('Stopped')
|
||
|
|
||
|
|
||
|
def fetch(bot, job):
|
||
|
"""Job function to check for newly announced CTFs"""
|
||
|
to_print = db.add_events(CTFTimeClient.fetch_data())
|
||
|
if to_print is []:
|
||
|
return
|
||
|
|
||
|
message = ""
|
||
|
for ctf in to_print:
|
||
|
message += db.starting_message(ctf)
|
||
|
|
||
|
if message is not "":
|
||
|
message = "*New CTF announced:*\n" + message
|
||
|
for element in groups.groups:
|
||
|
bot.sendMessage(element,
|
||
|
text=message,
|
||
|
parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
|
||
|
|
||
|
def starting(bot, job):
|
||
|
"""Job function to check for newly announced CTFs"""
|
||
|
to_print = db.starting_ctf()
|
||
|
if to_print is []:
|
||
|
return
|
||
|
|
||
|
message = ""
|
||
|
for ctf in to_print:
|
||
|
message += db.starting_message(ctf)
|
||
|
|
||
|
if message is not "":
|
||
|
message = "*The following CTF are starting in less than 24 hours:*\n" + message
|
||
|
for element in groups.groups:
|
||
|
bot.sendMessage(element,
|
||
|
text=message,
|
||
|
parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
|
||
|
|
||
|
def upcoming(bot, update):
|
||
|
"""List 5 upcoming CTFs in database"""
|
||
|
message = ""
|
||
|
for ctf in db.upcoming():
|
||
|
message += db.starting_message(ctf)
|
||
|
|
||
|
if message is not "":
|
||
|
message = "*Upcoming events:*\n" + message
|
||
|
bot.sendMessage(update.message.chat_id,
|
||
|
text=message,
|
||
|
parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
else:
|
||
|
bot.sendMessage(update.message.chat_id,
|
||
|
text="No upcoming CTF")
|
||
|
|
||
|
|
||
|
def current(bot, update):
|
||
|
"""List current running CTFs in database"""
|
||
|
message = ""
|
||
|
for ctf in db.running():
|
||
|
message += db.finishing_message(ctf)
|
||
|
|
||
|
if message is not "":
|
||
|
message = "*Now running events:*\n" + message
|
||
|
bot.sendMessage(update.message.chat_id,
|
||
|
text=message,
|
||
|
parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
else:
|
||
|
bot.sendMessage(update.message.chat_id,
|
||
|
text="No CTF is currently running")
|
||
|
|
||
|
|
||
|
def info(bot, update, args):
|
||
|
"""Get info form a given CTFid"""
|
||
|
if len(args) != 1:
|
||
|
update.message.reply_text('Usage: `/info <ctf_id>`',
|
||
|
parse_mode='MARKDOWN')
|
||
|
return
|
||
|
|
||
|
update.message.reply_text(db.get_info_message(args[0]),
|
||
|
parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
|
||
|
|
||
|
def ping(bot, update):
|
||
|
"""Classic ping command"""
|
||
|
message = "Pong. I'm not running in this group! Start me with `/start`"
|
||
|
if update.message.chat_id in groups.groups:
|
||
|
message = "Pong."
|
||
|
|
||
|
update.message.reply_text(message, parse_mode='MARKDOWN')
|
||
|
|
||
|
|
||
|
def usage(bot, update):
|
||
|
message = "*CTF Reminder* will remind your CTF as they start!\n"
|
||
|
message += "`/start` to start the reminder\n"
|
||
|
message += "`/stop` to stop the reminder\n"
|
||
|
message += "`/upcoming` to list all the upcoming CTFs\n"
|
||
|
message += "`/now` or `/current` to list all the currently running CTFs\n"
|
||
|
message += "`/info <ctf_id>` to get info for specific CTF\n"
|
||
|
message += "`/ping` to check if the reminder is started\n"
|
||
|
message += "\nGet the bot [Source Code]"
|
||
|
message += "(https://github.com/TheZ3ro/ctf_reminder)"
|
||
|
update.message.reply_text(message, parse_mode='MARKDOWN',
|
||
|
disable_web_page_preview=True)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
db.add_events(CTFTimeClient.fetch_data())
|
||
|
|
||
|
updater, bot = Updater(TOKEN), Bot(TOKEN)
|
||
|
|
||
|
# Get the dispatcher to register handlers
|
||
|
dp = updater.dispatcher
|
||
|
|
||
|
# on different commands - answer in Telegram
|
||
|
dp.add_handler(CommandHandler("start", start))
|
||
|
dp.add_handler(CommandHandler("stop", stop))
|
||
|
dp.add_handler(CommandHandler("upcoming", upcoming))
|
||
|
dp.add_handler(CommandHandler("now", current))
|
||
|
dp.add_handler(CommandHandler("current", current))
|
||
|
dp.add_handler(CommandHandler("info", info, pass_args=True))
|
||
|
dp.add_handler(CommandHandler("ping", ping))
|
||
|
dp.add_handler(CommandHandler("help", usage))
|
||
|
|
||
|
# log all errors
|
||
|
dp.add_error_handler(error)
|
||
|
|
||
|
# Start the Bot
|
||
|
updater.start_polling(clean=True)
|
||
|
|
||
|
job_queue = updater.job_queue
|
||
|
job_queue.run_repeating(fetch, 6 * 60 * 60)
|
||
|
job_queue.run_repeating(starting, 1 * 60 * 60)
|
||
|
|
||
|
# Block until you press Ctrl-C or the process receives SIGINT, SIGTERM or
|
||
|
# SIGABRT. This should be used most of the time, since start_polling() is
|
||
|
# non-blocking and will stop the bot gracefully.
|
||
|
updater.idle()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|