def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        :param str nick: an existing nickname
        :param str alias: an alias by which ``nick`` should also be known
        :raise ValueError: if the ``alias`` already exists
        :raise ~sqlalchemy.exc.SQLAlchemyError: if there is a database error

        .. seealso::

            To merge two *existing* nick groups, use :meth:`merge_nick_groups`.

            To remove an alias created with this function, use
            :meth:`unalias_nick`.

        """
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        session = self.ssession()
        try:
            result = session.query(Nicknames) \
                .filter(Nicknames.slug == alias.lower()) \
                .filter(Nicknames.canonical == alias) \
                .one_or_none()
            if result:
                raise ValueError('Alias already exists.')
            nickname = Nicknames(nick_id=nick_id, slug=alias.lower(), canonical=alias)
            session.add(nickname)
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            self.ssession.remove()
Ejemplo n.º 2
0
def cancel_bomb(bot, trigger):
    """
    Lets a bomber disarm the bomb they set on the specified user. Does not reset the cooldown timer.
    (Bot admins can cancel bombs on any player in the channel.)
    """
    target = trigger.group(3) or None
    if not target:
        for bomb in BOMBS:
            if trigger.nick == BOMBS[bomb]['bomber']:
                target = BOMBS[bomb]['target']
                break
        if not target:
            return bot.reply(STRINGS['CANCEL_WHOM'])
    target = Identifier(target)  # issue #24
    with lock:
        if target.lower() not in BOMBS:
            bot.reply(STRINGS['CANCEL_NO_BOMB'] % target)
            return
        if trigger.nick != BOMBS[target.lower()]['bomber'] and not trigger.admin:
            bot.reply(STRINGS['CANCEL_NO_PERMISSION'] % target)
            return
        bomber = BOMBS[target.lower()]['bomber']
        bombs_planted = bot.db.get_nick_value(bomber, 'bombs_planted') or 0
        bot.db.set_nick_value(bomber, 'bombs_planted', bombs_planted - 1)
        BOMBS.pop(target.lower())['timer'].cancel()
        bot.say(STRINGS['CANCEL_DONE'] % target)
Ejemplo n.º 3
0
def cutwire(bot, trigger):
    """
    Tells sopel to cut a wire when you've been bombed.
    """
    global bombs, colors
    target = Identifier(trigger.nick)
    if target.lower() != bot.nick.lower() and target.lower() not in bombs:
        bot.say('You can\'t cut a wire till someone bombs you')
        return
    if not trigger.group(2):
        bot.say('You have to choose a wire to cut.')
        return
    color, code = bombs.pop(target.lower())  # remove target from bomb list
    wirecut = trigger.group(2).rstrip(' ')
    if wirecut.lower() in ('all', 'all!'):
        sch.cancel(code)  # defuse timer, execute premature detonation
        kmsg = ('KICK %s %s : Cutting ALL the wires! *boom* (You should\'ve picked the %s wire.)'
                % (trigger.sender, target, color))
        bot.write([kmsg])
    elif wirecut.capitalize() not in colors:
        bot.say('I can\'t seem to find that wire, ' + target + '! You sure you\'re picking the right one? It\'s not here!')
        bombs[target.lower()] = (color, code)  # Add the target back onto the bomb list,
    elif wirecut.capitalize() == color:
        bot.say('You did it, ' + target + '! I\'ll be honest, I thought you were dead. But nope, you did it. You picked the right one. Well done.')
        sch.cancel(code)  # defuse bomb
    else:
        sch.cancel(code)  # defuse timer, execute premature detonation
        kmsg = 'KICK ' + trigger.sender + ' ' + target + \
               ' : No! No, that\'s the wrong one. Aww, you\'ve gone and killed yourself. Oh, that\'s... that\'s not good. No good at all, really. Wow. Sorry. (You should\'ve picked the ' + color + ' wire.)'
        bot.write([kmsg])
Ejemplo n.º 4
0
def start(bot, trigger):
    """
    Put a bomb in the specified user's pants. They will be kicked if they
     don't guess the right wire fast enough.
    """
    if not trigger.group(3):
        bot.say('Who do you want to Bomb?')
        return
    if not trigger.sender.startswith('#'):
        bot.say('Tell me this in a channel')
        return
    global bombs
    global sch
    target = Identifier(trigger.group(3))
    if target == bot.nick:
        bot.say('I will NOT BOMB MYSELF!')
        return
    if target.lower() in bombs:
        bot.say('I can\'t fit another bomb in ' + target + '\'s pants!')
        return
    if target == trigger.nick:
        bot.say('I will not LET YOU BOMB YOURSELF!')
        return
    if target.lower() not in bot.privileges[trigger.sender.lower()]:
        bot.say('Please Bomb someone WHO IS HERE!')
        return
    message = 'Hey, ' + target + '! Don\'t look but, I think there\'s a bomb in your pants. 2 minute timer, 5 wires: Red, Yellow, Blue, White and Black. Which wire should I cut? Don\'t worry, I know what I\'m doing! (respond with .cutwire color)'
    bot.say(message)
    color = choice(colors)
    bot.msg(trigger.nick,
               "Hey, don\'t tell %s, but the %s wire? Yeah, that\'s the one."
               " But shh! Don\'t say anything!" % (target, color))
    code = sch.enter(fuse, 1, explode, (bot, trigger))
    bombs[target.lower()] = (color, code)
    sch.run()
Ejemplo n.º 5
0
def cancel_bomb(bot, trigger):
    """
    Lets a bomber disarm the bomb they set on the specified user. Does not reset the cooldown timer.
    (Bot admins can cancel bombs on any player in the channel.)
    """
    target = trigger.group(3) or None
    if not target:
        for bomb in BOMBS:
            if trigger.nick == BOMBS[bomb]['bomber']:
                target = BOMBS[bomb]['target']
                break
        if not target:
            return bot.reply(STRINGS['CANCEL_WHOM'])
    target = Identifier(target)  # issue #24
    with lock:
        if target.lower() not in BOMBS:
            bot.reply(STRINGS['CANCEL_NO_BOMB'] % target)
            return
        if trigger.nick != BOMBS[target.lower()]['bomber'] and not trigger.admin:
            bot.reply(STRINGS['CANCEL_NO_PERMISSION'] % target)
            return
        bomber = BOMBS[target.lower()]['bomber']
        bombs_planted = bot.db.get_nick_value(bomber, 'bombs_planted') or 0
        bot.db.set_nick_value(bomber, 'bombs_planted', bombs_planted - 1)
        BOMBS.pop(target.lower())['timer'].cancel()
        bot.say(STRINGS['CANCEL_DONE'] % target)
Ejemplo n.º 6
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        session = self.ssession()
        try:
            result = session.query(Nicknames) \
                .filter(Nicknames.slug == alias.lower()) \
                .filter(Nicknames.canonical == alias) \
                .one_or_none()
            if result:
                raise ValueError('Given alias is the only entry in its group.')
            nickname = Nicknames(nick_id=nick_id,
                                 slug=alias.lower(),
                                 canonical=alias)
            session.add(nickname)
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            session.close()
Ejemplo n.º 7
0
def explode(bot, trigger):
    target = Identifier(trigger.group(3))
    orig_target = target
    with lock:
        if target.lower() not in BOMBS:  # nick change happened
            for nick in BOMBS.keys():
                if BOMBS[nick]['target'] == target:
                    target = Identifier(nick)
                    break
        bot.say(STRINGS['NEVER_TRIED'] % (target, BOMBS[target.lower()]['color']))
        kickboom(bot, trigger, target, BOMBS[target.lower()]['bomber'])
        BOMBS.pop(target.lower())
    timeouts = bot.db.get_nick_value(orig_target, 'bomb_timeouts') or 0
    bot.db.set_nick_value(orig_target, 'bomb_timeouts', timeouts + 1)
Ejemplo n.º 8
0
def explode(bot, trigger):
    target = Identifier(trigger.group(3))
    orig_target = target
    with lock:
        if target.lower() not in BOMBS:  # nick change happened
            for nick in BOMBS.keys():
                if BOMBS[nick]['target'] == target:
                    target = Identifier(nick)
                    break
        bot.say(STRINGS['NEVER_TRIED'] % (target, BOMBS[target.lower()]['color']))
        kickboom(bot, trigger, target)
        BOMBS.pop(target.lower())
    timeouts = bot.db.get_nick_value(orig_target, 'bomb_timeouts') or 0
    bot.db.set_nick_value(orig_target, 'bomb_timeouts', timeouts + 1)
Ejemplo n.º 9
0
def bomb_glue(bot, trigger):
    old = trigger.nick
    new = Identifier(trigger)
    with lock:
        if old.lower() in BOMBS:
            BOMBS[new.lower()] = BOMBS.pop(old.lower())
            bot.notice(STRINGS['BOMB_STILL'] % new, new)
Ejemplo n.º 10
0
def bomb_glue(bot, trigger):
    old = trigger.nick
    new = Identifier(trigger)
    with lock:
        if old.lower() in BOMBS:
            BOMBS[new.lower()] = BOMBS.pop(old.lower())
            bot.notice(STRINGS['BOMB_STILL'] % new, new)
Ejemplo n.º 11
0
    def unalias_nick(self, alias):
        """Remove an alias.

        :param str alias: an alias with at least one other nick in its group
        :raise ValueError: if there is not at least one other nick in the group
        :raise ~sqlalchemy.exc.SQLAlchemyError: if there is a database error

        .. seealso::

            To delete an entire group, use :meth:`delete_nick_group`.

            To *add* an alias for a nick, use :meth:`alias_nick`.

        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        session = self.ssession()
        try:
            count = session.query(Nicknames) \
                .filter(Nicknames.nick_id == nick_id) \
                .count()
            if count <= 1:
                raise ValueError('Given alias is the only entry in its group.')
            session.query(Nicknames).filter(
                Nicknames.slug == alias.lower()).delete()
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            self.ssession.remove()
Ejemplo n.º 12
0
def execute_main(bot, trigger):
    """Give someone a message the next time they're seen"""
    teller = trigger.nick
    verb = trigger.group(1)

    if not trigger.group(3):
        bot.reply("%s whom?" % verb)
        return

    tellee = trigger.group(3).rstrip('.,:;')
    msg = trigger.group(2).lstrip(tellee).lstrip()
    message = str(trigger.group(0))

    if not msg:
        bot.reply("%s %s what?" % (verb, tellee))
        return

    tellee = Identifier(tellee)

    if not os.path.exists(bot.tell_filename):
        return

    if len(tellee) > 20:
        return bot.reply('That nickname is too long.')
    if tellee == bot.nick:
        return bot.reply("I'm here now, you can tell me whatever you want!")
    if tellee.lower() in [u.lower() for u in bot.users]:
        if not message.endswith('please'):
            return bot.reply(
                "Tell %s that yourself you lazy f**k, they're online now." %
                tellee)

    if tellee not in (Identifier(teller), bot.nick, 'me'):
        tz = get_timezone(bot.db, bot.config, None, tellee)
        timenow = format_time(bot.db, bot.config, tz, tellee)
        msg = msg.rstrip('please').rstrip()
        bot.memory['tell_lock'].acquire()
        try:
            if tellee not in bot.memory['reminders']:
                bot.memory['reminders'][tellee] = [(teller, verb, timenow, msg)
                                                   ]
            else:
                bot.memory['reminders'][tellee].append(
                    (teller, verb, timenow, msg))
        finally:
            bot.memory['tell_lock'].release()

        response = "I'll pass that on when %s is around." % tellee

        bot.reply(response)
    elif Identifier(teller) == tellee:
        osd(bot, trigger.sender, 'say',
            "You can %s yourself that. I'm not your f*****g secretary." % verb)
    else:
        osd(bot, trigger.sender, 'say',
            "Hey, I'm not as stupid as Monty you know!")

    dumpReminders(bot.tell_filename, bot.memory['reminders'],
                  bot.memory['tell_lock'])  # @@ tell
