From 1d76dae187410706c9a09230ade03f145fcf0333 Mon Sep 17 00:00:00 2001 From: CMDR furrycat Date: Fri, 11 Nov 2016 16:44:38 +0000 Subject: [PATCH] Announcement() class. --- plugin/announcements/announcements.py | 259 +++++++++++++++++----------------- 1 file changed, 133 insertions(+), 126 deletions(-) diff --git a/plugin/announcements/announcements.py b/plugin/announcements/announcements.py index 77b8aae..beccaad 100644 --- a/plugin/announcements/announcements.py +++ b/plugin/announcements/announcements.py @@ -12,6 +12,11 @@ from plugins import PluginCommand import bot import cat +class Announcement(object): + def __init__(self, row): + for k, v in dict(row).items(): + setattr(self, k, v) + class Announcements(DBConnection): def __init__(self, filename = None): super(Announcements, self).__init__(filename) @@ -40,32 +45,32 @@ class Announcements(DBConnection): # Delete old announcements. now = int(time.time()) for announcement in self.get_all_announcements(client): - if announcement['asap'] == 'true': + if announcement.asap == 'true': # Don't delete announcements that were requested ASAP. continue - if not announcement['last_spoke']: + if not announcement.last_spoke: # Don't delete announcements that haven't played yet. continue - interval = announcement['interval'] + interval = announcement.interval if not interval: interval = 0 - if now - announcement['last_spoke'] < max(interval, 86400): + if now - announcement.last_spoke < max(interval, 86400): # Don't delete announcements that aren't old. continue - if announcement['interval']: - if not announcement['end_date']: + if announcement.interval: + if not announcement.end_date: # Don't delete ongoing announcements. continue - if announcement['end_date'] > now: + if announcement.end_date > now: # Don't delete announcements that still have time to run. continue if bot.get('dryrun'): - log.info("Would delete old announcement {}".format(announcement['id'])) + log.info("Would delete old announcement {}".format(announcement.id)) else: - if self.delete_announcement(client, announcement['id']): - log.info('Deleted old announcement {}'.format(announcement['id'])) + if self.delete_announcement(client, announcement.id): + log.info('Deleted old announcement {}'.format(announcement.id)) else: - log.info('Failed to delete old announcement {}'.format(announcement['id'])) + log.info('Failed to delete old announcement {}'.format(announcement.id)) yield from asyncio.sleep(waittime) @@ -84,16 +89,18 @@ class Announcements(DBConnection): yield from self.help_announcements(message, *args) def get_all_announcements(self, client, servers = []): - yield from self.get_all_from_table(client, 'announcements', servers) + for row in self.get_all_from_table(client, 'announcements', servers): + yield Announcement(row) def get_announcement(self, client, id): - return self.get_from_table(client, 'announcements', id) + row = self.get_from_table(client, 'announcements', id) + return Announcement(row) if row else None def get_announcements(self, client): now = self.now() cursor = self.query("select id, server_id, member_id, channel_id, voice_id, sound, attachment, mention, start_date, end_date, interval, probability, last_spoke, asap, message, digest from announcements where (start_date is null or start_date <= ?) and (end_date is null or end_date > ? or end_date=start_date) and (asap='true' or last_spoke is null or last_spoke < ? - interval) and (last_spoke is null or interval > 0) and bot_id=?", [now, now, now, client.user.id]) for row in cursor.fetchall(): - yield dict(row) + yield Announcement(row) self.close_db() def create_announcement(self, client, **args): @@ -122,25 +129,25 @@ class Announcements(DBConnection): # Anyone on the server can show details of an announcement. if command == 'show': if announcement is not None: - if announcement['member_id'] == author.id: + if announcement.member_id == author.id: log.debug('Anyone can show own announcements.') return announcement - if announcement['channel_id'] != 'private': - server = client.get_server(announcement['server_id']) + if announcement.channel_id != 'private': + server = client.get_server(announcement.server_id) if server is not None: member = server.get_member(author.id) if member in server.members: - log.debug('Member {} on server {} can show announcement {}.'.format(member.name, server.name, announcement['id'])) + log.debug('Member {} on server {} can show announcement {}.'.format(member.name, server.name, announcement.id)) return announcement if command in ['edit', 'delete', 'schedule']: if announcement is not None: - if announcement['member_id'] == author.id: + if announcement.member_id == author.id: log.debug('Anyone can manage own announcements.') return announcement - if announcement['channel_id'] != 'private': - server = client.get_server(announcement['server_id']) - announcer = server.get_member(announcement['member_id']) + if announcement.channel_id != 'private': + server = client.get_server(announcement.server_id) + announcer = server.get_member(announcement.member_id) announcer_role = bot.highest_role(announcer.roles) member = server.get_member(author.id) member_role = bot.highest_role(member.roles) @@ -153,11 +160,11 @@ class Announcements(DBConnection): return announcement if command == 'create': - if announcement['channel_id'] == 'private': + if announcement.channel_id == 'private': log.debug('Anyone can schedule a private announcement.') return announcement - server = client.get_server(announcement['server_id']) - member = server.get_member(announcement['member_id']) + server = client.get_server(announcement.server_id) + member = server.get_member(announcement.member_id) bot_member = server.get_member(client.user.id) member_role = bot.highest_role(member.roles) bot_role = bot.highest_role(bot_member.roles) @@ -283,28 +290,28 @@ class Announcements(DBConnection): results = [] for announcement in self.get_all_announcements(client, self.get_message_servers(client, message, True)): - if announcement['channel_id'] == 'private' and announcement['member_id'] != message.author.id: + if announcement.channel_id == 'private' and announcement.member_id != message.author.id: continue - text = 'announcement **{}**'.format(announcement['id']) - if announcement['channel_id'] == 'private': + text = 'announcement **{}**'.format(announcement.id) + if announcement.channel_id == 'private': text += ' in private' else: - server = client.get_server(announcement['server_id']) - member = server.get_member(announcement['member_id']) + server = client.get_server(announcement.server_id) + member = server.get_member(announcement.member_id) text += ' by {}'.format(member.name) - if announcement['channel_id']: - if announcement['channel_id'] != 'private': - text += ' in <#{}>'.format(announcement['channel_id']) - if announcement['voice_id']: - if announcement['sound']: - text += ' sound {}'.format(announcement['sound']) - if announcement['voice_id'] != announcement['channel_id']: - text += ' in <#{}>'.format(announcement['voice_id']) - if announcement['attachment']: - text += ' attachment {}'.format(announcement['attachment']) - if announcement['message']: - short = announcement['message'][:100] - if short != announcement['message']: + if announcement.channel_id: + if announcement.channel_id != 'private': + text += ' in <#{}>'.format(announcement.channel_id) + if announcement.voice_id: + if announcement.sound: + text += ' sound {}'.format(announcement.sound) + if announcement.voice_id != announcement.channel_id: + text += ' in <#{}>'.format(announcement.voice_id) + if announcement.attachment: + text += ' attachment {}'.format(announcement.attachment) + if announcement.message: + short = announcement.message[:100] + if short != announcement.message: short += '...' text += ': {}'.format(short.replace('\n', ' ')) results.append(text) @@ -321,48 +328,48 @@ class Announcements(DBConnection): return lines = [] - if announcement['channel_id'] == 'private': + if announcement.channel_id == 'private': for server in client.servers: try: - member = server.get_member(announcement['member_id']) + member = server.get_member(announcement.member_id) except: log.exception("announce") else: - server = client.get_server(announcement['server_id']) - member = server.get_member(announcement['member_id']) - text = '**{}announcement {} by {}'.format('private ' if announcement['channel_id'] == 'private' else '', id, member.name if member is not None else announcement['member_id']) + server = client.get_server(announcement.server_id) + member = server.get_member(announcement.member_id) + text = '**{}announcement {} by {}'.format('private ' if announcement.channel_id == 'private' else '', id, member.name if member is not None else announcement.member_id) now = int(time.time()) - if announcement['last_spoke']: - offset = announcement['last_spoke'] - text += ' last given at {}'.format(bot.iso8601(announcement['last_spoke'])) + if announcement.last_spoke: + offset = announcement.last_spoke + text += ' last given at {}'.format(bot.iso8601(announcement.last_spoke)) else: offset = now - if announcement['start_date']: - if announcement['start_date'] > now: - offset = announcement['start_date'] - text += ' scheduled for {}'.format(bot.iso8601(announcement['start_date'])) - if announcement['end_date']: - if announcement['end_date'] < now: + if announcement.start_date: + if announcement.start_date > now: + offset = announcement.start_date + text += ' scheduled for {}'.format(bot.iso8601(announcement.start_date)) + if announcement.end_date: + if announcement.end_date < now: offset = None text += ' has expired' if offset is not None and offset <= now: - if announcement['interval']: - text += ' scheduled for {}'.format(bot.iso8601(offset + announcement['interval'])) - if announcement['asap'] == 'true': + if announcement.interval: + text += ' scheduled for {}'.format(bot.iso8601(offset + announcement.interval)) + if announcement.asap == 'true': text += ' will be given ASAP' - if announcement['probability'] < 0: + if announcement.probability < 0: text += ' paused' text += '**' lines.append(text) text = 'announce create' - if announcement['start_date']: - text += ' from "{}"'.format(bot.iso8601(announcement['start_date'])) - if announcement['end_date']: - text += ' to "{}"'.format(bot.iso8601(announcement['end_date'])) - if announcement['interval']: - text += ' every {}'.format(bot.unparse_seconds(int(announcement['interval']))) - mention = announcement['mention'] + if announcement.start_date: + text += ' from "{}"'.format(bot.iso8601(announcement.start_date)) + if announcement.end_date: + text += ' to "{}"'.format(bot.iso8601(announcement.end_date)) + if announcement.interval: + text += ' every {}'.format(bot.unparse_seconds(int(announcement.interval))) + mention = announcement.mention if mention: if mention == 'everyone' or mention == 'here': text += ' tell @{}'.format(mention) @@ -372,25 +379,25 @@ class Announcements(DBConnection): text += ' tell @{}'.format(mention) else: text += ' tell <@{}>'.format(mention) - if announcement['channel_id'] != announcement['voice_id']: - if announcement['channel_id'] == 'private': + if announcement.channel_id != announcement.voice_id: + if announcement.channel_id == 'private': text += ' in private' else: - text += ' in <#{}>'.format(announcement['channel_id']) - if announcement['voice_id']: - text += ' voice <#{}>'.format(announcement['voice_id']) - if announcement['sound']: - text += ' sound {}'.format(announcement['sound']) - if announcement['attachment']: - text += ' attachment {}'.format(announcement['attachment']) - if abs(announcement['probability']) < 1.0: - text += ' probability {}'.format(abs(announcement['probability'])) - - if announcement['message']: + text += ' in <#{}>'.format(announcement.channel_id) + if announcement.voice_id: + text += ' voice <#{}>'.format(announcement.voice_id) + if announcement.sound: + text += ' sound {}'.format(announcement.sound) + if announcement.attachment: + text += ' attachment {}'.format(announcement.attachment) + if abs(announcement.probability) < 1.0: + text += ' probability {}'.format(abs(announcement.probability)) + + if announcement.message: text += ':' lines.append(text) - if announcement['message']: - lines.append(announcement['message']) + if announcement.message: + lines.append(announcement.message) yield from bot.say_many(message.channel, lines) @@ -624,7 +631,7 @@ class Announcements(DBConnection): if create is None: return - announce = yield from self.can_manage_announcements(message.author, message.channel, 'create', create = create) + announce = yield from self.can_manage_announcements(message.author, message.channel, 'create', create = Announcement(create)) if not announce: return @@ -687,9 +694,9 @@ class Announcements(DBConnection): # Pause announcement. if 'pause' in args: if args['pause']: - update['probability'] = -abs(announcement['probability']) + update['probability'] = -abs(announcement.probability) else: - update['probability'] = abs(announcement['probability']) + update['probability'] = abs(announcement.probability) # ASAP. if 'asap' in args: @@ -746,47 +753,47 @@ class Announcements(DBConnection): @asyncio.coroutine def announce(self, announcement): update = {} - interval = announcement['interval'] + interval = announcement.interval if interval is None: interval = 0 # Adhere to schedule. - if bot.parse_boolean(announcement['asap']): - log.info('Announcement {} was requested ASAP'.format(announcement['id'])) - announcement['probability'] = 1.0 + if bot.parse_boolean(announcement.asap): + log.info('Announcement {} was requested ASAP'.format(announcement.id)) + announcement.probability = 1.0 update['asap'] = 'false' elif interval: - if announcement['start_date'] or announcement['last_spoke']: + if announcement.start_date or announcement.last_spoke: now = int(time.time()) - if announcement['start_date']: - start = announcement['start_date'] + if announcement.start_date: + start = announcement.start_date else: - start = announcement['last_spoke'] + start = announcement.last_spoke intervals = math.floor((now - start) / interval) if intervals: # We missed a schedule. scheduled = start + intervals * interval if now - scheduled > max(60, interval / 2): - log.info('Announcement {} should have been given at {}'.format(announcement['id'], bot.iso8601(scheduled))) - if 'digest' in announcement: - update['digest'] = announcement['digest'] + log.info('Announcement {} should have been given at {}'.format(announcement.id, bot.iso8601(scheduled))) + if announcement.digest: + update['digest'] = announcement.digest update['last_spoke'] = scheduled - self.update_announcement(client, announcement['id'], **update) + self.update_announcement(client, announcement.id, **update) return # Give the announcement now but set the original schedule. last_spoke = start + (intervals + 1) * interval if last_spoke < now: update['last_spoke'] = last_spoke - log.info('Forcing last_spoke for announcement {} to {} in line with schedule'.format(announcement['id'], bot.iso8601(update['last_spoke']))) + log.info('Forcing last_spoke for announcement {} to {} in line with schedule'.format(announcement.id, bot.iso8601(update['last_spoke']))) if 'asap' not in update and 'last_spoke' not in update: update['last_spoke'] = int(time.time()) channel = None - channel_id = str(announcement['channel_id']) + channel_id = str(announcement.channel_id) private = channel_id == 'private' if private: for server in client.servers: try: - member = server.get_member(announcement['member_id']) + member = server.get_member(announcement.member_id) channel = yield from client.start_private_message(member) break except: @@ -794,34 +801,34 @@ class Announcements(DBConnection): else: channel = client.get_channel(channel_id) if channel is None: - log.warning("Can't get channel for announcement {}".format(announcement['id'])) + log.warning("Can't get channel for announcement {}".format(announcement.id)) # Set last_spoke so we don't spam. - self.update_announcement(client, announcement['id'], **update) + self.update_announcement(client, announcement.id, **update) return attachment = None - if announcement['attachment']: - attachment = bot.parse_attachment(announcement['attachment']) + if announcement.attachment: + attachment = bot.parse_attachment(announcement.attachment) - voice_only = attachment is None and announcement['voice_id'] == announcement['channel_id'] - log.debug('Announcement {} {}.'.format(announcement['id'], 'is voice only' if voice_only else 'has text')) + voice_only = attachment is None and announcement.voice_id == announcement.channel_id + log.debug('Announcement {} {}.'.format(announcement.id, 'is voice only' if voice_only else 'has text')) already_posted = False if voice_only: text = None else: # @everyone mention mangles the digest - text = announcement['message'] - mention = announcement['mention'] + text = announcement.message + mention = announcement.mention if mention: if mention in ['everyone', 'here']: text = '@{}\n{}'.format(mention, text) else: text = '<@{}>\n{}'.format(mention, text) - digest = announcement['digest'] + digest = announcement.digest # Always post private messages. Try not to spam public announcements. - if not private and not bot.parse_boolean(announcement['asap']): + if not private and not bot.parse_boolean(announcement.asap): cutoff = datetime.datetime.utcnow() - datetime.timedelta(0, interval) log.debug('Getting logs from {}.'.format(cutoff)) result = yield from client.logs_from(channel, after = cutoff) @@ -834,15 +841,15 @@ class Announcements(DBConnection): for message in logs: raw = re.sub(r'^(