MultiServer: fix case sensitivity in server commands (#1156)

* fix case sensitivity in server commands

* improve ambiguous match breakout

* worried about accidentally swapping team and slot

* Remove now unused import
This commit is contained in:
Doug Hoskisson 2022-10-29 15:41:07 -07:00 committed by GitHub
parent ed23a426ec
commit 09d8c4b912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 23 deletions

View File

@ -1802,14 +1802,32 @@ class ServerCommandProcessor(CommonCommandProcessor):
self.output(response)
return False
def resolve_player(self, input_name: str) -> typing.Optional[typing.Tuple[int, int, str]]:
""" returns (team, slot, player name) """
# first match case
for (team, slot), name in self.ctx.player_names.items():
if name == input_name:
return team, slot, name
# if no case-sensitive match, then match without case only if there's only 1 match
input_lower = input_name.lower()
match: typing.Optional[typing.Tuple[int, int, str]] = None
for (team, slot), name in self.ctx.player_names.items():
lowered = name.lower()
if lowered == input_lower:
if match:
return None # ambiguous input_name
match = (team, slot, name)
return match
@mark_raw
def _cmd_collect(self, player_name: str) -> bool:
"""Send out the remaining items to player."""
seeked_player = player_name.lower()
for (team, slot), name in self.ctx.player_names.items():
if name.lower() == seeked_player:
collect_player(self.ctx, team, slot)
return True
player = self.resolve_player(player_name)
if player:
team, slot, _ = player
collect_player(self.ctx, team, slot)
return True
self.output(f"Could not find player {player_name} to collect")
return False
@ -1822,11 +1840,11 @@ class ServerCommandProcessor(CommonCommandProcessor):
@mark_raw
def _cmd_forfeit(self, player_name: str) -> bool:
"""Send out the remaining items from a player to their intended recipients."""
seeked_player = player_name.lower()
for (team, slot), name in self.ctx.player_names.items():
if name.lower() == seeked_player:
forfeit_player(self.ctx, team, slot)
return True
player = self.resolve_player(player_name)
if player:
team, slot, _ = player
forfeit_player(self.ctx, team, slot)
return True
self.output(f"Could not find player {player_name} to release")
return False
@ -1834,12 +1852,12 @@ class ServerCommandProcessor(CommonCommandProcessor):
@mark_raw
def _cmd_allow_forfeit(self, player_name: str) -> bool:
"""Allow the specified player to use the !release command."""
seeked_player = player_name.lower()
for (team, slot), name in self.ctx.player_names.items():
if name.lower() == seeked_player:
self.ctx.allow_forfeits[(team, slot)] = True
self.output(f"Player {player_name} is now allowed to use the !release command at any time.")
return True
player = self.resolve_player(player_name)
if player:
team, slot, name = player
self.ctx.allow_forfeits[(team, slot)] = True
self.output(f"Player {name} is now allowed to use the !release command at any time.")
return True
self.output(f"Could not find player {player_name} to allow the !release command for.")
return False
@ -1847,13 +1865,12 @@ class ServerCommandProcessor(CommonCommandProcessor):
@mark_raw
def _cmd_forbid_forfeit(self, player_name: str) -> bool:
""""Disallow the specified player from using the !release command."""
seeked_player = player_name.lower()
for (team, slot), name in self.ctx.player_names.items():
if name.lower() == seeked_player:
self.ctx.allow_forfeits[(team, slot)] = False
self.output(
f"Player {player_name} has to follow the server restrictions on use of the !release command.")
return True
player = self.resolve_player(player_name)
if player:
team, slot, name = player
self.ctx.allow_forfeits[(team, slot)] = False
self.output(f"Player {name} has to follow the server restrictions on use of the !release command.")
return True
self.output(f"Could not find player {player_name} to forbid the !release command for.")
return False

View File

@ -0,0 +1,40 @@
import unittest
from MultiServer import Context, ServerCommandProcessor
class TestResolvePlayerName(unittest.TestCase):
def test_resolve(self) -> None:
p = ServerCommandProcessor(Context("", 0, "", "", 0, 0, False))
p.ctx.player_names = {
(1, 1): "AAA",
(1, 2): "aBc",
(1, 3): "abC",
}
assert not p.resolve_player("abc"), "ambiguous name entry shouldn't resolve to player"
assert not p.resolve_player("Abc"), "ambiguous name entry shouldn't resolve to player"
assert p.resolve_player("aBc") == (1, 2, "aBc"), "matching case resolve"
assert p.resolve_player("abC") == (1, 3, "abC"), "matching case resolve"
assert not p.resolve_player("aB"), "partial name shouldn't resolve to player"
assert not p.resolve_player("abCD"), "incorrect name shouldn't resolve to player"
p.ctx.player_names = {
(1, 1): "aaa",
(1, 2): "abc",
(1, 3): "abC",
}
assert p.resolve_player("abc") == (1, 2, "abc"), "matching case resolve"
assert not p.resolve_player("Abc"), "ambiguous name entry shouldn't resolve to player"
assert not p.resolve_player("aBc"), "ambiguous name entry shouldn't resolve to player"
assert p.resolve_player("abC") == (1, 3, "abC"), "matching case resolve"
p.ctx.player_names = {
(1, 1): "AbcdE",
(1, 2): "abc",
(1, 3): "abCD",
}
assert p.resolve_player("abc") == (1, 2, "abc"), "matching case resolve"
assert p.resolve_player("abC") == (1, 2, "abc"), "case insensitive resolves when 1 match"
assert p.resolve_player("Abc") == (1, 2, "abc"), "case insensitive resolves when 1 match"
assert p.resolve_player("ABC") == (1, 2, "abc"), "case insensitive resolves when 1 match"
assert p.resolve_player("abcd") == (1, 3, "abCD"), "case insensitive resolves when 1 match"
assert not p.resolve_player("aB"), "partial name shouldn't resolve to player"