Ejemplo n.º 13
0
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     result = self.execute(
         'SELECT value FROM nicknames JOIN nick_values '
         'ON nicknames.nick_id = nick_values.nick_id '
         'WHERE slug = ? AND key = ?', [nick.lower(), key]).fetchone()
     if result is not None:
         result = result[0]
     return _deserialize(result)
Ejemplo n.º 14
0
def verified_nick(bot, nick, channel):
    nick = re.search('([a-zA-Z0-9\[\]\\`_\^\{\|\}-]{1,32})', nick).group(1)
    if not nick:
        return None
    nick = Identifier(nick)
    if nick.lower() not in bot.privileges[channel.lower()]:
        if nick.endswith('--'):
            if Identifier(nick[:-2]).lower() in bot.privileges[channel.lower()]:
                return Identifier(nick[:-2])
        return None
    return nick
Ejemplo n.º 15
0
def cancel_bomb(bot, trigger):
    """
    Cancel the bomb placed on the specified player (can also be used by admins).
    """
    target = trigger.group(3) or None
    if not target:
        bot.reply(STRINGS['CANCEL_WHOM'])
        return
    target = Identifier(target)  # issue #24
    with lock:
        if target.lower() not in BOMBS:
            bot.reply(STRINGS['CANCEL_NO_BOMB'] % target)
            return
        if trigger.nick != BOMBS[target.lower()]['bomber'] and not trigger.admin:
            bot.reply(STRINGS['CANCEL_NO_PERMISSION'] % target)
            return
        bomber = BOMBS[target.lower()]['bomber']
        bombs_planted = bot.db.get_nick_value(bomber, 'bombs_planted') or 0
        bot.db.set_nick_value(bomber, 'bombs_planted', bombs_planted - 1)
        BOMBS.pop(target.lower())['timer'].cancel()
        bot.say(STRINGS['CANCEL_DONE'] % target)
