get more IRC bot functionality under test
remove a character, get character status, and the main level up check thread Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
parent
15df477fa4
commit
14a1c5ceb6
@ -110,6 +110,29 @@ class IdleRPG(Plugin):
|
||||
explicit_target=character.game.channel.name)
|
||||
return self.bot.reply(event, f"{character} has been successfully logged in.")
|
||||
|
||||
def handle_remove(self, connection, event, match):
|
||||
"""Handle the disabling of a character."""
|
||||
hostmask = event.source
|
||||
try:
|
||||
character = Character.objects.get(enabled=True, hostmask=hostmask)
|
||||
character.enabled = False
|
||||
character.save()
|
||||
return self.bot.reply(event, f"Character {character.name} has been disabled.")
|
||||
except Character.DoesNotExist:
|
||||
return self.bot.reply(event, "No character associated to your hostmask found (try logging in first).")
|
||||
|
||||
def handle_status(self, connection, event, match):
|
||||
"""Handle the request for character/player status."""
|
||||
hostmask = event.source
|
||||
try:
|
||||
character = Character.objects.get(enabled=True, hostmask=hostmask)
|
||||
self.bot.reply(event, f"{character}, is {hostmask}.")
|
||||
self.bot.reply(event, f"{character.name} is {Character.CHARACTER_STATUSES[character.status]}.")
|
||||
if character.status == Character.CHARACTER_STATUS_LOGGED_IN:
|
||||
self.bot.reply(event, f"{character.name} will level up on {character.next_level_str()}.")
|
||||
except Character.DoesNotExist:
|
||||
self.bot.reply(event, "No character associated to your hostmask found (try logging in first).")
|
||||
|
||||
def _handle_generic_penalty_and_logout(self, hostmask: str, channel: str, penalty: int, reason: str,
|
||||
penalty_log_attr: str):
|
||||
"""Penalize a character and log them out, for a provided reason.
|
||||
@ -135,5 +158,24 @@ class IdleRPG(Plugin):
|
||||
except Character.DoesNotExist:
|
||||
logger.debug("no character found for %s", hostmask)
|
||||
|
||||
def level_thread(self):
|
||||
"""Check for characters who have leveled up, and log as such in the channel."""
|
||||
while self.check_for_level_ups:
|
||||
time.sleep(self.SLEEP_BETWEEN_LEVEL_CHECKS)
|
||||
self._level_up_games()
|
||||
|
||||
def _level_up_games(self):
|
||||
"""Find games under management and level up characters within them, updating their channel."""
|
||||
logger.debug("checking for level ups in games")
|
||||
for game in Game.objects.filter(active=True):
|
||||
logger.debug("checking for level ups in %s", game)
|
||||
for character in Character.objects.levelable(game):
|
||||
logger.debug("going to try to level up %s", character)
|
||||
character.level_up()
|
||||
self.bot.reply(None, f"{character.name}, the {character.character_class}, has attained level "
|
||||
f"{character.level}! Next level at {character.next_level_str()}.",
|
||||
explicit_target=game.channel.name)
|
||||
character.save()
|
||||
|
||||
|
||||
plugin = IdleRPG
|
||||
|
46
tests/fixtures/simple_character.json
vendored
46
tests/fixtures/simple_character.json
vendored
@ -33,6 +33,20 @@
|
||||
"discord_bridge": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ircbot.ircchannel",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "#level_test",
|
||||
"server": 1,
|
||||
"autojoin": false,
|
||||
"topic_msg": "",
|
||||
"topic_time": "2024-05-06T05:10:25.154Z",
|
||||
"topic_by": "",
|
||||
"markov_learn_from_channel": true,
|
||||
"discord_bridge": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.game",
|
||||
"pk": 1,
|
||||
@ -42,6 +56,15 @@
|
||||
"channel": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.game",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "level test",
|
||||
"active": true,
|
||||
"channel": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.character",
|
||||
"pk": 1,
|
||||
@ -64,5 +87,28 @@
|
||||
"time_penalized_notice": 0,
|
||||
"game": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.character",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "bss2",
|
||||
"password": "pbkdf2_sha256$720000$A941t4dL96zzqeldCFucrr$Pof137/IjT3p//ZR+iYNoBnGmYPG6jLbNqenwMA3hHY=",
|
||||
"hostmask": "bss2!bss@bss",
|
||||
"status": "OFFLINE",
|
||||
"character_class": "tester",
|
||||
"level": 0,
|
||||
"next_level": "2024-05-05T05:20:45.437Z",
|
||||
"created": "2024-05-05T05:10:45.438Z",
|
||||
"last_login": "2024-05-05T05:10:45.437Z",
|
||||
"time_penalized_nick_change": 0,
|
||||
"time_penalized_part": 0,
|
||||
"time_penalized_quit": 0,
|
||||
"time_penalized_logout": 0,
|
||||
"time_penalized_kicked": 0,
|
||||
"time_penalized_privmsg": 0,
|
||||
"time_penalized_notice": 0,
|
||||
"game": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -3,6 +3,7 @@
|
||||
SPDX-FileCopyrightText: © 2024 Brian S. Stephan <bss@incorporeal.org>
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
import datetime
|
||||
import logging
|
||||
import re
|
||||
import unittest.mock as mock
|
||||
@ -255,3 +256,118 @@ class IrcPluginTest(TestCase):
|
||||
)
|
||||
|
||||
self.plugin.seen_hostmasks.remove('bss!bss@test_login')
|
||||
|
||||
def test_remove(self):
|
||||
"""Test the remove command."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss!bss@bss_remove'
|
||||
mock_event.recursing = False
|
||||
|
||||
game = Game.objects.get(pk=2)
|
||||
test_char = Character.objects.register('test_remove', game, 'test', 'bss!bss@bss_remove', 'tester')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'REMOVEME')
|
||||
self.plugin.handle_remove(self.mock_connection, mock_event, match)
|
||||
|
||||
assert test_char.enabled is True
|
||||
refetch = Character.objects.get(name='test_remove')
|
||||
assert refetch.enabled is False
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(mock_event, "Character test_remove has been disabled."),
|
||||
])
|
||||
|
||||
def test_remove_no_match(self):
|
||||
"""Test the remove command doesn't do anything if the hostname isn't found."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss2!bss@bss_remove'
|
||||
mock_event.recursing = False
|
||||
|
||||
game = Game.objects.get(pk=2)
|
||||
test_char = Character.objects.register('test_remove', game, 'test', 'bss!bss@bss_remove', 'tester')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'REMOVEME')
|
||||
self.plugin.handle_remove(self.mock_connection, mock_event, match)
|
||||
|
||||
assert test_char.enabled is True
|
||||
refetch = Character.objects.get(name='test_remove')
|
||||
assert refetch.enabled is True
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(mock_event, "No character associated to your hostmask found (try logging in first)."),
|
||||
])
|
||||
|
||||
def test_status(self):
|
||||
"""Test the status command."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss!bss@bss'
|
||||
mock_event.recursing = False
|
||||
|
||||
self.plugin.seen_hostmasks.add('bss!bss@bss')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'STATUS')
|
||||
self.plugin.handle_status(self.mock_connection, mock_event, match)
|
||||
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(mock_event, "bss, the level 0 tester, is bss!bss@bss."),
|
||||
mock.call(mock_event, "bss is logged in."),
|
||||
mock.call(mock_event, "bss will level up on 2024-05-05 05:20:45 UTC."),
|
||||
])
|
||||
assert self.mock_bot.reply.call_count == 3
|
||||
|
||||
self.plugin.seen_hostmasks.remove('bss!bss@bss')
|
||||
|
||||
def test_status_logged_out(self):
|
||||
"""Test the status command."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss2!bss@bss'
|
||||
mock_event.recursing = False
|
||||
|
||||
self.plugin.seen_hostmasks.add('bss2!bss@bss')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'STATUS')
|
||||
self.plugin.handle_status(self.mock_connection, mock_event, match)
|
||||
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(mock_event, "bss2, the level 0 tester, is bss2!bss@bss."),
|
||||
mock.call(mock_event, "bss2 is offline."),
|
||||
])
|
||||
assert self.mock_bot.reply.call_count == 2
|
||||
|
||||
self.plugin.seen_hostmasks.remove('bss2!bss@bss')
|
||||
|
||||
def test_status_no_match(self):
|
||||
"""Test the status command."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss3!bss@bss'
|
||||
mock_event.recursing = False
|
||||
|
||||
self.plugin.seen_hostmasks.add('bss3!bss@bss')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'STATUS')
|
||||
self.plugin.handle_status(self.mock_connection, mock_event, match)
|
||||
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(mock_event, "No character associated to your hostmask found (try logging in first)."),
|
||||
])
|
||||
assert self.mock_bot.reply.call_count == 1
|
||||
|
||||
self.plugin.seen_hostmasks.remove('bss3!bss@bss')
|
||||
|
||||
def test_level_up_games(self):
|
||||
"""Test the walking of games and characters to level them up."""
|
||||
game = Game.objects.get(pk=2)
|
||||
char_1 = Character.objects.register('test_level_1', game, 'test', 'test_1!test@test', 'tester')
|
||||
char_2 = Character.objects.register('test_level_2', game, 'test', 'test_2!test@test', 'tester')
|
||||
char_2.log_out()
|
||||
level_time = datetime.datetime(year=2024, month=5, day=16, hour=00, minute=0, second=0)
|
||||
char_1.next_level = level_time
|
||||
char_2.next_level = level_time
|
||||
char_1.save()
|
||||
char_2.save()
|
||||
# only one should level up, since char_2 isn't logged in
|
||||
self.plugin._level_up_games()
|
||||
|
||||
char_1 = Character.objects.get(pk=char_1.pk)
|
||||
char_2 = Character.objects.get(pk=char_2.pk)
|
||||
assert char_1.level == 1
|
||||
assert char_2.level == 0
|
||||
assert char_1.next_level != char_2.next_level
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(None, "test_level_1, the tester, has attained level 1! Next level at 2024-05-16 00:10:00 UTC.",
|
||||
explicit_target=game.channel.name),
|
||||
])
|
||||
assert self.mock_bot.reply.call_count == 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user