Add poll options to toot post

This commit is contained in:
Ivan Habunek 2023-03-08 14:02:51 +01:00
parent 1e3d59fee2
commit 47c16b01ad
No known key found for this signature in database
GPG key ID: F5F0623FF5EBCB3D
4 changed files with 134 additions and 8 deletions

View file

@ -137,6 +137,7 @@ def test_post(app, user, run):
assert status["visibility"] == "public"
assert status["sensitive"] is False
assert status["spoiler_text"] == ""
assert status["poll"] is None
# Pleroma doesn't return the application
if status["application"]:
@ -196,6 +197,92 @@ def test_post_scheduled_in(app, user, run):
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):
out = run("post", "test", "--language", "hr")
status_id = _posted_status_id(out)

View file

@ -172,6 +172,10 @@ def post_status(
language=None,
scheduled_at=None,
content_type=None,
poll_options=None,
poll_expires_in=None,
poll_multiple=None,
poll_hide_totals=None,
):
"""
Publish a new status.
@ -184,7 +188,7 @@ def post_status(
# Strip keys for which value is None
# Sending null values doesn't bother Mastodon, but it breaks Pleroma
json = drop_empty_values({
data = drop_empty_values({
'status': status,
'media_ids': media_ids,
'visibility': visibility,
@ -193,10 +197,18 @@ def post_status(
'language': language,
'scheduled_at': scheduled_at,
'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):

View file

@ -102,7 +102,11 @@ def post(app, user, args):
in_reply_to_id=args.reply_to,
language=args.language,
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:

View file

@ -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):
match = re.match(r"""^
(([0-9]+)\s*(days|day|d))?\s*
@ -520,16 +524,35 @@ POST_COMMANDS = [
}),
(["--scheduled-in"], {
"type": duration,
"help": """Schedule the toot to be posted after a given amount
of time. Examples: "1 day", "2 hours 30 minutes",
"5 minutes 30 seconds" or any combination of above.
Shorthand: "1d", "2h30m", "5m30s". Must be at least 5
"help": f"""Schedule the toot to be posted after a given amount
of time, {DURATION_EXAMPLES}. Must be at least 5
minutes.""",
}),
(["-t", "--content-type"], {
"type": str,
"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,
),