Ejemplo n.º 16
0
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     result = self.execute(
         'SELECT value FROM nicknames JOIN nick_values '
         'ON nicknames.nick_id = nick_values.nick_id '
         'WHERE slug = ? AND key = ?',
         [nick.lower(), key]
     ).fetchone()
     if result is not None:
         result = result[0]
     return _deserialize(result)
Ejemplo n.º 17
0
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        count = self.execute('SELECT COUNT(*) FROM nicknames WHERE nick_id = ?',
                             [nick_id]).fetchone()[0]
        if count == 0:
            raise ValueError('Given alias is the only entry in its group.')
        self.execute('DELETE FROM nicknames WHERE slug = ?', [alias.lower()])
Ejemplo n.º 18
0
def cutwire(bot, trigger):
    """
    If you've been bombed, tells the bot which wire you want to cut.
    """
    global BOMBS
    target = Identifier(trigger.nick)
    if target == bot.nick:  # a parallel bot behind a bouncer (e.g. Bucket) can trigger this function (see #16)
        return
    with lock:
        if target.lower() != bot.nick.lower() and target.lower() not in BOMBS:
            bot.say(STRINGS['CUT_NO_BOMB'] % target)
            return
        if not trigger.group(3):
            bot.say(STRINGS['CUT_NO_WIRE'])
            return
        # Remove target from bomb list temporarily
        bomb = BOMBS.pop(target.lower())
        wirecut = trigger.group(3)
        if wirecut.lower() in ('all', 'all!'):
            bomb['timer'].cancel()  # defuse timer, execute premature detonation
            bot.say(STRINGS['CUT_ALL_WIRES'] % bomb['color'])
            kickboom(bot, trigger, target, bomb['bomber'])
            alls = bot.db.get_nick_value(bomb['target'], 'bomb_alls') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_alls', alls + 1)
        elif wirecut.capitalize() not in bomb['wires']:
            bot.say(STRINGS['CUT_IMAGINARY'] % target)
            # Add the target back onto the bomb list
            BOMBS[target.lower()] = bomb
        elif wirecut.capitalize() == bomb['color']:
            bot.say(STRINGS['CUT_CORRECT'] % target)
            bomb['timer'].cancel()  # defuse bomb
            defuses = bot.db.get_nick_value(bomb['target'], 'bomb_defuses') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_defuses', defuses + 1)
        else:
            bomb['timer'].cancel()  # defuse timer, execute premature detonation
            bot.say(STRINGS['CUT_WRONG'] % bomb['color'])
            kickboom(bot, trigger, target, bomb['bomber'])
            wrongs = bot.db.get_nick_value(bomb['target'], 'bomb_wrongs') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_wrongs', wrongs + 1)
