def delete(bot, msg): """Delete a macro.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: c.execute('DELETE FROM macros WHERE slug = %s', (slug, )) msg.respond('macro `{}` has been deleted.'.format(slug))
def addme(bot, msg): """Add yourself to a notification group as a member.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return # If you're already a _direct_ owner or member of this group, do nothing. if group['owners'] and msg.nick in group['owners'].split(' '): msg.respond(f'You\'re already an owner of {slug}!') return members = [] if group['members']: members = group['members'].split(' ') if msg.nick in members: msg.respond(f'You\'re already a member of {slug}!') return members.append(msg.nick) c.execute( 'UPDATE notify SET members = %s WHERE slug = %s', (' '.join(members), slug), ) msg.respond(f'Added you to {slug}, as a member.')
def rand(bot, msg): """Show a random quote, optionally filtered by a search term.""" if msg.match.groups(): arg = msg.match.group(1).split() else: arg = [] with db.cursor(password=bot.mysql_password) as c: c.execute( 'SELECT * FROM quotes WHERE is_deleted = 0 ' + ' '.join( 'AND quote LIKE %s COLLATE utf8mb4_unicode_ci' for _ in arg ) + ' ORDER BY RAND() LIMIT 1', tuple( f'%{a}%' for a in arg ), ) quote = c.fetchone() if quote is not None: _print_quote(msg.respond, quote) else: msg.respond('There are... no quotes?')
def add(bot, msg): """Add a new quote.""" with db.cursor(password=bot.mysql_password) as c: c.execute('INSERT INTO quotes (quote) VALUES (%s)', (msg.match.group(1), )) msg.respond('Your quote was added as #{}'.format(c.lastrowid))
def add(bot, msg): """Add a new macro.""" slug = msg.match.group(1) link = msg.match.group(2) if slug in KEYWORDS: msg.respond(f'`{slug}` is a reserved keyword.') return if len(slug) > 50 or len(link) > 100: msg.respond('macro slugs must be <= 50 and links <= 100 characters') return if len(link) > 80: msg.respond('please try to keep macro links below 80 characters') with db.cursor(password=bot.mysql_password) as c: c.execute('SELECT * FROM macros WHERE slug = %s', (slug, )) result = c.fetchone() if result is not None: msg.respond( 'macro `{}` already exists as {}'.format( result['slug'], result['link'], ), ) else: c.execute( 'INSERT INTO macros (slug, link) VALUES (%s, %s)', (slug, link), ) msg.respond(f'macro added as `{slug}`')
def removeme(bot, msg): """Remove yourself from a notification group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return # If you're already a _direct_ owner or member of this group, do nothing. if group['owners'] and msg.nick in group['owners'].split(' '): msg.respond( f'You\'re an owner of {slug}. ' + 'If you\'re sure you want to remove yourself, please use !notify remove.', ) return if group['members'] is None: msg.respond(f'You\'re not a member of {slug}!') return members = group['members'].split(' ') if msg.nick not in members: msg.respond(f'You\'re not a member of {slug}!') return members = [m for m in members if m != msg.nick] c.execute( 'UPDATE notify SET members = %s WHERE slug = %s', (' '.join(members), slug), ) msg.respond(f'Removed you to from the member list for {slug}.')
def build_model(db_passwd, model_weights=[1, 1, 1]): """Rebuild the markov model using quotes, inspire, and rants databases as seeds.""" with db.cursor(password=db_passwd) as c: # Fetch quote data c.execute('SELECT quote FROM quotes WHERE is_deleted = 0') quotes = c.fetchall() # Fetch inspire data c.execute('SELECT text FROM inspire') inspirations = c.fetchall() # Fetch iconic FOSS rants c.execute('SELECT text FROM markov_rants') rants = c.fetchall() # Normalize the quote data... Get rid of IRC junk clean_quotes = [normalize_quote(d['quote']) for d in quotes] # Normalize the inspire data... Just lightly prune authors clean_inspirations = [ normalize_inspiration(d['text']) for d in inspirations ] # Normalize the rant data... just remove ending punctuation clean_rants = [normalize_rant(d['text']) for d in rants] # Create the three models, and combine them. # More heavily weight our quotes and rants rants_model = markovify.NewlineText('\n'.join(clean_rants)) quotes_model = markovify.NewlineText('\n'.join(clean_quotes)) inspire_model = markovify.NewlineText('\n'.join(clean_inspirations)) return markovify.combine([quotes_model, rants_model, inspire_model], model_weights)
def notify(bot, msg): """Notify all targets (owners and members) in the tagged notificaton group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: targets = get_all_targets(c, slug) if targets is not None: targets_str = ' '.join(targets) msg.respond(f'{slug}: {targets_str}', ping=False)
def join_channel(bot, channel): if IRC_CHANNELS_JOIN_MYSQL: with db.cursor(password=bot.mysql_password) as c: c.execute( 'INSERT IGNORE INTO channels (channel) VALUES (%s)', (channel,), ) bot.connection.join(channel)
def register(bot): bot.listen(r'^join (#[a-zA-Z0-9\-_#]+)$', join, require_mention=True) bot.listen(r'^leave$', leave, require_mention=True) if IRC_CHANNELS_JOIN_MYSQL: with db.cursor(password=bot.mysql_password) as c: c.execute('SELECT channel FROM channels') bot.extra_channels |= {row['channel'] for row in c}
def list(bot): """List all macros for macros help page.""" with db.cursor(password=bot.mysql_password) as c: c.execute('SELECT slug, link FROM macros ORDER BY slug') for entry in c.fetchall(): yield entry['slug'], entry['link']
def leave(bot, msg): """Leave the current channel.""" if msg.channel in IRC_CHANNELS_OPER | IRC_CHANNELS_ANNOUNCE: msg.respond("can't leave {}!".format(msg.channel)) else: with db.cursor(password=bot.mysql_password) as c: c.execute('DELETE FROM channels WHERE channel = %s', (msg.channel, )) bot.connection.part(msg.channel)
def know_that(bot, msg): """Create or update a definition.""" thing, what_it_is = msg.match.groups() with db.cursor(password=bot.mysql_password) as c: c.execute( 'REPLACE INTO what_is (thing, what_it_is) VALUES (%s, %s)', (thing, what_it_is), ) msg.respond('okay, {} is {}'.format(thing, what_it_is), ping=False)
def replace(bot, msg): """Replace the target of a macro slug.""" slug = msg.match.group(1) new_link = msg.match.group(2) with db.cursor(password=bot.mysql_password) as c: c.execute( 'UPDATE macros SET link = %s WHERE slug = %s', (new_link, slug), ) msg.respond(f'macro `{slug}` updated')
def delete(bot, msg): """Delete a quote.""" arg = msg.match.group(1) try: quote_id = int(arg) except ValueError: msg.respond('Not a valid ID: {}'.format(arg)) else: with db.cursor(password=bot.mysql_password) as c: c.execute('UPDATE quotes SET is_deleted = 1 WHERE id = %s', (quote_id, )) msg.respond('Quote #{} has been deleted.'.format(quote_id))
def create(bot, msg): """Create a new notification group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: existing = get_group(c, slug) if existing is not None: msg.respond(f'{slug} already exists.') return c.execute( 'INSERT INTO notify (slug, owners) VALUES (%s, %s)', (slug, msg.nick), ) msg.respond(f'Empty group "{slug}" added. You are the only owner.')
def show(bot, msg): """Show owners and members of the notification group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond(f'{slug} not found.') return for attr in ('owners', 'members'): if group[attr] is None: msg.respond(f'{slug} has no {attr}', ping=False) else: targets = expand_list(c, group[attr]) msg.respond(f'{slug} {attr}: {targets}', ping=False)
def inspire(bot, msg): """Print a quote, optionally filtering.""" term = msg.match.group(1) or '' with db.cursor(password=bot.mysql_password) as c: c.execute( 'SELECT text FROM `inspire` ' + 'WHERE LOWER(text) LIKE LOWER(%s) ' + 'ORDER BY RAND() LIMIT 1', '%{}%'.format(term), ) quote = c.fetchone() msg.respond(quote['text'] if quote else "Nothing inspirational matching '{}' found.".format(term))
def showdumb(bot, msg): """Show the notification group, but don't expand subgroups.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond(f'{slug} not found.') return for attr in ('owners', 'members'): if group[attr] is None: msg.respond(f'{slug} has no {attr}', ping=False) else: targets = [deping(target) for target in group[attr].split(' ')] joined_targets = ' '.join(targets) msg.respond(f'{slug} {attr}: {joined_targets}', ping=False)
def rename(bot, msg): """Rename a macro.""" old_slug = msg.match.group(1) new_slug = msg.match.group(2) if new_slug in KEYWORDS: msg.respond(f'`{new_slug}` is a reserved keyword.') return with db.cursor(password=bot.mysql_password) as c: c.execute( 'UPDATE macros SET slug = %s WHERE slug = %s', (new_slug, old_slug), ) msg.respond(f'macro `{old_slug}` has been renamed to `{new_slug}`')
def show(bot, msg): """Return a macro by slug.""" slug = msg.match.group(1) # special case these so show doesn't trigger on add/delete # while still letting the trigger appear anywhere in the msg if slug in ('add', 'delete'): return with db.cursor(password=bot.mysql_password) as c: c.execute('SELECT link FROM macros WHERE slug = %s', (slug, )) macro = c.fetchone() if macro is not None: msg.respond(macro['link'], ping=False) else: msg.respond('macro `{}` does not exist.'.format(slug))
def addmembers(bot, msg): """Add member(s) to a notification group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return if not msg.is_oper and not is_owner(c, msg.respond, group, msg.nick): msg.respond(f'You can\'t add to {slug}, since you\'re neither an oper, nor an owner of the group.') return members = [] if group['members'] is not None: members = group['members'].split(' ') owners = [] if group['owners'] is not None: owners = group['owners'].split(' ') present = [] added = [] for nick in filter(lambda s: s != '', msg.match.group(2).split(' ')): if nick in members or nick in owners: present.append(nick) else: members.append(nick) added.append(nick) if len(present) > 0: present_str = ', '.join(present) was_plural = 'were' if len(present) > 1 else 'was' msg.respond(f'{present_str} {was_plural} already in {slug}.') if len(added) == 0: return c.execute( 'UPDATE notify SET members = %s WHERE slug = %s', (' '.join(members), slug), ) added_str = ', '.join(added) if len(added) > 1: msg.respond(f'{added_str} were added to {slug} as members.') else: msg.respond(f'{added_str} was added to {slug} as a member.')
def delete(bot, msg): """Delete a notifcation group.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return if not msg.is_oper and not is_owner(c, msg.respond, group, msg.nick): msg.respond(f'You can\'t delete {slug}, since you\'re neither an oper, nor an owner of the group.') return c.execute( 'DELETE FROM notify WHERE slug = %s', (slug,), ) msg.respond(f'{slug} has been deleted.')
def what_is(bot, msg): """Print out the current definition.""" what_who, thing = msg.match.groups() # Special case: "who is in the lab" should be ignored if thing.startswith('in the lab'): return with db.cursor(password=bot.mysql_password) as c: c.execute( 'SELECT * FROM what_is WHERE thing = %s', (thing,), ) definition = c.fetchone() if definition is not None: msg.respond('{} is {}'.format(thing, definition['what_it_is']), ping=False) else: msg.respond('idk {} {} is'.format(what_who, thing), ping=False)
def clear(bot, msg): """Reset a notification group, clearing all members.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return if not msg.is_oper and not is_owner(c, msg.respond, group, msg.nick): msg.respond(f'You can\'t clear {slug}, since you\'re neither an oper, nor an owner of the group.') return c.execute( 'UPDATE notify SET owners = %s, members = NULL WHERE slug = %s', (msg.nick, slug), ) msg.respond(f'{slug} has been cleared. You are now the only owner, and there are no members.')
def show(bot, msg): """Show quote(s) by ID.""" arg = msg.match.group(1).split() quote_ids = [] for a in arg: try: quote_ids.append(int(a.lstrip('#'))) except ValueError: msg.respond('Not a valid ID: {}'.format(a)) break else: with db.cursor(password=bot.mysql_password) as c: for quote_id in quote_ids: c.execute( 'SELECT * FROM quotes WHERE id = %s and is_deleted = 0', (quote_id, )) quote = c.fetchone() if quote is not None: _print_quote(msg.respond, quote) else: msg.respond('Quote #{} does not exist.'.format(quote_id))
def list_groups(bot, msg): """List all notification groups.""" with db.cursor(password=bot.mysql_password) as c: c.execute('SELECT slug FROM notify') slugs = sorted([group['slug'] for group in c.fetchall()]) msg.respond(' '.join(slugs))
def remove(bot, msg): """Remove targets from a notification group, for both owners and members.""" slug = msg.match.group(1) with db.cursor(password=bot.mysql_password) as c: group = get_group(c, slug) if group is None: msg.respond('No such notification group.') return if not msg.is_oper and not is_owner(c, msg.respond, group, msg.nick): msg.respond(f'You can\'t remove from {slug}, since you\'re neither an oper, nor an owner of the group.') return members = group['members'] and group['members'].split(' ') owners = group['owners'] and group['owners'].split(' ') missing = [] former_members = [] former_owners = [] for nick in filter(lambda s: s != '', msg.match.group(2).split(' ')): if members and nick in members: members.remove(nick) former_members.append(nick) elif owners and nick in owners: owners.remove(nick) former_owners.append(nick) else: missing.append(nick) if len(missing) > 0: missing_str = ', '.join(missing) was_plural = 'were' if len(missing) > 1 else 'was' msg.respond(f'{missing_str} {was_plural} not in {slug}.') if len(former_owners) == 0 and len(former_members) == 0: return sql_owners = owners if owners is not None: sql_owners = ' '.join(owners) sql_members = members if members is not None: sql_members = ' '.join(members) c.execute( 'UPDATE notify SET owners = %s, members = %s WHERE slug = %s', (sql_owners, sql_members, slug), ) if len(former_owners) > 0: owners_str = ', '.join(former_owners) if len(former_owners) > 1: msg.respond(f'{owners_str} were removed as owners of {slug}.') else: msg.respond(f'{owners_str} was removed as an owner of {slug}.') if len(former_members) > 0: members_str = ', '.join(former_members) if len(former_members) > 1: msg.respond(f'{members_str} were removed as members of {slug}.') else: msg.respond(f'{members_str} was removed as a member of {slug}.')