Skip to content
This repository has been archived by the owner on Oct 23, 2019. It is now read-only.

Commit

Permalink
Merge pull request #612 from linuxdaemon/gonzobot+ignore-list
Browse files Browse the repository at this point in the history
ignore: Add list command
  • Loading branch information
linuxdaemon authored Oct 12, 2019
2 parents 500dfbf + 813e532 commit 6600dcb
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 10 deletions.
76 changes: 66 additions & 10 deletions plugins/core/ignore.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from collections import OrderedDict

from irclib.util.compare import match_mask
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, String, Boolean
from sqlalchemy import (
Boolean, Column, PrimaryKeyConstraint, String, Table, UniqueConstraint, and_,
select,
)

from cloudbot import hook
from cloudbot.util import database
from cloudbot.util import database, web

table = Table(
"ignored",
Expand Down Expand Up @@ -34,12 +39,15 @@ def load_cache(db):
ignore_cache.extend(new_cache)


def ignore_in_cache(conn, chan, mask):
return (conn.casefold(), chan.casefold(), mask.casefold()) in ignore_cache


def add_ignore(db, conn, chan, mask):
if (conn, chan) in ignore_cache:
pass
else:
db.execute(table.insert().values(connection=conn, channel=chan, mask=mask))
if ignore_in_cache(conn, chan, mask):
return

db.execute(table.insert().values(connection=conn, channel=chan, mask=mask))
db.commit()
load_cache(db)

Expand All @@ -66,6 +74,8 @@ def is_ignored(conn, chan, mask):
if match_mask(mask_cf, _mask_cf):
return True

return False


# noinspection PyUnusedLocal
@hook.sieve(priority=50)
Expand Down Expand Up @@ -113,7 +123,7 @@ def ignore(text, db, chan, conn, notice, admin_log, nick):
"""<nick|mask> - ignores all input from <nick|mask> in this channel."""
target = get_user(conn, text)

if is_ignored(conn.name, chan, target):
if ignore_in_cache(conn.name, chan, target):
notice("{} is already ignored in {}.".format(target, chan))
else:
admin_log("{} used IGNORE to make me ignore {} in {}".format(nick, target, chan))
Expand All @@ -126,20 +136,34 @@ def unignore(text, db, chan, conn, notice, nick, admin_log):
"""<nick|mask> - un-ignores all input from <nick|mask> in this channel."""
target = get_user(conn, text)

if not is_ignored(conn.name, chan, target):
if not ignore_in_cache(conn.name, chan, target):
notice("{} is not ignored in {}.".format(target, chan))
else:
admin_log("{} used UNIGNORE to make me stop ignoring {} in {}".format(nick, target, chan))
notice("{} has been un-ignored in {}.".format(target, chan))
remove_ignore(db, conn.name, chan, target)


@hook.command(permissions=["ignore", "chanop"], autohelp=False)
def listignores(db, conn, chan):
"""- List all active ignores for the current channel"""

rows = db.execute(select([table.c.mask], and_(
table.c.connection == conn.name.lower(),
table.c.channel == chan.lower(),
))).fetchall()

out = '\n'.join(row['mask'] for row in rows) + '\n'

return web.paste(out)


@hook.command(permissions=["botcontrol"])
def global_ignore(text, db, conn, notice, nick, admin_log):
"""<nick|mask> - ignores all input from <nick|mask> in ALL channels."""
target = get_user(conn, text)

if is_ignored(conn.name, "*", target):
if ignore_in_cache(conn.name, "*", target):
notice("{} is already globally ignored.".format(target))
else:
notice("{} has been globally ignored.".format(target))
Expand All @@ -152,9 +176,41 @@ def global_unignore(text, db, conn, notice, nick, admin_log):
"""<nick|mask> - un-ignores all input from <nick|mask> in ALL channels."""
target = get_user(conn, text)

if not is_ignored(conn.name, "*", target):
if not ignore_in_cache(conn.name, "*", target):
notice("{} is not globally ignored.".format(target))
else:
notice("{} has been globally un-ignored.".format(target))
admin_log("{} used GLOBAL_UNIGNORE to make me stop ignoring {} everywhere".format(nick, target))
remove_ignore(db, conn.name, "*", target)


@hook.command(permissions=["botcontrol", "snoonetstaff"], autohelp=False)
def list_global_ignores(db, conn):
"""- List all global ignores for the current network"""
return listignores(db, conn, "*")


@hook.command(permissions=["botcontrol", "snoonetstaff"], autohelp=False)
def list_all_ignores(db, conn, text):
"""<chan> - List all ignores for <chan>, requires elevated permissions"""
whereclause = table.c.connection == conn.name.lower()

if text:
whereclause = and_(whereclause, table.c.channel == text.lower())

rows = db.execute(select([table.c.channel, table.c.mask], whereclause)).fetchall()

ignores = OrderedDict()

for row in rows:
ignores.setdefault(row['channel'], []).append(row['mask'])

out = ""
for chan, masks in ignores.items():
out += "Ignores for {}:\n".format(chan)
for mask in masks:
out += '- {}\n'.format(mask)

out += '\n'

return web.paste(out)
246 changes: 246 additions & 0 deletions tests/plugin_tests/test_ignore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import pytest
from mock import MagicMock


class MockConn:
def __init__(self, name):
self.name = name


def setup_db(mock_db):
from plugins.core import ignore

ignore.table.create(mock_db.engine, checkfirst=True)

sess = mock_db.session()

sess.execute(ignore.table.delete())

ignore.load_cache(sess)


def test_ignore(mock_db, patch_paste):
from plugins.core import ignore

setup_db(mock_db)

sess = mock_db.session()

conn = MockConn('testconn')

ignore.add_ignore(sess, conn.name, '#chan', '*!*@host')
ignore.add_ignore(sess, conn.name, '#chan', '*!*@host')

ignore.add_ignore(sess, conn.name, '*', '*!*@evil.host')

assert ignore.is_ignored(conn.name, '#chan', 'nick!user@host')
assert ignore.is_ignored(conn.name, '#a_chan', 'evil!user@evil.host')

assert not ignore.is_ignored(conn.name, '#chan', 'nick!user@otherhost')

assert not ignore.is_ignored(conn.name, '#otherchan', 'nick!user@host')

assert not ignore.is_ignored('otherconn', '#chan', 'nick!user@host')

ignore.listignores(sess, conn, '#chan')

patch_paste.assert_called_with('*!*@host\n')

ignore.list_all_ignores(sess, conn, '')

patch_paste.assert_called_with(
'Ignores for #chan:\n- *!*@host\n\nIgnores for *:\n- *!*@evil.host\n\n'
)

ignore.list_all_ignores(sess, conn, '#chan')

patch_paste.assert_called_with('Ignores for #chan:\n- *!*@host\n\n')

ignore.list_global_ignores(sess, conn)

patch_paste.assert_called_with('*!*@evil.host\n')


def test_remove_ignore(mock_db):
from plugins.core import ignore

setup_db(mock_db)

sess = mock_db.session()

ignore.add_ignore(sess, 'testconn', '#chan', '*!*@host')

assert ignore.is_ignored('testconn', '#chan', 'nick!user@host')

ignore.remove_ignore(sess, 'testconn', '#chan', '*!*@host')

assert not ignore.is_ignored('testconn', '#chan', 'nick!user@host')


@pytest.mark.asyncio
async def test_ignore_sieve(mock_db):
from plugins.core import ignore

setup_db(mock_db)

sess = mock_db.session()

ignore.add_ignore(sess, 'testconn', '#chan', '*!*@host')

_hook = MagicMock()
bot = MagicMock()
event = MagicMock()

_hook.type = "irc_raw"

assert (await ignore.ignore_sieve(bot, event, _hook)) is event

_hook.type = "command"
event.triggered_command = "unignore"

assert (await ignore.ignore_sieve(bot, event, _hook)) is event

event.triggered_command = "somecommand"

event.mask = None

assert (await ignore.ignore_sieve(bot, event, _hook)) is event

event.conn.name = "testconn"
event.chan = "#chan"
event.mask = "nick!user@host"

assert (await ignore.ignore_sieve(bot, event, _hook)) is None

event.conn.name = "testconn1"

assert (await ignore.ignore_sieve(bot, event, _hook)) is event


def test_get_user():
from plugins.core import ignore

conn = MagicMock()

conn.memory = {}

assert ignore.get_user(conn, "nick") == "nick!*@*"
assert ignore.get_user(conn, "nick!user@host") == "nick!user@host"

conn.memory["users"] = {"nick": {"nick": "nick", "user": "user", "host": "host"}}

assert ignore.get_user(conn, "nick") == "*!*@host"


def test_ignore_command(mock_db):
from plugins.core import ignore

setup_db(mock_db)

sess = mock_db.session()

conn = MagicMock()

conn.name = "testconn"
conn.memory = {}

event = MagicMock()

ignore.ignore(
"*!*@host", sess, "#chan", conn, event.notice, event.admin_log, "opnick"
)

event.admin_log.assert_called_with(
'opnick used IGNORE to make me ignore *!*@host in #chan'
)
event.notice.assert_called_with('*!*@host has been ignored in #chan.')
assert ignore.is_ignored('testconn', '#chan', 'nick!user@host')

event.reset_mock()

ignore.global_ignore(
"*!*@host", sess, conn, event.notice, "opnick", event.admin_log
)

event.admin_log.assert_called_with(
'opnick used GLOBAL_IGNORE to make me ignore *!*@host everywhere'
)
event.notice.assert_called_with('*!*@host has been globally ignored.')
assert ignore.is_ignored('testconn', '#otherchan', 'nick!user@host')

event.reset_mock()

ignore.ignore(
"*!*@host", sess, "#chan", conn, event.notice, event.admin_log, "opnick"
)

event.notice.assert_called_with('*!*@host is already ignored in #chan.')

event.reset_mock()

ignore.global_ignore(
"*!*@host", sess, conn, event.notice, "opnick", event.admin_log
)

event.notice.assert_called_with('*!*@host is already globally ignored.')


def test_unignore_command(mock_db):
from plugins.core import ignore

setup_db(mock_db)

sess = mock_db.session()

conn = MagicMock()

conn.name = "testconn"
conn.memory = {}

event = MagicMock()

ignore.unignore(
"*!*@host", sess, "#chan", conn, event.notice, "opnick", event.admin_log
)

event.notice.assert_called_with("*!*@host is not ignored in #chan.")

ignore.add_ignore(sess, 'testconn', '#chan', '*!*@host')

event.reset_mock()

ignore.unignore(
"*!*@host", sess, "#chan", conn, event.notice, "opnick", event.admin_log
)

event.notice.assert_called_with('*!*@host has been un-ignored in #chan.')
event.admin_log.assert_called_with(
'opnick used UNIGNORE to make me stop ignoring *!*@host in #chan'
)

assert not ignore.is_ignored("testconn", "#chan", "nick!user@host")

event.reset_mock()

ignore.global_unignore(
"*!*@host", sess, conn, event.notice, "opnick", event.admin_log
)

event.notice.assert_called_with('*!*@host is not globally ignored.')

ignore.add_ignore(sess, 'testconn', '*', '*!*@host')

event.reset_mock()

ignore.global_unignore(
"*!*@host", sess, conn, event.notice, "opnick", event.admin_log
)

event.notice.assert_called_with('*!*@host has been globally un-ignored.')
event.admin_log.assert_called_with(
'opnick used GLOBAL_UNIGNORE to make me stop ignoring *!*@host everywhere'
)

assert not ignore.is_ignored("testconn", "#chan", "nick!user@host")

event.reset_mock()

0 comments on commit 6600dcb

Please sign in to comment.