Ejemplo n.º 19
0
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        count = self.execute('SELECT COUNT(*) FROM nicknames WHERE nick_id = ?',
                             [nick_id]).fetchone()[0]
        if count == 0:
            raise ValueError('Given alias is the only entry in its group.')
        self.execute('DELETE FROM nicknames WHERE slug = ?', [alias.lower()])
Ejemplo n.º 20
0
def cutwire(bot, trigger):
    """
    Tells sopel to cut a wire when you've been bombed.
    """
    global BOMBS
    target = Identifier(trigger.nick)
    if target == bot.nick:  # a parallel bot behind a bouncer (e.g. Bucket) can trigger this function (see #16)
        return
    with lock:
        if target.lower() != bot.nick.lower() and target.lower() not in BOMBS:
            bot.say(STRINGS['CUT_NO_BOMB'] % target)
            return
        if not trigger.group(3):
            bot.say(STRINGS['CUT_NO_WIRE'])
            return
        # Remove target from bomb list temporarily
        bomb = BOMBS.pop(target.lower())
        wirecut = trigger.group(3)
        if wirecut.lower() in ('all', 'all!'):
            bomb['timer'].cancel()  # defuse timer, execute premature detonation
            bot.say(STRINGS['CUT_ALL_WIRES'] % bomb['color'])
            kickboom(bot, trigger, target)
            alls = bot.db.get_nick_value(bomb['target'], 'bomb_alls') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_alls', alls + 1)
        elif wirecut.capitalize() not in bomb['wires']:
            bot.say(STRINGS['CUT_IMAGINARY'] % target)
            # Add the target back onto the bomb list
            BOMBS[target.lower()] = bomb
        elif wirecut.capitalize() == bomb['color']:
            bot.say(STRINGS['CUT_CORRECT'] % target)
            bomb['timer'].cancel()  # defuse bomb
            defuses = bot.db.get_nick_value(bomb['target'], 'bomb_defuses') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_defuses', defuses + 1)
        else:
            bomb['timer'].cancel()  # defuse timer, execute premature detonation
            bot.say(STRINGS['CUT_WRONG'] % bomb['color'])
            kickboom(bot, trigger, target)
            wrongs = bot.db.get_nick_value(bomb['target'], 'bomb_wrongs') or 0
            bot.db.set_nick_value(bomb['target'], 'bomb_wrongs', wrongs + 1)
