diff --git a/README.rst b/README.rst index 44a8e65..e5b81a6 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,8 @@ Running ``toot -h`` shows the documentation for the given command. =================== =============================================================== ``toot login`` Log into a Mastodon instance, saves access keys for later use. ``toot logout`` Log out, deletes stored access keys. - ``toot auth`` Display current login details. + ``toot auth`` Display stored authenitication tokens. + ``toot whoami`` Display logged in user details. ``toot post`` Post a status to your timeline. ``toot search`` Search for accounts or hashtags. ``toot timeline`` Display recent items in your public timeline. diff --git a/tests/test_console.py b/tests/test_console.py index fd30418..e28bd6f 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import pytest import requests +import re from toot import console, User, App @@ -10,6 +11,11 @@ app = App('https://habunek.com', 'foo', 'bar') user = User('ivan@habunek.com', 'xxx') +def uncolorize(text): + """Remove ANSI color sequences from a string""" + return re.sub(r'\x1b[^m]*m', '', text) + + def test_print_usagecap(capsys): console.print_usage() out, err = capsys.readouterr() @@ -263,3 +269,44 @@ def test_unfollow_not_found(monkeypatch, capsys): out, err = capsys.readouterr() assert "Account not found" in err + + +def test_whoami(monkeypatch, capsys): + def mock_get(url, params, headers=None): + assert url == 'https://habunek.com/api/v1/accounts/verify_credentials' + assert headers == {'Authorization': 'Bearer xxx'} + assert params is None + + return MockResponse({ + 'acct': 'ihabunek', + 'avatar': 'https://files.mastodon.social/accounts/avatars/000/046/103/original/6a1304e135cac514.jpg?1491312434', + 'avatar_static': 'https://files.mastodon.social/accounts/avatars/000/046/103/original/6a1304e135cac514.jpg?1491312434', + 'created_at': '2017-04-04T13:23:09.777Z', + 'display_name': 'Ivan Habunek', + 'followers_count': 5, + 'following_count': 9, + 'header': '/headers/original/missing.png', + 'header_static': '/headers/original/missing.png', + 'id': 46103, + 'locked': False, + 'note': 'A developer.', + 'statuses_count': 19, + 'url': 'https://mastodon.social/@ihabunek', + 'username': 'ihabunek' + }) + + monkeypatch.setattr(requests, 'get', mock_get) + + console.cmd_whoami(app, user, []) + + out, err = capsys.readouterr() + out = uncolorize(out) + + assert "@ihabunek Ivan Habunek" in out + assert "A developer." in out + assert "https://mastodon.social/@ihabunek" in out + assert "ID: 46103" in out + assert "Since: 2017-04-04 @ 13:23:09" in out + assert "Followers: 5" in out + assert "Following: 9" in out + assert "Statuses: 19" in out diff --git a/toot/api.py b/toot/api.py index 61dd9d6..30b3fb0 100644 --- a/toot/api.py +++ b/toot/api.py @@ -151,3 +151,7 @@ def unfollow(app, user, account): url = '/api/v1/accounts/%d/unfollow' % account return _post(app, user, url) + + +def verify_credentials(app, user): + return _get(app, user, '/api/v1/accounts/verify_credentials') diff --git a/toot/console.py b/toot/console.py index 552f097..a9d33ed 100644 --- a/toot/console.py +++ b/toot/console.py @@ -36,6 +36,10 @@ def yellow(text): return u"\033[33m{}\033[0m".format(text) +def blue(text): + return u"\033[34m{}\033[0m".format(text) + + def print_error(text): print(red(text), file=sys.stderr) @@ -80,10 +84,11 @@ def print_usage(): print("toot - interact with Mastodon from the command line") print("") print("Usage:") - print(" toot login - log into a Mastodon instance (saves access tokens to `~/.config/toot/`)") - print(" toot logout - log out (delete saved access tokens)") - print(" toot auth - shows currently logged in user and instance") - print(" toot post - toot a new post to your timeline") + print(" toot login - log into a Mastodon instance (stores access tokens)") + print(" toot logout - log out (delete stored access tokens)") + print(" toot auth - display stored authentication tokens") + print(" toot whoami - display logged in user details") + print(" toot post - toot a new post to your timeline") print(" toot search - search for accounts or hashtags") print(" toot timeline - shows your public timeline") print(" toot follow - follow an account") @@ -322,6 +327,26 @@ def cmd_unfollow(app, user, args): print(green(u"✓ You are no longer following %s" % args.account)) +def cmd_whoami(app, user, args): + parser = ArgumentParser(prog="toot whoami", + description="Display logged in user details", + epilog="https://github.com/ihabunek/toot") + parser.parse_args(args) + + response = api.verify_credentials(app, user) + + print("{} {}".format(green("@" + response['acct']), response['display_name'])) + print(response['note']) + print(response['url']) + print("") + print("ID: " + green(response['id'])) + print("Since: " + green(response['created_at'][:19].replace('T', ' @ '))) + print("") + print("Followers: " + yellow(response['followers_count'])) + print("Following: " + yellow(response['following_count'])) + print("Statuses: " + yellow(response['statuses_count'])) + + def run_command(command, args): app = load_app() user = load_user() @@ -360,6 +385,9 @@ def run_command(command, args): if command == 'unfollow': return cmd_unfollow(app, user, args) + if command == 'whoami': + return cmd_whoami(app, user, args) + print_error("Unknown command '{}'\n".format(command)) print_usage()