From 5174a751f24ec709a1bdf2ec30d68607eca76207 Mon Sep 17 00:00:00 2001 From: Denis Laxalde Date: Sun, 17 Feb 2019 14:03:11 +0100 Subject: [PATCH] Implement "notifications" command The list of notifications is diplayed with each item enclosed within an horizontal line as for timeline. When a status is involved (when notification type is "reblog" or "favourite"), we also display the full status. Closes #81. --- tests/test_console.py | 110 ++++++++++++++++++++++++++++++++++++++++++ toot/commands.py | 28 ++++++++++- toot/console.py | 6 +++ 3 files changed, 143 insertions(+), 1 deletion(-) diff --git a/tests/test_console.py b/tests/test_console.py index 1923613..ba02c54 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -436,6 +436,116 @@ def test_whoami(mock_get, capsys): assert "Statuses: 19" in out +@mock.patch('toot.http.get') +def test_notifications(mock_get, capsys): + mock_get.return_value = MockResponse([{ + 'id': '1', + 'type': 'follow', + 'created_at': '2019-02-16T07:01:20.714Z', + 'account': { + 'display_name': 'Frank Zappa', + 'acct': 'frank@zappa.social', + }, + }, { + 'id': '2', + 'type': 'mention', + 'created_at': '2017-01-12T12:12:12.0Z', + 'account': { + 'display_name': 'Dweezil Zappa', + 'acct': 'dweezil@zappa.social', + }, + 'status': { + 'id': '111111111111111111', + 'account': { + 'display_name': 'Dweezil Zappa', + 'acct': 'dweezil@zappa.social', + }, + 'created_at': '2017-04-12T15:53:18.174Z', + 'content': "

We still have fans in 2017 @fan123

", + 'reblog': None, + 'in_reply_to_id': None, + 'media_attachments': [], + }, + }, { + 'id': '3', + 'type': 'reblog', + 'created_at': '1983-11-03T03:03:03.333Z', + 'account': { + 'display_name': 'Terry Bozzio', + 'acct': 'terry@bozzio.social', + }, + 'status': { + 'id': '1234', + 'account': { + 'display_name': 'Zappa Fan', + 'acct': 'fan123@zappa-fans.social' + }, + 'created_at': '1983-11-04T15:53:18.174Z', + 'content': "

The Black Page, a masterpiece

", + 'reblog': None, + 'in_reply_to_id': None, + 'media_attachments': [], + }, + }, { + 'id': '4', + 'type': 'favourite', + 'created_at': '1983-12-13T01:02:03.444Z', + 'account': { + 'display_name': 'Zappa Old Fan', + 'acct': 'fan9@zappa-fans.social', + }, + 'status': { + 'id': '1234', + 'account': { + 'display_name': 'Zappa Fan', + 'acct': 'fan123@zappa-fans.social' + }, + 'created_at': '1983-11-04T15:53:18.174Z', + 'content': "

The Black Page, a masterpiece

", + 'reblog': None, + 'in_reply_to_id': None, + 'media_attachments': [], + }, + }]) + + console.run_command(app, user, 'notifications', []) + + mock_get.assert_called_once_with(app, user, '/api/v1/notifications') + + out, err = capsys.readouterr() + out = uncolorize(out) + + width = 100 + assert not err + assert out == "\n".join([ + "─" * width, + "Frank Zappa @frank@zappa.social now follows you", + "─" * width, + "Dweezil Zappa @dweezil@zappa.social mentioned you in", + "Dweezil Zappa @dweezil@zappa.social 2017-04-12 15:53", + "", + "We still have fans in 2017 @fan123", + "", + "ID 111111111111111111 ", + "─" * width, + "Zappa Old Fan @fan9@zappa-fans.social favourited your status", + "Zappa Fan @fan123@zappa-fans.social 1983-11-04 15:53", + "", + "The Black Page, a masterpiece", + "", + "ID 1234 ", + "─" * width, + "Terry Bozzio @terry@bozzio.social reblogged your status", + "Zappa Fan @fan123@zappa-fans.social 1983-11-04 15:53", + "", + "The Black Page, a masterpiece", + "", + "ID 1234 ", + "─" * width, + "", + ]) + + def u(user_id, access_token="abc"): username, instance = user_id.split("@") return { diff --git a/toot/commands.py b/toot/commands.py index 8fb9745..027538e 100644 --- a/toot/commands.py +++ b/toot/commands.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- +from datetime import datetime + from toot import api, config from toot.auth import login_interactive, login_browser_interactive, create_app_interactive from toot.exceptions import ConsoleError, NotFoundError -from toot.output import print_out, print_instance, print_account, print_search_results, print_timeline +from toot.output import (print_out, print_instance, print_account, + print_search_results, print_status, print_timeline) from toot.utils import assert_domain_exists, multiline_input, EOF_KEY @@ -293,3 +296,26 @@ def instance(app, user, args): "Instance not found at {}.\n" "The given domain probably does not host a Mastodon instance.".format(name) ) + + +def notifications(app, user, args): + width = 100 + for notification in sorted(api.get_notifications(app, user), + key=lambda n: datetime.strptime( + n["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ"), + reverse=True): + account = "{display_name} @{acct}".format(**notification["account"]) + msg = { + "follow": "{account} now follows you", + "mention": "{account} mentioned you in", + "reblog": "{account} reblogged your status", + "favourite": "{account} favourited your status", + }.get(notification["type"]) + if msg is None: + continue + print_out("─" * width) + print_out(msg.format(account=account)) + status = notification.get("status") + if status is not None: + print_status(status, width=width) + print_out("─" * width) diff --git a/toot/console.py b/toot/console.py index e3c9a46..755c1c3 100644 --- a/toot/console.py +++ b/toot/console.py @@ -167,6 +167,12 @@ READ_COMMANDS = [ ], require_auth=True, ), + Command( + name="notifications", + description="Notifications for logged in user", + arguments=[], + require_auth=True, + ), Command( name="instance", description="Display instance details",