Ejemplo n.º 21
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        sql = 'INSERT INTO nicknames (nick_id, slug, canonical) VALUES (?, ?, ?)'
        values = [nick_id, alias.lower(), alias]
        try:
            self.execute(sql, values)
        except sqlite3.IntegrityError:
            raise ValueError('Alias already exists.')
Ejemplo n.º 22
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        sql = 'INSERT INTO nicknames (nick_id, slug, canonical) VALUES (?, ?, ?)'
        values = [nick_id, alias.lower(), alias]
        try:
            self.execute(sql, values)
        except sqlite3.IntegrityError as e:
            raise ValueError('Alias already exists. {0}'.format(e))
Ejemplo n.º 23
0
    def alias_nick(self, nick, alias):
        """Create an alias for a nick.

        Raises ValueError if the alias already exists. If nick does not already
        exist, it will be added along with the alias."""
        nick = Identifier(nick)
        alias = Identifier(alias)
        nick_id = self.get_nick_id(nick)
        session = self.ssession()
        try:
            result = session.query(Nicknames) \
                .filter(Nicknames.slug == alias.lower()) \
                .filter(Nicknames.canonical == alias) \
                .one_or_none()
            if result:
                raise ValueError('Given alias is the only entry in its group.')
            nickname = Nicknames(nick_id=nick_id, slug=alias.lower(), canonical=alias)
            session.add(nickname)
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            session.close()
Ejemplo n.º 24
0
 def adjust_nick_value(self, nick, key, value):
     """Adjusts the value for a given key to be associated with the nick."""
     nick = Identifier(nick)
     result = self.execute(
         'SELECT value FROM nicknames JOIN nick_values '
         'ON nicknames.nick_id = nick_values.nick_id '
         'WHERE slug = ? AND key = ?', [nick.lower(), key]).fetchone()
     if result is not None:
         result = result[0]
     current_value = _deserialize(result)
     value = current_value + value
     value = json.dumps(value, ensure_ascii=False)
     nick_id = self.get_nick_id(nick)
     self.execute('INSERT OR REPLACE INTO nick_values VALUES (?, ?, ?)',
                  [nick_id, key, value])
Ejemplo n.º 25
0
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     session = self.ssession()
     try:
         result = session.query(NickValues) \
             .filter(Nicknames.nick_id == NickValues.nick_id) \
             .filter(Nicknames.slug == nick.lower()) \
             .filter(NickValues.key == key) \
             .one_or_none()
         if result is not None:
             result = result.value
         return _deserialize(result)
     except SQLAlchemyError:
         session.rollback()
         raise
     finally:
         session.close()
Ejemplo n.º 26
0
Archivo: test_db.py Proyecto: dgw/sopel
def test_get_nick_id(db: SopelDB):
    """Test get_nick_id does not create NickID by default."""
    nick = Identifier('MrEricPraline')

    # Attempt to get nick ID: it is not created by default
    with pytest.raises(ValueError):
        db.get_nick_id(nick)

    # Create the nick ID
    nick_id = db.get_nick_id(nick, create=True)

    # Check that one and only one nickname exists with that ID
    with db.session() as session:
        nickname = session.execute(
            select(Nicknames).where(Nicknames.nick_id == nick_id)).scalar_one(
            )  # will raise if not one and exactly one
    assert nickname.canonical == 'MrEricPraline'
    assert nickname.slug == nick.lower()
