mirror of
https://github.com/ihabunek/toot.git
synced 2024-09-29 04:35:54 -04:00
commit
1098f63170
@ -137,6 +137,7 @@ def test_post(app, user, run):
|
|||||||
assert status["visibility"] == "public"
|
assert status["visibility"] == "public"
|
||||||
assert status["sensitive"] is False
|
assert status["sensitive"] is False
|
||||||
assert status["spoiler_text"] == ""
|
assert status["spoiler_text"] == ""
|
||||||
|
assert status["poll"] is None
|
||||||
|
|
||||||
# Pleroma doesn't return the application
|
# Pleroma doesn't return the application
|
||||||
if status["application"]:
|
if status["application"]:
|
||||||
@ -196,6 +197,92 @@ def test_post_scheduled_in(app, user, run):
|
|||||||
assert delta.total_seconds() < 5
|
assert delta.total_seconds() < 5
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_poll(app, user, run):
|
||||||
|
text = str(uuid.uuid4())
|
||||||
|
|
||||||
|
out = run(
|
||||||
|
"post", text,
|
||||||
|
"--poll-option", "foo",
|
||||||
|
"--poll-option", "bar",
|
||||||
|
"--poll-option", "baz",
|
||||||
|
"--poll-option", "qux",
|
||||||
|
)
|
||||||
|
|
||||||
|
status_id = _posted_status_id(out)
|
||||||
|
|
||||||
|
status = api.fetch_status(app, user, status_id)
|
||||||
|
assert status["poll"]["expired"] is False
|
||||||
|
assert status["poll"]["multiple"] is False
|
||||||
|
assert status["poll"]["options"] == [
|
||||||
|
{"title": "foo", "votes_count": 0},
|
||||||
|
{"title": "bar", "votes_count": 0},
|
||||||
|
{"title": "baz", "votes_count": 0},
|
||||||
|
{"title": "qux", "votes_count": 0}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Test expires_at is 24h by default
|
||||||
|
actual = datetime.strptime(status["poll"]["expires_at"], "%Y-%m-%dT%H:%M:%S.%f%z")
|
||||||
|
expected = datetime.now(timezone.utc) + timedelta(days=1)
|
||||||
|
delta = actual - expected
|
||||||
|
assert delta.total_seconds() < 5
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_poll_multiple(app, user, run):
|
||||||
|
text = str(uuid.uuid4())
|
||||||
|
|
||||||
|
out = run(
|
||||||
|
"post", text,
|
||||||
|
"--poll-option", "foo",
|
||||||
|
"--poll-option", "bar",
|
||||||
|
"--poll-multiple"
|
||||||
|
)
|
||||||
|
|
||||||
|
status_id = _posted_status_id(out)
|
||||||
|
|
||||||
|
status = api.fetch_status(app, user, status_id)
|
||||||
|
assert status["poll"]["multiple"] is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_poll_expires_in(app, user, run):
|
||||||
|
text = str(uuid.uuid4())
|
||||||
|
|
||||||
|
out = run(
|
||||||
|
"post", text,
|
||||||
|
"--poll-option", "foo",
|
||||||
|
"--poll-option", "bar",
|
||||||
|
"--poll-expires-in", "8h",
|
||||||
|
)
|
||||||
|
|
||||||
|
status_id = _posted_status_id(out)
|
||||||
|
|
||||||
|
status = api.fetch_status(app, user, status_id)
|
||||||
|
actual = datetime.strptime(status["poll"]["expires_at"], "%Y-%m-%dT%H:%M:%S.%f%z")
|
||||||
|
expected = datetime.now(timezone.utc) + timedelta(hours=8)
|
||||||
|
delta = actual - expected
|
||||||
|
assert delta.total_seconds() < 5
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_poll_hide_totals(app, user, run):
|
||||||
|
text = str(uuid.uuid4())
|
||||||
|
|
||||||
|
out = run(
|
||||||
|
"post", text,
|
||||||
|
"--poll-option", "foo",
|
||||||
|
"--poll-option", "bar",
|
||||||
|
"--poll-hide-totals"
|
||||||
|
)
|
||||||
|
|
||||||
|
status_id = _posted_status_id(out)
|
||||||
|
|
||||||
|
status = api.fetch_status(app, user, status_id)
|
||||||
|
|
||||||
|
# votes_count is None when totals are hidden
|
||||||
|
assert status["poll"]["options"] == [
|
||||||
|
{"title": "foo", "votes_count": None},
|
||||||
|
{"title": "bar", "votes_count": None},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_post_language(app, user, run):
|
def test_post_language(app, user, run):
|
||||||
out = run("post", "test", "--language", "hr")
|
out = run("post", "test", "--language", "hr")
|
||||||
status_id = _posted_status_id(out)
|
status_id = _posted_status_id(out)
|
||||||
@ -232,7 +319,7 @@ def test_media_thumbnail(app, user, run):
|
|||||||
assert media["preview_url"].endswith(".png")
|
assert media["preview_url"].endswith(".png")
|
||||||
|
|
||||||
# Video properties
|
# Video properties
|
||||||
assert media["meta"]["original"]["duration"] == 5.58
|
assert int(media["meta"]["original"]["duration"]) == 5
|
||||||
assert media["meta"]["original"]["height"] == 320
|
assert media["meta"]["original"]["height"] == 320
|
||||||
assert media["meta"]["original"]["width"] == 560
|
assert media["meta"]["original"]["width"] == 560
|
||||||
|
|
||||||
|
18
toot/api.py
18
toot/api.py
@ -172,6 +172,10 @@ def post_status(
|
|||||||
language=None,
|
language=None,
|
||||||
scheduled_at=None,
|
scheduled_at=None,
|
||||||
content_type=None,
|
content_type=None,
|
||||||
|
poll_options=None,
|
||||||
|
poll_expires_in=None,
|
||||||
|
poll_multiple=None,
|
||||||
|
poll_hide_totals=None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Publish a new status.
|
Publish a new status.
|
||||||
@ -184,7 +188,7 @@ def post_status(
|
|||||||
|
|
||||||
# Strip keys for which value is None
|
# Strip keys for which value is None
|
||||||
# Sending null values doesn't bother Mastodon, but it breaks Pleroma
|
# Sending null values doesn't bother Mastodon, but it breaks Pleroma
|
||||||
json = drop_empty_values({
|
data = drop_empty_values({
|
||||||
'status': status,
|
'status': status,
|
||||||
'media_ids': media_ids,
|
'media_ids': media_ids,
|
||||||
'visibility': visibility,
|
'visibility': visibility,
|
||||||
@ -193,10 +197,18 @@ def post_status(
|
|||||||
'language': language,
|
'language': language,
|
||||||
'scheduled_at': scheduled_at,
|
'scheduled_at': scheduled_at,
|
||||||
'content_type': content_type,
|
'content_type': content_type,
|
||||||
'spoiler_text': spoiler_text
|
'spoiler_text': spoiler_text,
|
||||||
})
|
})
|
||||||
|
|
||||||
return http.post(app, user, '/api/v1/statuses', json=json, headers=headers).json()
|
if poll_options:
|
||||||
|
data["poll"] = {
|
||||||
|
"options": poll_options,
|
||||||
|
"expires_in": poll_expires_in,
|
||||||
|
"multiple": poll_multiple,
|
||||||
|
"hide_totals": poll_hide_totals,
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.post(app, user, '/api/v1/statuses', json=data, headers=headers).json()
|
||||||
|
|
||||||
|
|
||||||
def fetch_status(app, user, id):
|
def fetch_status(app, user, id):
|
||||||
|
@ -87,7 +87,7 @@ def post(app, user, args):
|
|||||||
raise ConsoleError("Cannot attach more than 4 files.")
|
raise ConsoleError("Cannot attach more than 4 files.")
|
||||||
|
|
||||||
media_ids = _upload_media(app, user, args)
|
media_ids = _upload_media(app, user, args)
|
||||||
status_text = _get_status_text(args.text, args.editor)
|
status_text = _get_status_text(args.text, args.editor, args.media)
|
||||||
scheduled_at = _get_scheduled_at(args.scheduled_at, args.scheduled_in)
|
scheduled_at = _get_scheduled_at(args.scheduled_at, args.scheduled_in)
|
||||||
|
|
||||||
if not status_text and not media_ids:
|
if not status_text and not media_ids:
|
||||||
@ -102,7 +102,11 @@ def post(app, user, args):
|
|||||||
in_reply_to_id=args.reply_to,
|
in_reply_to_id=args.reply_to,
|
||||||
language=args.language,
|
language=args.language,
|
||||||
scheduled_at=scheduled_at,
|
scheduled_at=scheduled_at,
|
||||||
content_type=args.content_type
|
content_type=args.content_type,
|
||||||
|
poll_options=args.poll_option,
|
||||||
|
poll_expires_in=args.poll_expires_in,
|
||||||
|
poll_multiple=args.poll_multiple,
|
||||||
|
poll_hide_totals=args.poll_hide_totals,
|
||||||
)
|
)
|
||||||
|
|
||||||
if "scheduled_at" in response:
|
if "scheduled_at" in response:
|
||||||
@ -115,7 +119,7 @@ def post(app, user, args):
|
|||||||
delete_tmp_status_file()
|
delete_tmp_status_file()
|
||||||
|
|
||||||
|
|
||||||
def _get_status_text(text, editor):
|
def _get_status_text(text, editor, media):
|
||||||
isatty = sys.stdin.isatty()
|
isatty = sys.stdin.isatty()
|
||||||
|
|
||||||
if not text and not isatty:
|
if not text and not isatty:
|
||||||
@ -124,7 +128,7 @@ def _get_status_text(text, editor):
|
|||||||
if isatty:
|
if isatty:
|
||||||
if editor:
|
if editor:
|
||||||
text = editor_input(editor, text)
|
text = editor_input(editor, text)
|
||||||
elif not text:
|
elif not text and not media:
|
||||||
print_out("Write or paste your toot. Press <yellow>{}</yellow> to post it.".format(EOF_KEY))
|
print_out("Write or paste your toot. Press <yellow>{}</yellow> to post it.".format(EOF_KEY))
|
||||||
text = multiline_input()
|
text = multiline_input()
|
||||||
|
|
||||||
|
@ -105,6 +105,10 @@ DURATION_UNITS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DURATION_EXAMPLES = """e.g. "1 day", "2 hours 30 minutes", "5 minutes 30
|
||||||
|
seconds" or any combination of above. Shorthand: "1d", "2h30m", "5m30s\""""
|
||||||
|
|
||||||
|
|
||||||
def duration(value: str):
|
def duration(value: str):
|
||||||
match = re.match(r"""^
|
match = re.match(r"""^
|
||||||
(([0-9]+)\s*(days|day|d))?\s*
|
(([0-9]+)\s*(days|day|d))?\s*
|
||||||
@ -520,16 +524,35 @@ POST_COMMANDS = [
|
|||||||
}),
|
}),
|
||||||
(["--scheduled-in"], {
|
(["--scheduled-in"], {
|
||||||
"type": duration,
|
"type": duration,
|
||||||
"help": """Schedule the toot to be posted after a given amount
|
"help": f"""Schedule the toot to be posted after a given amount
|
||||||
of time. Examples: "1 day", "2 hours 30 minutes",
|
of time, {DURATION_EXAMPLES}. Must be at least 5
|
||||||
"5 minutes 30 seconds" or any combination of above.
|
|
||||||
Shorthand: "1d", "2h30m", "5m30s". Must be at least 5
|
|
||||||
minutes.""",
|
minutes.""",
|
||||||
}),
|
}),
|
||||||
(["-t", "--content-type"], {
|
(["-t", "--content-type"], {
|
||||||
"type": str,
|
"type": str,
|
||||||
"help": "MIME type for the status text (not supported on all instances)",
|
"help": "MIME type for the status text (not supported on all instances)",
|
||||||
}),
|
}),
|
||||||
|
(["--poll-option"], {
|
||||||
|
"action": "append",
|
||||||
|
"type": str,
|
||||||
|
"help": "Possible answer to the poll"
|
||||||
|
}),
|
||||||
|
(["--poll-expires-in"], {
|
||||||
|
"type": duration,
|
||||||
|
"help": f"""Duration that the poll should be open,
|
||||||
|
{DURATION_EXAMPLES}. Defaults to 24h.""",
|
||||||
|
"default": 24 * 60 * 60,
|
||||||
|
}),
|
||||||
|
(["--poll-multiple"], {
|
||||||
|
"action": "store_true",
|
||||||
|
"default": False,
|
||||||
|
"help": "Allow multiple answers to be selected."
|
||||||
|
}),
|
||||||
|
(["--poll-hide-totals"], {
|
||||||
|
"action": "store_true",
|
||||||
|
"default": False,
|
||||||
|
"help": "Hide vote counts until the poll ends. Defaults to false."
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
require_auth=True,
|
require_auth=True,
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user