def on_status(self, status): if (status.user.screen_name.lower() in self.relevant_users and not status.text.startswith("RT ")): log.info("On status from tweepy: %s", status.text) tweet = status ScheduleManager.execute_now(self.dispatch_tweet, args=[tweet])
async def _ban( self, user, timeout_in_seconds=0, reason=None, delete_message_days=0 ): delete_message_days = ( 7 if delete_message_days > 7 else (0 if delete_message_days < 0 else delete_message_days) ) if not self.guild: return if not user: return try: ban = await self.guild.fetch_ban(user) if ban: return except: pass if timeout_in_seconds > 0: reason = f"{reason} for {timeout_in_seconds} seconds" timeouts = json.loads(self.redis.get("timeouts-discord")) timeouts[str(user.id)] = { "discord_id": str(user.id), "unban_date": str(utils.now() + timedelta(seconds=timeout_in_seconds)), "reason": str(reason) } self.redis.set("timeouts-discord", json.dumps(timeouts)) ScheduleManager.execute_delayed(delay=timeout_in_seconds, method=self.unban, args=[user.id, "Unbanned by timer"]) await self.guild.ban( user=user, reason=reason, delete_message_days=delete_message_days )
async def initial_unbans(self): try: data = json.loads(self.redis.get(f"{self.bot.bot_name}:timeouts-discord")) for user in data: unban_date = utils.parse_date(data[user]["unban_date"]) time_now = utils.now() resp_timeout = data.get("resp_timeout", "") resp_timeout += " after " if resp_timeout else "" if unban_date < time_now: ScheduleManager.execute_now( method=self.unban, args=[ data[user]["discord_id"], f"Unbanned by timer{resp_timeout}", ], ) continue ScheduleManager.execute_delayed( delay=(unban_date - time_now).seconds, method=self.unban, args=[data[user]["discord_id"], f"Unbanned by timer{resp_timeout}"], ) except Exception as e: log.exception(e) self.redis.set(f"{self.bot.bot_name}:timeouts-discord", json.dumps({})) with DBManager.create_session_scope() as db_session: unnamed_users = db_session.query(User).filter_by(user_name="").all() for user in unnamed_users: member = self.get_member(int(user.discord_id)) if not member: db_session.delete(user) continue user.user_name = str(member)
def __init__(self, config, args): self.config = config self.args = args self.private_loop = asyncio.get_event_loop() self.private_loop.set_exception_handler(custom_exception_handler) self.discord_token = self.config["main"]["discord_token"] ScheduleManager.init(self.private_loop) DBManager.init(self.config["main"]["db"]) ActionParser.bot = self # redis redis_options = {} if "redis" in config: redis_options = dict(config.items("redis")) RedisManager.init(**redis_options) utils.wait_for_redis_data_loaded(RedisManager.get()) # SQL migrations try: with DBManager.create_dbapi_connection_scope() as sql_conn: sql_migratable = DatabaseMigratable(sql_conn) sql_migration = Migration(sql_migratable, greenbot.migration_revisions.db, self) sql_migration.run() except ValueError as error: log.error(error) HandlerManager.init_handlers() self.movienight_api = MovieNightAPI(self, self.config["wsc"], self.config["wowza_cdn"]) HandlerManager.add_handler("parse_command_from_message", self.parse_command_from_message) self.bot_name = self.config["main"]["bot_name"] self.command_prefix = self.config["discord"]["command_prefix"] self.settings = { "discord_token": self.discord_token, "bot_name": self.bot_name, "command_prefix": self.command_prefix, "discord_guild_id": self.config["discord"]["discord_guild_id"], } HandlerManager.add_handler("discord_ready", self.wait_discord_load) self.discord_bot = DiscordBotManager( bot=self, settings=self.settings, redis=RedisManager.get(), private_loop=self.private_loop, ) self.twitter_manager = TwitterManager(self) self.filters = Filters(self, self.discord_bot) self.functions = Functions(self, self.filters)
def enable(self, settings): self.settings = settings self.salt = utils.random_string() with DBManager.create_session_scope() as db_session: current_timeouts = Timeout._active_timeouts(db_session) for timeout in current_timeouts: if timeout.time_left: ScheduleManager.execute_delayed( timeout.time_left + 1, self.auto_untimeout, args=[timeout.id, self.salt], )
def run(self, bot, author, channel, message, args): if self.action is None: log.warning("This command is not available.") return False if args["user_level"] < self.level: # User does not have a high enough power level to run this command return False if args["whisper"] and self.can_execute_with_whisper is False: # This user cannot execute the command through a whisper return False cd_modifier = 0.2 if args["user_level"] >= 500 else 1.0 cur_time = greenbot.utils.now().timestamp() time_since_last_run = (cur_time - self.last_run) / cd_modifier if (time_since_last_run < self.delay_all and args["user_level"] < Command.BYPASS_DELAY_LEVEL): log.debug( f"Command was run {time_since_last_run:.2f} seconds ago, waiting..." ) return False time_since_last_run_user = (cur_time - self.last_run_by_user.get( str(author.id), 0)) / cd_modifier if (time_since_last_run_user < self.delay_user and args["user_level"] < Command.BYPASS_DELAY_LEVEL): log.debug( f"{author.name}#{author.discriminator} ran command {time_since_last_run_user:.2f} seconds ago, waiting..." ) return False with DBManager.create_session_scope() as db_session: user = User._create_or_get_by_discord_id(db_session, str(author.id), str(author)) if self.cost > 0 and not user.can_afford(self.cost): # User does not have enough points to use the command return False args.update(self.extra_args) if self.run_in_thread: log.debug(f"Running {self} in a thread") ScheduleManager.execute_now( self.run_action, args=[bot, author, channel, message, args]) else: self.run_action(bot, author, channel, message, args) return True
def __init__(self, bot): super().__init__(bot) self.twitter_stream = None self.listener = None if "twitter" not in bot.config or not self.twitter_client: return try: ScheduleManager.execute_every(30, self.check_twitter_connection) except: log.exception("Twitter authentication failed.") log.info("Started Twitter")
async def ban(self, user, timeout_in_seconds=0, reason=None, delete_message_days=0): delete_message_days = ( 7 if delete_message_days > 7 else (0 if delete_message_days < 0 else delete_message_days) ) if not self.guild: return False if not user: return False try: ban = await self.guild.fetch_ban(user) if ban: return False except: return False try: resp_timeout = utils.seconds_to_resp(timeout_in_seconds) reason += ( f" for {resp_timeout}!" if timeout_in_seconds > 0 else " Permanently!" ) await self.guild.ban( user=user, reason=reason, delete_message_days=delete_message_days ) if timeout_in_seconds > 0: timeouts = json.loads( self.redis.get(f"{self.bot.bot_name}:timeouts-discord") ) timeouts[str(user.id)] = { "discord_id": str(user.id), "unban_date": str( utils.now() + timedelta(seconds=timeout_in_seconds) ), "resp_timeout": resp_timeout, "reason": str(reason), } self.redis.set( f"{self.bot.bot_name}:timeouts-discord", json.dumps(timeouts) ) ScheduleManager.execute_delayed( delay=timeout_in_seconds, method=self.unban, args=[user.id, f"Unbanned by timer after {resp_timeout}"], ) except: return False return True
def run_functions( functions, bot, extra, author, channel, args, num_urlfetch_subs, private_message ): for func in functions: final_args = get_argument_substitutions_array( get_substitutions_array(func.arguments, bot, extra), extra ) resp, embed = func.cb(final_args, extra) if num_urlfetch_subs == 0: return ( bot.private_message(author, resp, embed) if private_message else bot.say(channel, resp, embed) ) return ScheduleManager.execute_now( urlfetch_msg, args=[], kwargs={ "args": [author if private_message else channel], "kwargs": {}, "method": bot.private_message if private_message else bot.say, "bot": bot, "extra": extra, "message": resp, "embed": embed, "num_urlfetch_subs": num_urlfetch_subs, }, )
def initial_unbans(self): try: data = json.loads(self.redis.get("timeouts-discord")) for user in data: unban_date = data[user]["unban_date"] if ":" in unban_date[-5:]: unban_date = f"{unban_date[:-5]}{unban_date[-5:-3]}{unban_date[-2:]}" unban_date = datetime.strptime(unban_date, "%Y-%m-%d %H:%M:%S.%f%z") time_now = utils.now() if unban_date < time_now: ScheduleManager.execute_now(method=self.unban, args=[data[user]["discord_id"], "Unbanned by timer"]) continue ScheduleManager.execute_delayed(delay=(unban_date - time_now).seconds, method=self.unban, args=[data[user]["discord_id"], "Unbanned by timer"]) except Exception as e: log.exception(e) self.redis.set("timeouts-discord", json.dumps({}))
def __init__(self, bot, wsc_config, wowza_cdn_config): self.bot = bot self.wsc_api_key = wsc_config.get("wsc_api_key", None) self.wsc_access_key = wsc_config.get("wsc_access_key", None) self.wsc_host = wsc_config.get("wsc_host", None) self.wsc_version = wsc_config.get("wsc_version", None) self.wowza_cdn_expiration_time = wowza_cdn_config.get("wowza_cdn_expiration_time", None) self.wowza_cdn_live_stream_id = wowza_cdn_config.get("wowza_cdn_live_stream_id", None) self.wowza_cdn_trusted_shared_secret = wowza_cdn_config.get("wowza_cdn_trusted_shared_secret") self.ull_stream_running = False self.cdn_stream_running = False self.ull_playback_key = "" self.cdn_playback_key = "" if self.wsc_api_key\ and self.wsc_access_key\ and self.wsc_host\ and self.wsc_version\ and self.wowza_cdn_expiration_time\ and self.wowza_cdn_live_stream_id\ and self.wowza_cdn_trusted_shared_secret: self.schedule_job = ScheduleManager.execute_every(interval=30, method=self.stream_check) self.active = True else: self.active = False
def run(self, bot, author, channel, message, args): extra = self.get_extra_data(author, channel, message, args) resp, embed = self.get_response(bot, extra) if self.functions: run_functions( self.functions, bot, extra, author, channel, args, self.num_urlfetch_subs, True, ) if not resp and embed: return False if self.num_urlfetch_subs == 0: return bot.private_message(author, resp, embed) return ScheduleManager.execute_now( urlfetch_msg, args=[], kwargs={ "args": [author], "kwargs": {}, "method": bot.private_message, "bot": bot, "extra": extra, "message": resp, "embed": embed, "num_urlfetch_subs": self.num_urlfetch_subs, }, )
def enable(self, bot): if not bot: return try: reminders_list = json.loads(self.redis.get("remind-me-reminders")) """ { user_id: { "message_id": message_id, "message": message, "date_of_reminder": date_of_reminder, }, } """ except: self.redis.set("remind-me-reminders", json.dumps({})) reminders_list = {} new_reminders_list = {} for user in reminders_list: user_reminders = reminders_list[user] new_user_reminders = [] for reminder in user_reminders: salt = random_string() date_of_reminder = reminder["date_of_reminder"] if ":" in date_of_reminder[-5:]: date_of_reminder = f"{date_of_reminder[:-5]}{date_of_reminder[-5:-3]}{date_of_reminder[-2:]}" date_of_reminder = datetime.strptime(date_of_reminder, "%Y-%m-%d %H:%M:%S.%f%z") if date_of_reminder < utils.now(): continue new_user_reminders.append(reminder) self.reminder_tasks[salt] = ScheduleManager.execute_delayed((date_of_reminder-utils.now()).seconds, self.execute_reminder, args=[salt, reminder])
def enable(self, bot): if not bot: return try: reminders_list = json.loads( self.redis.get(f"{self.bot.bot_name}:remind-me-reminders")) """ { user_id: [ { "message_id": message_id, "channel_id": channel_id, "salt": salt, "message": message, "date_of_reminder": date_of_reminder, "date_reminder_set": date_reminder_set }, ], } """ except: self.redis.set(f"{self.bot.bot_name}:remind-me-reminders", json.dumps({})) reminders_list = {} new_reminders_list = {} for user_id in reminders_list: user_reminders = reminders_list[user_id] new_user_reminders = [] for reminder in user_reminders: salt = reminder["salt"] date_of_reminder = utils.parse_date( reminder["date_of_reminder"]) if date_of_reminder < utils.now(): continue new_user_reminders.append(reminder) self.reminder_tasks[salt] = ScheduleManager.execute_delayed( (date_of_reminder - utils.now()).total_seconds(), self.execute_reminder, args=[salt, user_id, reminder], ) new_reminders_list[user_id] = new_user_reminders self.redis.set(f"{self.bot.bot_name}:remind-me-reminders", json.dumps(new_reminders_list))
async def create_reminder(self, bot, author, channel, message, args): command_args = message.split(" ") if message else [] try: reminders_list = json.loads( self.redis.get(f"{self.bot.bot_name}:remind-me-reminders")) """ { user_id: [ { "message_id": message_id, "channel_id": channel_id, "message": message, "date_of_reminder": date_of_reminder, "date_reminder_set": date_reminder_set }, ], } """ except: self.redis.set(f"{self.bot.bot_name}:remind-me-reminders", json.dumps({})) reminders_list = {} user_reminders = (reminders_list[str(author.id)] if str(author.id) in reminders_list else []) if len(user_reminders) >= int(self.settings["max_reminders_per_user"]): await self.bot.say( channel, f"{author.mention} you already have {len(user_reminders)} reminders!", ) return False if len(command_args) == 0: await self.bot.say(channel, embed=self.help) return False time_delta = utils.parse_timedelta(command_args[0]) if not time_delta: await self.bot.say( channel, f"{author.mention} invalid time: {command_args[0]}") return False await self.bot.say( channel, f"{author.mention} ill remind you that in {utils.seconds_to_resp(time_delta.total_seconds())}", ) bot_message = await self.bot.say( channel, f"If anyone else wants to be reminded click the {self.settings['emoji']}", ) salt = utils.random_string() await bot_message.add_reaction(self.settings["emoji"]) reminder = { "message_id": bot_message.id, "channel_id": bot_message.channel.id, "salt": salt, "message": " ".join(command_args[1:]), "date_of_reminder": str(utils.now() + time_delta), "date_reminder_set": str(utils.now()), } user_reminders.append(reminder) reminders_list[str(author.id)] = user_reminders self.redis.set(f"{self.bot.bot_name}:remind-me-reminders", json.dumps(reminders_list)) self.reminder_tasks[salt] = ScheduleManager.execute_delayed( time_delta.total_seconds(), self.execute_reminder, args=[salt, author.id, reminder], )
def init(args): import subprocess import sys from flask import request from flask import session from flask_scrypt import generate_random_salt import greenbot.utils import greenbot.web.common import greenbot.web.routes from greenbot.managers.db import DBManager from greenbot.managers.redis import RedisManager from greenbot.managers.schedule import ScheduleManager from greenbot.models.module import ModuleManager from greenbot.models.sock import SocketClientManager from greenbot.utils import load_config from greenbot.web.models import errors from greenbot.bothelper import BotHelper ScheduleManager.init() config = load_config(args.config) redis_options = {} if "redis" in config: redis_options = dict(config["redis"]) RedisManager.init(**redis_options) if "web" not in config: log.error("Missing [web] section in config.ini") sys.exit(1) if "secret_key" not in config["web"]: salt = generate_random_salt() config.set("web", "secret_key", salt.decode("utf-8")) with open(args.config, "w") as configfile: config.write(configfile) bot_name = config["main"]["bot_name"] BotHelper.set_bot_name(bot_name) SocketClientManager.init(bot_name) app.bot_modules = config["web"].get("modules", "").split() app.bot_commands_list = [] app.bot_config = config app.secret_key = config["web"]["secret_key"] app.config["DISCORD_CLIENT_ID"] = app.bot_config["discord"]["client_id"] app.config["DISCORD_CLIENT_SECRET"] = app.bot_config["discord"][ "client_secret"] app.config["DISCORD_REDIRECT_URI"] = app.bot_config["discord"][ "redirect_uri"] app.bot_dev = ("flags" in config and "dev" in config["flags"] and config["flags"]["dev"] == "1") DBManager.init(config["main"]["db"]) app.module_manager = ModuleManager(None).load() greenbot.web.routes.admin.init(app) greenbot.web.routes.api.init(app) greenbot.web.routes.base.init(app) greenbot.web.common.filters.init(app) greenbot.web.common.assets.init(app) greenbot.web.common.menu.init(app) errors.init(app, config) last_commit = None if app.bot_dev: try: last_commit = (subprocess.check_output( ["git", "log", "-1", "--format=%cd"]).decode("utf8").strip()) except: log.exception( "Failed to get last_commit, will not show last commit") default_variables = { "last_commit": last_commit, "version": "v1.0", "bot": { "name": config["main"]["bot_name"] }, "site": { "domain": config["web"]["domain"] }, "modules": app.bot_modules, "request": request, "session": session, "google_analytics": config["web"].get("google_analytics", None), } @app.context_processor def current_time(): current_time = {} current_time["current_time"] = greenbot.utils.now() return current_time @app.context_processor def inject_default_variables(): return default_variables
def execute_every(self, period, function, *args, **kwargs): ScheduleManager.execute_every(period, lambda: function(*args, **kwargs))
def execute_delayed(self, delay, function, *args, **kwargs): ScheduleManager.execute_delayed(delay, lambda: function(*args, **kwargs))
async def timeout_user(self, db_session, member, banner, until, ban_reason): if not self.settings["enabled"]: return False, "Module is not enabled" current_timeout = Timeout._is_timedout(db_session, str(member.id)) new_timeout = None if current_timeout is not None: if current_timeout.check_lengths(until): current_timeout.active = False new_timeout = Timeout._create(db_session, str(member.id), str(banner.id), until, ban_reason) db_session.commit() current_timeout.unban( db_session, None, f"Timeout overwritten by Timeout #{new_timeout.id}", ) db_session.commit() else: return ( False, f"{member} is currently timedout by Timeout #{current_timeout.id}", ) if not new_timeout: new_timeout = Timeout._create(db_session, str(member.id), str(banner.id), until, ban_reason) db_session.commit() await self.apply_timeout(member, new_timeout) if self.settings["log_timeout"]: embed = discord.Embed( title="Member has been timedout", timestamp=new_timeout.created_at, colour=member.colour, ) embed.set_author( name=f"{member} ({member.id})- Timeout Removed", icon_url=str(member.avatar_url), ) embed.add_field( name="Banned on", value=str( new_timeout.created_at.strftime("%b %d %Y %H:%M:%S %Z")), inline=False, ) if new_timeout.issued_by_id: issued_by = self.bot.filters.get_member( [int(new_timeout.issued_by_id)], None, {})[0] embed.add_field( name="Banned by", value=issued_by.mention if issued_by else f"{new_timeout.issued_by_id}", inline=False, ) if new_timeout.ban_reason: embed.add_field(name="Ban Reason", value=str(new_timeout.ban_reason), inline=False) await HandlerManager.trigger("aml_custom_log", embed=embed) if new_timeout.time_left: ScheduleManager.execute_delayed( new_timeout.time_left + 5, self.auto_untimeout, args=[new_timeout.id, self.salt], ) return True, None
def load_commands(self, **options): if not self.bot: return ScheduleManager.execute_now(self.update_manager)
def enable(self, bot): if not bot: return self.process_messages_job = ScheduleManager.execute_every( 3600, self.process_messages) # Checks every hour