Ejemplo n.º 27
0
 def get_nick_value(self, nick, key):
     """Retrieves the value for a given key associated with a nick."""
     nick = Identifier(nick)
     session = self.ssession()
     try:
         result = session.query(NickValues) \
             .filter(Nicknames.nick_id == NickValues.nick_id) \
             .filter(Nicknames.slug == nick.lower()) \
             .filter(NickValues.key == key) \
             .one_or_none()
         if result is not None:
             result = result.value
         return _deserialize(result)
     except SQLAlchemyError:
         session.rollback()
         raise
     finally:
         session.close()
Ejemplo n.º 28
0
def test_get_nick_id(db):
    """Test get_nick_id does not create NickID by default."""
    nick = Identifier('Exirel')
    session = db.session()

    # Attempt to get nick ID: it is not created by default
    with pytest.raises(ValueError):
        db.get_nick_id(nick)

    # Create the nick ID
    nick_id = db.get_nick_id(nick, create=True)

    # Check that one and only one nickname exists with that ID
    nickname = session.query(Nicknames).filter(
        Nicknames.nick_id == nick_id,
    ).one()  # will raise if not one and exactly one
    assert nickname.canonical == 'Exirel'
    assert nickname.slug == nick.lower()

    session.close()
Ejemplo n.º 29
0
    def get_nick_value(self, nick, key, default=None):
        """Get a value from the key-value store for ``nick``.

        :param str nick: the nickname whose values to access
        :param str key: the name by which the desired value was saved
        :param mixed default: value to return if ``key`` does not have a value
                              set (optional)
        :raise ~sqlalchemy.exc.SQLAlchemyError: if there is a database error

        .. versionadded:: 7.0

            The ``default`` parameter.

        .. seealso::

            To set a value for later retrieval with this method, use
            :meth:`set_nick_value`.

            To delete a value instead of retrieving it, use
            :meth:`delete_nick_value`.

        """
        nick = Identifier(nick)
        session = self.ssession()
        try:
            result = session.query(NickValues) \
                .filter(Nicknames.nick_id == NickValues.nick_id) \
                .filter(Nicknames.slug == nick.lower()) \
                .filter(NickValues.key == key) \
                .one_or_none()
            if result is not None:
                result = result.value
            elif default is not None:
                result = default
            return _deserialize(result)
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            self.ssession.remove()
Ejemplo n.º 30
0
Archivo: db.py Proyecto: kwaaak/sopel
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        session = self.ssession()
        try:
            count = session.query(Nicknames) \
                .filter(Nicknames.nick_id == nick_id) \
                .count()
            if count <= 1:
                raise ValueError('Given alias is the only entry in its group.')
            session.query(Nicknames).filter(Nicknames.slug == alias.lower()).delete()
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            self.ssession.remove()
Ejemplo n.º 31
0
    def unalias_nick(self, alias):
        """Removes an alias.

        Raises ValueError if there is not at least one other nick in the group.
        To delete an entire group, use `delete_group`.
        """
        alias = Identifier(alias)
        nick_id = self.get_nick_id(alias, False)
        session = self.ssession()
        try:
            count = session.query(Nicknames) \
                .filter(Nicknames.nick_id == nick_id) \
                .count()
            if count <= 1:
                raise ValueError('Given alias is the only entry in its group.')
            session.query(Nicknames).filter(Nicknames.slug == alias.lower()).delete()
            session.commit()
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            session.close()
Ejemplo n.º 32
0
    def get_channel_slug(self, chan):
        """Return the case-normalized representation of ``channel``.

        :param str channel: the channel name to normalize, with prefix
                            (required)
        :return str: the case-normalized channel name (or "slug"
                     representation)

        This is useful to make sure that a channel name is stored consistently
        in both the bot's own database and third-party plugins'
        databases/files, without regard for variation in case between
        different clients and/or servers on the network.
        """
        chan = Identifier(chan)
        slug = chan.lower()
        session = self.ssession()
        try:
            count = session.query(ChannelValues) \
                .filter(ChannelValues.channel == slug) \
                .count()

            if count == 0:
                # see if it needs case-mapping migration
                old_rows = session.query(ChannelValues) \
                    .filter(ChannelValues.channel == Identifier._lower_swapped(chan))
                old_count = old_rows.count()
                if old_count > 0:
                    # it does!
                    old_rows.update({ChannelValues.channel: slug})
                    session.commit()

            return slug
        except SQLAlchemyError:
            session.rollback()
            raise
        finally:
            self.ssession.remove()
