kopia lustrzana https://github.com/ihabunek/toot
Porównaj commity
16 Commity
2491ed668c
...
cd35fa4033
Autor | SHA1 | Data |
---|---|---|
Daniel Schwarz | cd35fa4033 | |
Ivan Habunek | 07ad41960f | |
Sandra Snan | 07beba8c68 | |
Sandra Snan | 7244b2718f | |
Ivan Habunek | 968a516f76 | |
Ivan Habunek | 38eca67905 | |
Luca Matei Pintilie | 1d48e64853 | |
Ivan Habunek | bf12dbff70 | |
Daniel Schwarz | 31bbb20324 | |
Daniel Schwarz | 9d59df6c7e | |
Daniel Schwarz | d21b2920cb | |
Daniel Schwarz | a5cd9d343c | |
Daniel Schwarz | c30657dc24 | |
Daniel Schwarz | cb7cbd872a | |
Daniel Schwarz | ecb9c75f2e | |
Daniel Schwarz | fe5b9d1a46 |
|
@ -41,6 +41,8 @@ TRUMPET = str(Path(__file__).parent.parent.parent / "trumpet.png")
|
|||
|
||||
ASSETS_DIR = str(Path(__file__).parent.parent / "assets")
|
||||
|
||||
PASSWORD = "83dU29170rjKilKQQwuWhJv3PKnSW59bWx0perjP6i7Nu4rkeh4mRfYuvVLYM3fM"
|
||||
|
||||
|
||||
def create_app(base_url):
|
||||
instance = api.get_instance(base_url).json()
|
||||
|
@ -52,7 +54,7 @@ def register_account(app: App):
|
|||
username = str(uuid.uuid4())[-10:]
|
||||
email = f"{username}@example.com"
|
||||
|
||||
response = api.register_account(app, username, email, "password", "en")
|
||||
response = api.register_account(app, username, email, PASSWORD, "en")
|
||||
return User(app.instance, username, response["access_token"])
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from unittest import mock
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
from toot import User, cli
|
||||
from tests.integration.conftest import Run
|
||||
from tests.integration.conftest import PASSWORD, Run
|
||||
|
||||
# TODO: figure out how to test login
|
||||
|
||||
|
@ -89,7 +89,7 @@ def test_login_cli(
|
|||
cli.auth.login_cli,
|
||||
"--instance", "http://localhost:3000",
|
||||
"--email", f"{user.username}@example.com",
|
||||
"--password", "password",
|
||||
"--password", PASSWORD,
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "✓ Successfully logged in." in result.stdout
|
||||
|
|
|
@ -3,28 +3,13 @@ Helpers for testing.
|
|||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Callable
|
||||
from typing import Callable, TypeVar
|
||||
|
||||
|
||||
class MockResponse:
|
||||
def __init__(self, response_data={}, ok=True, is_redirect=False):
|
||||
self.response_data = response_data
|
||||
self.content = response_data
|
||||
self.ok = ok
|
||||
self.is_redirect = is_redirect
|
||||
|
||||
def raise_for_status(self):
|
||||
pass
|
||||
|
||||
def json(self):
|
||||
return self.response_data
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def retval(val):
|
||||
return lambda *args, **kwargs: val
|
||||
|
||||
|
||||
def run_with_retries(fn: Callable[..., Any]):
|
||||
def run_with_retries(fn: Callable[..., T]) -> T:
|
||||
"""
|
||||
Run the the given function repeatedly until it finishes without raising an
|
||||
AssertionError. Sleep a bit between attempts. If the function doesn't
|
||||
|
@ -41,4 +26,4 @@ def run_with_retries(fn: Callable[..., Any]):
|
|||
except AssertionError:
|
||||
time.sleep(delay)
|
||||
|
||||
fn()
|
||||
return fn()
|
||||
|
|
44
toot/api.py
44
toot/api.py
|
@ -8,7 +8,7 @@ from typing import BinaryIO, List, Optional
|
|||
from urllib.parse import urlparse, urlencode, quote
|
||||
|
||||
from toot import App, User, http, CLIENT_NAME, CLIENT_WEBSITE
|
||||
from toot.exceptions import ConsoleError
|
||||
from toot.exceptions import ApiError, ConsoleError
|
||||
from toot.utils import drop_empty_values, str_bool, str_bool_nullable
|
||||
|
||||
|
||||
|
@ -53,8 +53,28 @@ def _tag_action(app, user, tag_name, action) -> Response:
|
|||
return http.post(app, user, url)
|
||||
|
||||
|
||||
def create_app(base_url):
|
||||
url = f"{base_url}/api/v1/apps"
|
||||
def _status_toggle_action(app, user, status_id, action, data=None):
|
||||
url = '/api/v1/statuses/{}/{}'.format(status_id, action)
|
||||
|
||||
try:
|
||||
response = http.post(app, user, url).json()
|
||||
except ApiError as e:
|
||||
# For "toggle" operations, Mastodon returns unhelpful
|
||||
# 422: "Validation failed: Status has already been taken"
|
||||
# responses when you try to bookmark a status already
|
||||
# bookmarked, or favourite a status already favourited
|
||||
# so we just swallow those errors here
|
||||
if str(e) == "Validation failed: Status has already been taken":
|
||||
response = None
|
||||
else:
|
||||
# not the error we expected; re-raise the exception
|
||||
raise e
|
||||
finally:
|
||||
return response
|
||||
|
||||
|
||||
def create_app(domain, scheme='https'):
|
||||
url = f"{scheme}://{domain}/api/v1/apps"
|
||||
|
||||
json = {
|
||||
'client_name': CLIENT_NAME,
|
||||
|
@ -310,38 +330,40 @@ def delete_status(app, user, status_id):
|
|||
|
||||
|
||||
def favourite(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'favourite')
|
||||
return _status_toggle_action(app, user, status_id, 'favourite')
|
||||
|
||||
|
||||
def unfavourite(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'unfavourite')
|
||||
return _status_toggle_action(app, user, status_id, 'unfavourite')
|
||||
|
||||
|
||||
def reblog(app, user, status_id, visibility="public"):
|
||||
return _status_action(app, user, status_id, 'reblog', data={"visibility": visibility})
|
||||
return _status_toggle_action(app, user, status_id, 'reblog', data={"visibility": visibility})
|
||||
|
||||
|
||||
def unreblog(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'unreblog')
|
||||
return _status_toggle_action(app, user, status_id, 'unreblog')
|
||||
|
||||
|
||||
def pin(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'pin')
|
||||
return _status_toggle_action(app, user, status_id, 'pin')
|
||||
|
||||
|
||||
def unpin(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'unpin')
|
||||
return _status_toggle_action(app, user, status_id, 'unpin')
|
||||
|
||||
|
||||
def bookmark(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'bookmark')
|
||||
return _status_toggle_action(app, user, status_id, 'bookmark')
|
||||
|
||||
|
||||
def unbookmark(app, user, status_id):
|
||||
return _status_action(app, user, status_id, 'unbookmark')
|
||||
return _status_toggle_action(app, user, status_id, 'unbookmark')
|
||||
|
||||
|
||||
def translate(app, user, status_id):
|
||||
# don't use status_toggle_action for translate as this is
|
||||
# not toggling anything server-side; it's a read only operation.
|
||||
return _status_action(app, user, status_id, 'translate')
|
||||
|
||||
|
||||
|
|
|
@ -111,7 +111,10 @@ def bookmarks(
|
|||
|
||||
|
||||
@cli.command()
|
||||
@click.option("--clear", help="Dismiss all notifications and exit")
|
||||
@click.option(
|
||||
"--clear", is_flag=True,
|
||||
help="Dismiss all notifications and exit"
|
||||
)
|
||||
@click.option(
|
||||
"--reverse", "-r", is_flag=True,
|
||||
help="Reverse the order of the shown notifications (newest on top)"
|
||||
|
|
|
@ -219,7 +219,7 @@ def status_lines(status: Status) -> t.Generator[str, None, None]:
|
|||
|
||||
reply = f"↲ In reply to {yellow(in_reply_to_id)} " if in_reply_to_id else ""
|
||||
boost = f"↻ {blue(reblogged_by_acct)} boosted " if reblogged_by else ""
|
||||
yield f"ID {yellow(status_id)} {reply} {boost}"
|
||||
yield f"ID {yellow(status_id)} Visibility: {status.visibility} {reply} {boost}"
|
||||
|
||||
|
||||
def html_lines(html: str, width: int) -> t.Generator[str, None, None]:
|
||||
|
|
|
@ -327,8 +327,10 @@ class TUI(urwid.Frame):
|
|||
# get the major version number of the server
|
||||
# this works for Mastodon and Pleroma version strings
|
||||
# Mastodon versions < 4 do not have translation service
|
||||
# If the version is missing, assume 0 as a fallback
|
||||
# Revisit this logic if Pleroma implements translation
|
||||
ch = instance["version"][0]
|
||||
version = instance["version"]
|
||||
ch = "0" if not version else version[0]
|
||||
self.can_translate = int(ch) > 3 if ch.isnumeric() else False
|
||||
|
||||
return self.run_in_thread(_load_instance, done_callback=_done)
|
||||
|
|
Ładowanie…
Reference in New Issue