feat(bot_cli): add set-pin subcommand with local name resolution

This commit is contained in:
yiekheng 2026-05-02 16:58:46 +08:00
parent f5d4a554d6
commit 66d5feaea1
2 changed files with 58 additions and 0 deletions

View File

@ -23,6 +23,19 @@ def cmd_register(_args):
_print_user(bot.get_user_api()) _print_user(bot.get_user_api())
def cmd_set_pin(args):
bot = CM_BOT_HAL()
if not bot.is_whatsapp_url(args.link):
print(f"ERROR: not a WhatsApp URL: {args.link}", file=sys.stderr)
sys.exit(2)
t_username, f_username = bot.get_whatsapp_link_username(args.link)
success = bot.set_security_pin_api(args.link)
if not success:
print("ERROR: set_security_pin_api returned a falsy result", file=sys.stderr)
sys.exit(1)
print(f"OK: f_username={f_username} t_username={t_username}")
def build_parser() -> argparse.ArgumentParser: def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser( p = argparse.ArgumentParser(
prog="bot_cli", prog="bot_cli",
@ -33,6 +46,10 @@ def build_parser() -> argparse.ArgumentParser:
sp = sub.add_parser("register", aliases=["get-acc"], help="Get next available account (Telegram /1).") sp = sub.add_parser("register", aliases=["get-acc"], help="Get next available account (Telegram /1).")
sp.set_defaults(func=cmd_register) sp.set_defaults(func=cmd_register)
sp = sub.add_parser("set-pin", help="Set security PIN from a WhatsApp link (Telegram /2).")
sp.add_argument("link")
sp.set_defaults(func=cmd_set_pin)
return p return p

View File

@ -65,5 +65,46 @@ class CmdRegisterTests(unittest.TestCase):
self.assertIs(args.func, bot_cli.cmd_register) self.assertIs(args.func, bot_cli.cmd_register)
class CmdSetPinTests(unittest.TestCase):
@mock.patch.object(bot_cli, "CM_BOT_HAL")
def test_rejects_invalid_whatsapp_url(self, mock_hal_class):
mock_hal = mock_hal_class.return_value
mock_hal.is_whatsapp_url.return_value = False
with self.assertRaises(SystemExit) as cm:
bot_cli.cmd_set_pin(argparse.Namespace(link="https://not-whatsapp.example/x"))
self.assertEqual(cm.exception.code, 2)
mock_hal.set_security_pin_api.assert_not_called()
@mock.patch.object(bot_cli, "CM_BOT_HAL")
def test_extracts_names_locally_and_succeeds(self, mock_hal_class):
mock_hal = mock_hal_class.return_value
mock_hal.is_whatsapp_url.return_value = True
mock_hal.get_whatsapp_link_username.return_value = ("t_user_42", "f_user_42")
mock_hal.set_security_pin_api.return_value = True
out = io.StringIO()
with contextlib.redirect_stdout(out):
bot_cli.cmd_set_pin(argparse.Namespace(link="https://chat.whatsapp.com/abc"))
text = out.getvalue()
self.assertIn("f_username=f_user_42", text)
self.assertIn("t_username=t_user_42", text)
mock_hal.set_security_pin_api.assert_called_once_with("https://chat.whatsapp.com/abc")
@mock.patch.object(bot_cli, "CM_BOT_HAL")
def test_falsy_set_security_pin_result_exits_nonzero(self, mock_hal_class):
mock_hal = mock_hal_class.return_value
mock_hal.is_whatsapp_url.return_value = True
mock_hal.get_whatsapp_link_username.return_value = ("t", "f")
mock_hal.set_security_pin_api.return_value = False
with self.assertRaises(SystemExit) as cm:
bot_cli.cmd_set_pin(argparse.Namespace(link="https://chat.whatsapp.com/abc"))
self.assertEqual(cm.exception.code, 1)
def test_set_pin_subparser_dispatches(self):
parser = bot_cli.build_parser()
args = parser.parse_args(["set-pin", "https://chat.whatsapp.com/abc"])
self.assertIs(args.func, bot_cli.cmd_set_pin)
self.assertEqual(args.link, "https://chat.whatsapp.com/abc")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()