Ejemplo n.º 33
0
Archivo: rep.py Proyecto: dgw/sopel-rep
def luv_h8(bot, trigger, target, which, warn_nonexistent=True):
    target = Identifier(target)
    which = which.lower()  # issue #18
    pfx = change = selfreply = None  # keep PyCharm & other linters happy
    if target.lower() not in bot.privileges[trigger.sender.lower()]:
        if warn_nonexistent:
            bot.reply("You can only %s someone who is here." % which)
        return
    if rep_too_soon(bot, trigger.nick):
        return
    if which == 'luv':
        selfreply = "No narcissism allowed!"
        pfx, change = 'in', 1
    if which == 'h8':
        selfreply = "Go to 4chan if you really hate yourself!"
        pfx, change = 'de', -1
    if not (pfx and change and selfreply):  # safeguard against leaving something in the above mass-None assignment
        bot.say("Logic error! Please report this to %s." % bot.config.core.owner)
        return
    if is_self(bot, trigger.nick, target):
        bot.reply(selfreply)
        return
    rep = mod_rep(bot, trigger.nick, target, change)
    bot.say("%s has %screased %s's reputation score to %d" % (trigger.nick, pfx, target, rep))
Ejemplo n.º 34
0
def start(bot, trigger):
    """
    Put a bomb in the specified user's pants. If they take too long or guess wrong,
    they "die" and (if enabled) get kicked from the channel.
    """
    if not trigger.group(3):
        bot.say(STRINGS['TARGET_MISSING'])
        return NOLIMIT
    if not bombing_allowed(bot, trigger.sender):
        bot.notice(STRINGS['CHANNEL_DISABLED'] % trigger.sender, trigger.nick)
        return NOLIMIT
    since_last = time_since_bomb(bot, trigger.nick)
    if since_last < TIMEOUT:
        bot.notice(STRINGS['TIMEOUT_REMAINING'] % (TIMEOUT - since_last),
                   trigger.nick)
        return
    global BOMBS
    target = Identifier(trigger.group(3))
    target_unbombable = bot.db.get_nick_value(target, 'unbombable')
    if target == bot.nick:
        bot.say(STRINGS['TARGET_BOT'])
        return NOLIMIT
    if is_self(bot, trigger.nick, target):
        bot.say(STRINGS['TARGET_SELF'] % trigger.nick)
        return NOLIMIT
    if target.lower() not in bot.privileges[trigger.sender.lower()]:
        bot.say(STRINGS['TARGET_IMAGINARY'])
        return NOLIMIT
    if target_unbombable and not trigger.admin:
        bot.say(STRINGS['TARGET_DISABLED'] % target)
        return NOLIMIT
    if bot.db.get_nick_value(trigger.nick, 'unbombable'):
        bot.say(STRINGS['NOT_WHILE_DISABLED'] % trigger.nick)
        return NOLIMIT
    with lock:
        if target.lower() in BOMBS:
            bot.say(STRINGS['TARGET_FULL'] % target)
            return NOLIMIT
        wires = [COLORS[i] for i in sorted(sample(xrange(len(COLORS)), randrange(3, 5)))]
        num_wires = len(wires)
        wires_list = [formatting.color(str(wire), str(wire)) for wire in wires]
        wires_list = ", ".join(wires_list[:-2] + [" and ".join(wires_list[-2:])]).replace('Light_', '')
        wires = [wire.replace('Light_', '') for wire in wires]
        color = choice(wires)
        bot.say(
                choice(STRINGS['BOMB_PLANTED']) % {'target':           target,
                                                   'fuse_time': STRINGS['FUSE'],
                                                   'wire_num':         num_wires,
                                                   'wire_list':        wires_list,
                                                   'prefix':           bot.config.core.help_prefix or '.'
                                                   })
        bot.notice(STRINGS['BOMB_ANSWER'] % (target, color), trigger.nick)
        if target_unbombable:
            bot.notice(STRINGS['TARGET_DISABLED_FYI'] % target, trigger.nick)
        timer = Timer(FUSE, explode, (bot, trigger))
        BOMBS[target.lower()] = {'wires':  wires,
                                 'color':  color,
                                 'timer':  timer,
                                 'target': target,
                                 'bomber': trigger.nick
                                 }
        timer.start()
    bombs_planted = bot.db.get_nick_value(trigger.nick, 'bombs_planted') or 0
    bot.db.set_nick_value(trigger.nick, 'bombs_planted', bombs_planted + 1)
    bot.db.set_nick_value(trigger.nick, 'bomb_last_planted', time.time())
