#!/usr/bin/env python # -*- coding: utf-8 -*- # # openmamba bot for Telegram # # Copyright (C) 2016-2017 by Silvan Calarco # # GPL v3 license from telegram import (ParseMode) from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler, ConversationHandler, Job) import logging import subprocess import sqlite3 import os # Enable logging logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) timers = dict() social_log_last_ids = dict() def start(bot, update): user = update.message.from_user logger.info("User %s started the conversation." % user.first_name) update.message.reply_text( 'Hi! This is the openmamba GNU/Linux Bot.\n' 'Send any text to search for packages.\n' 'Send /details name to see details of specified source package.\n' 'Send /set [seconds] to enable notifications.\n' 'Send /unset to disable notifications.\n' 'Send /cancel to stop talking to me.\n\n') return def query(bot, update): user = update.message.from_user logger.info("Query of %s: %s" % (user.first_name, update.message.text)) response = "" for rep in [ 'devel', 'devel-games', 'devel-makedist', 'devel-autodist', 'devel-kernel', 'devel-misc', 'devel-kde4' ]: conn = sqlite3.connect('/var/webbuild/db/%s-sources.db' % rep, check_same_thread=False) cursor = conn.cursor() cursor.execute( 'SELECT id,name,version,release,summary,url FROM sources where name like "%%%s%%" or summary like "%%%s%%" ' 'ORDER BY name="%s" DESC, name like "%s%%" DESC, name like "%%%s%%" DESC limit 10' % (update.message.text, update.message.text, update.message.text, update.message.text, update.message.text)) for row in cursor: response += "%s %s-%s (%s)\n%s\n%s\n\n" % (row[1], row[2], row[3], rep, row[4], row[5]) if response != "": update.message.reply_text(response, parse_mode=ParseMode.HTML) else: update.message.reply_text('No results found.') return def details(bot, update, args): user = update.message.from_user logger.info("Details of %s: %s" % (user.first_name, update.message.text)) response = "" for rep in [ 'devel', 'devel-games', 'devel-makedist', 'devel-autodist', 'devel-kernel', 'devel-misc', 'devel-kde4' ]: conn = sqlite3.connect('/var/webbuild/db/%s-sources.db' % rep, check_same_thread=False) cursor = conn.cursor() cursor.execute( 'SELECT id,name,version,release,summary,url,description FROM sources where name="%s"' % (args[0])) for row in cursor: response += "%s %s-%s (devel)\n%s\n%s\n\n%s\n\n" % (row[1], row[2], row[3], row[4], row[5], row[6]) for arch in [ 'x86_64', 'i586', 'arm' ]: conn1 = sqlite3.connect('/var/webbuild/db/' + rep + '-' + arch + '.db', check_same_thread=False) cursor1 = conn1.cursor() cursor1.execute('SELECT id,name FROM packages where id_source=%s' % (row[0])) for row1 in cursor1: response += "%s(%s) " % (row1[1], arch) response += "\n\n\n" if response != "": update.message.reply_text(response, parse_mode=ParseMode.HTML) else: update.message.reply_text('No results found.') return def alarm(bot, job): social_log_conn = sqlite3.connect('/var/webbuild/webbuild.db') social_log_cursor = social_log_conn.cursor() social_log_cursor.execute('SELECT id,user,text,datetime(time,\'localtime\'),type FROM social_log where id>%s' % social_log_last_ids[job.context]) response = "" for row in social_log_cursor: if row[4] == "job": response += "Job run by %s %s (%s)\n" % (row[1], row[2], row[3]) else: response += "%s %s (%s)\n" % (row[1], row[2], row[3]) if response != "": bot.sendMessage(job.context, response, parse_mode=ParseMode.HTML) social_log_last_ids[job.context] = row[0] def set(bot, update, args, job_queue): chat_id = update.message.chat_id try: due = int(args[0]) if due < 0: update.message.reply_text('Sorry we can not go back to future!') return job = Job(alarm, due, repeat=True, context=chat_id) timers[chat_id] = job job_queue.put(job) social_log_conn = sqlite3.connect('/var/webbuild/webbuild.db') social_log_cursor = social_log_conn.cursor() social_log_cursor.execute('''SELECT MAX(id) FROM social_log''') social_log_last_ids[chat_id] = social_log_cursor.fetchone()[0] - 5 update.message.reply_text('Notifications enabled!') except (IndexError, ValueError): update.message.reply_text('Usage: /set ') def unset(bot, update): chat_id = update.message.chat_id if chat_id not in timers: update.message.reply_text('Notification were not enabled') return job = timers[chat_id] job.schedule_removal() del timers[chat_id] update.message.reply_text('Notifications disabled') def cancel(bot, update): user = update.message.from_user logger.info("User %s canceled the conversation." % user.first_name) update.message.reply_text('Bye!') return ConversationHandler.END def error(bot, update, error): logger.warn('Update "%s" caused error "%s"' % (update, error)) def main(): # Load bot token from external configuration file bot_token = "" with open("/etc/autodist/secrets") as myfile: for line in myfile: name, var = line.rstrip().split("=") if name == "TELEGRAM_BOT_TOKEN": bot_token = var # Create the EventHandler and pass it your bot's token. updater = Updater(bot_token) # Get the dispatcher to register handlers dp = updater.dispatcher dp.add_handler(CommandHandler('start', start)) dp.add_handler(MessageHandler(Filters.text, query)) dp.add_handler(CommandHandler('details', details, pass_args=True)) dp.add_handler(CommandHandler('set', set, pass_args=True, pass_job_queue=True)) dp.add_handler(CommandHandler('unset', unset)) dp.add_handler(CommandHandler('cancel', cancel)) # log all errors dp.add_error_handler(error) # Start the Bot updater.start_polling() # Run the bot until the you presses 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()