Ejemplo n.º 35
0
def explode(bot, trigger):
    target = Identifier(trigger.group(3))
    kmsg = 'KICK ' + trigger.sender + ' ' + target + \
           ' : Oh, come on, ' + target + '! You could\'ve at least picked one! Now you\'re dead. Guts, all over the place. You see that? Guts, all over YourPants. (You should\'ve picked the ' + bombs[target.lower()][0] + ' wire.)'
    bot.write([kmsg])
    bombs.pop(target.lower())
Ejemplo n.º 36
0
def start(bot, trigger):
    """
    Put a bomb in the specified user's pants. If they take too long or guess wrong,
     they die (and get kicked from the channel, if enabled).
    """
    if not trigger.group(3):
        bot.say(STRINGS['TARGET_MISSING'])
        return NOLIMIT
    if bot.db.get_channel_value(trigger.sender, 'bombs_disabled'):
        bot.notice(STRINGS['CHANNEL_DISABLED'] % trigger.sender, trigger.nick)
        return NOLIMIT
    since_last = time_since_bomb(bot, trigger.nick)
    if since_last < TIMEOUT and not trigger.admin:
        bot.notice(STRINGS['TIMEOUT_REMAINING'] % (TIMEOUT - since_last),
                   trigger.nick)
        return
    global BOMBS
    target = Identifier(trigger.group(3))
    target_unbombable = bot.db.get_nick_value(target, 'unbombable')
    if target == bot.nick:
        bot.say(STRINGS['TARGET_BOT'])
        return NOLIMIT
    if is_self(bot, trigger.nick, target):
        bot.say(STRINGS['TARGET_SELF'] % trigger.nick)
        return NOLIMIT
    if target.lower() not in bot.privileges[trigger.sender.lower()]:
        bot.say(STRINGS['TARGET_IMAGINARY'])
        return NOLIMIT
    if target_unbombable and not trigger.admin:
        bot.say(STRINGS['TARGET_DISABLED'] % target)
        return NOLIMIT
    if bot.db.get_nick_value(trigger.nick, 'unbombable'):
        bot.say(STRINGS['NOT_WHILE_DISABLED'] % trigger.nick)
        return NOLIMIT
    with lock:
        if target.lower() in BOMBS:
            bot.say(STRINGS['TARGET_FULL'] % target)
            return NOLIMIT
        wires = [COLORS[i] for i in sorted(sample(xrange(len(COLORS)), randrange(3, 5)))]
        num_wires = len(wires)
        wires_list = [formatting.color(str(wire), str(wire)) for wire in wires]
        wires_list = ", ".join(wires_list[:-2] + [" and ".join(wires_list[-2:])]).replace('Light_', '')
        wires = [wire.replace('Light_', '') for wire in wires]
        color = choice(wires)
        bot.say(
                choice(STRINGS['BOMB_PLANTED']) % {'target':           target,
                                                   'fuse_time': STRINGS['FUSE'],
                                                   'wire_num':         num_wires,
                                                   'wire_list':        wires_list,
                                                   'prefix':           bot.config.core.help_prefix or '.'
                                                   })
        bot.notice(STRINGS['BOMB_ANSWER'] % (target, color), trigger.nick)
        if target_unbombable:
            bot.notice(STRINGS['TARGET_DISABLED_FYI'] % target, trigger.nick)
        timer = Timer(FUSE, explode, (bot, trigger))
        BOMBS[target.lower()] = {'wires':  wires,
                                 'color':  color,
                                 'timer':  timer,
                                 'target': target,
                                 'bomber': trigger.nick
                                 }
        timer.start()
    bombs_planted = bot.db.get_nick_value(trigger.nick, 'bombs_planted') or 0
    bot.db.set_nick_value(trigger.nick, 'bombs_planted', bombs_planted + 1)
    bot.db.set_nick_value(trigger.nick, 'bomb_last_planted', time.time())