mirror of
https://github.com/ihabunek/toot
synced 2025-02-03 12:47:32 +01:00
Add featured tag commands
This commit is contained in:
parent
743dfd715e
commit
381e3583ef
@ -1,11 +1,14 @@
|
||||
from toot import cli
|
||||
from toot.entities import Tag, from_dict, from_dict_list
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
from toot import api, cli
|
||||
from toot.entities import FeaturedTag, Tag, from_dict, from_dict_list
|
||||
|
||||
|
||||
def test_tags(run, base_url):
|
||||
def test_tags(run):
|
||||
result = run(cli.tags, "followed")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "You're not following any hashtags."
|
||||
assert result.stdout.strip() == "You're not following any hashtags"
|
||||
|
||||
result = run(cli.tags, "follow", "foo")
|
||||
assert result.exit_code == 0
|
||||
@ -13,7 +16,7 @@ def test_tags(run, base_url):
|
||||
|
||||
result = run(cli.tags, "followed")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == f"* #foo\t{base_url}/tags/foo"
|
||||
assert _find_tags(result.stdout) == ["#foo"]
|
||||
|
||||
result = run(cli.tags, "follow", "bar")
|
||||
assert result.exit_code == 0
|
||||
@ -21,10 +24,7 @@ def test_tags(run, base_url):
|
||||
|
||||
result = run(cli.tags, "followed")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "\n".join([
|
||||
f"* #bar\t{base_url}/tags/bar",
|
||||
f"* #foo\t{base_url}/tags/foo",
|
||||
])
|
||||
assert _find_tags(result.stdout) == ["#bar", "#foo"]
|
||||
|
||||
result = run(cli.tags, "unfollow", "foo")
|
||||
assert result.exit_code == 0
|
||||
@ -32,7 +32,7 @@ def test_tags(run, base_url):
|
||||
|
||||
result = run(cli.tags, "followed")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == f"* #bar\t{base_url}/tags/bar"
|
||||
assert _find_tags(result.stdout) == ["#bar"]
|
||||
|
||||
result = run(cli.tags, "unfollow", "bar")
|
||||
assert result.exit_code == 0
|
||||
@ -40,7 +40,7 @@ def test_tags(run, base_url):
|
||||
|
||||
result = run(cli.tags, "followed")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "You're not following any hashtags."
|
||||
assert result.stdout.strip() == "You're not following any hashtags"
|
||||
|
||||
|
||||
def test_tags_json(run_json):
|
||||
@ -82,3 +82,82 @@ def test_tags_json(run_json):
|
||||
|
||||
result = run_json(cli.tags, "followed", "--json")
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_tags_featured(run, app, user):
|
||||
result = run(cli.tags, "featured")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "You don't have any featured hashtags"
|
||||
|
||||
result = run(cli.tags, "feature", "foo")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "✓ Tag #foo is now featured"
|
||||
|
||||
result = run(cli.tags, "featured")
|
||||
assert result.exit_code == 0
|
||||
assert _find_tags(result.stdout) == ["#foo"]
|
||||
|
||||
result = run(cli.tags, "feature", "bar")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "✓ Tag #bar is now featured"
|
||||
|
||||
result = run(cli.tags, "featured")
|
||||
assert result.exit_code == 0
|
||||
assert _find_tags(result.stdout) == ["#bar", "#foo"]
|
||||
|
||||
# Unfeature by Name
|
||||
result = run(cli.tags, "unfeature", "foo")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "✓ Tag #foo is no longer featured"
|
||||
|
||||
result = run(cli.tags, "featured")
|
||||
assert result.exit_code == 0
|
||||
assert _find_tags(result.stdout) == ["#bar"]
|
||||
|
||||
# Unfeature by ID
|
||||
tag = api.find_featured_tag(app, user, "bar")
|
||||
assert tag is not None
|
||||
|
||||
result = run(cli.tags, "unfeature", tag["id"])
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "✓ Tag #bar is no longer featured"
|
||||
|
||||
result = run(cli.tags, "featured")
|
||||
assert result.exit_code == 0
|
||||
assert result.stdout.strip() == "You don't have any featured hashtags"
|
||||
|
||||
|
||||
def test_tags_featured_json(run_json):
|
||||
result = run_json(cli.tags, "featured", "--json")
|
||||
assert result == []
|
||||
|
||||
result = run_json(cli.tags, "feature", "foo", "--json")
|
||||
tag = from_dict(FeaturedTag, result)
|
||||
assert tag.name == "foo"
|
||||
|
||||
result = run_json(cli.tags, "featured", "--json")
|
||||
[tag] = from_dict_list(FeaturedTag, result)
|
||||
assert tag.name == "foo"
|
||||
|
||||
result = run_json(cli.tags, "feature", "bar", "--json")
|
||||
tag = from_dict(FeaturedTag, result)
|
||||
assert tag.name == "bar"
|
||||
|
||||
result = run_json(cli.tags, "featured", "--json")
|
||||
tags = from_dict_list(FeaturedTag, result)
|
||||
[bar, foo] = sorted(tags, key=lambda t: t.name)
|
||||
assert foo.name == "foo"
|
||||
assert bar.name == "bar"
|
||||
|
||||
result = run_json(cli.tags, "unfeature", "foo", "--json")
|
||||
assert result == {}
|
||||
|
||||
result = run_json(cli.tags, "unfeature", "bar", "--json")
|
||||
assert result == {}
|
||||
|
||||
result = run_json(cli.tags, "featured", "--json")
|
||||
assert result == []
|
||||
|
||||
|
||||
def _find_tags(txt: str) -> List[str]:
|
||||
return sorted(re.findall(r"#\w+", txt))
|
||||
|
23
toot/api.py
23
toot/api.py
@ -531,6 +531,29 @@ def followed_tags(app, user):
|
||||
return _get_response_list(app, user, path)
|
||||
|
||||
|
||||
def featured_tags(app, user):
|
||||
return http.get(app, user, "/api/v1/featured_tags")
|
||||
|
||||
|
||||
def feature_tag(app, user, tag: str) -> Response:
|
||||
return http.post(app, user, "/api/v1/featured_tags", data={"name": tag})
|
||||
|
||||
|
||||
def unfeature_tag(app, user, tag_id: str) -> Response:
|
||||
return http.delete(app, user, f"/api/v1/featured_tags/{tag_id}")
|
||||
|
||||
|
||||
def find_featured_tag(app, user, tag) -> Optional[dict]:
|
||||
"""Find a featured tag by tag name or ID"""
|
||||
return next(
|
||||
(
|
||||
t for t in featured_tags(app, user).json()
|
||||
if t["name"].lower() == tag.lstrip("#").lower() or t["id"] == tag
|
||||
),
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
def whois(app, user, account):
|
||||
return http.get(app, user, f'/api/v1/accounts/{account}').json()
|
||||
|
||||
|
@ -20,7 +20,10 @@ def followed(ctx: Context, json: bool):
|
||||
if json:
|
||||
click.echo(pyjson.dumps(tags))
|
||||
else:
|
||||
print_tag_list(tags)
|
||||
if tags:
|
||||
print_tag_list(tags)
|
||||
else:
|
||||
click.echo("You're not following any hashtags")
|
||||
|
||||
|
||||
@tags.command()
|
||||
@ -51,6 +54,58 @@ def unfollow(ctx: Context, tag: str, json: bool):
|
||||
click.secho(f"✓ You are no longer following #{tag}", fg="green")
|
||||
|
||||
|
||||
@tags.command()
|
||||
@json_option
|
||||
@pass_context
|
||||
def featured(ctx: Context, json: bool):
|
||||
"""List hashtags featured on your profile."""
|
||||
response = api.featured_tags(ctx.app, ctx.user)
|
||||
if json:
|
||||
click.echo(response.text)
|
||||
else:
|
||||
tags = response.json()
|
||||
if tags:
|
||||
print_tag_list(tags)
|
||||
else:
|
||||
click.echo("You don't have any featured hashtags")
|
||||
|
||||
|
||||
@tags.command()
|
||||
@click.argument("tag")
|
||||
@json_option
|
||||
@pass_context
|
||||
def feature(ctx: Context, tag: str, json: bool):
|
||||
"""Feature a hashtag on your profile"""
|
||||
tag = tag.lstrip("#")
|
||||
response = api.feature_tag(ctx.app, ctx.user, tag)
|
||||
if json:
|
||||
click.echo(response.text)
|
||||
else:
|
||||
click.secho(f"✓ Tag #{tag} is now featured", fg="green")
|
||||
|
||||
|
||||
@tags.command()
|
||||
@click.argument("tag")
|
||||
@json_option
|
||||
@pass_context
|
||||
def unfeature(ctx: Context, tag: str, json: bool):
|
||||
"""Unfollow a hashtag
|
||||
|
||||
TAG can either be a tag name like "#foo" or "foo" or a tag ID.
|
||||
"""
|
||||
featured_tag = api.find_featured_tag(ctx.app, ctx.user, tag)
|
||||
|
||||
# TODO: should this be idempotent?
|
||||
if not featured_tag:
|
||||
raise click.ClickException(f"Tag {tag} is not featured")
|
||||
|
||||
response = api.unfeature_tag(ctx.app, ctx.user, featured_tag["id"])
|
||||
if json:
|
||||
click.echo(response.text)
|
||||
else:
|
||||
click.secho(f"✓ Tag #{featured_tag['name']} is no longer featured", fg="green")
|
||||
|
||||
|
||||
# -- Deprecated commands -------------------------------------------------------
|
||||
|
||||
@cli.command(name="tags_followed", hidden=True)
|
||||
|
@ -411,6 +411,10 @@ class Relationship:
|
||||
|
||||
@dataclass
|
||||
class TagHistory:
|
||||
"""
|
||||
Usage statistics for given days (typically the past week).
|
||||
https://docs.joinmastodon.org/entities/Tag/#history
|
||||
"""
|
||||
day: str
|
||||
uses: str
|
||||
accounts: str
|
||||
@ -428,6 +432,19 @@ class Tag:
|
||||
following: Optional[bool]
|
||||
|
||||
|
||||
@dataclass
|
||||
class FeaturedTag:
|
||||
"""
|
||||
Represents a hashtag that is featured on a profile.
|
||||
https://docs.joinmastodon.org/entities/FeaturedTag/
|
||||
"""
|
||||
id: str
|
||||
name: str
|
||||
url: str
|
||||
statuses_count: int
|
||||
last_status_at: datetime
|
||||
|
||||
|
||||
# Generic data class instance
|
||||
T = TypeVar("T")
|
||||
|
||||
|
@ -115,11 +115,8 @@ def print_acct_list(accounts):
|
||||
|
||||
|
||||
def print_tag_list(tags):
|
||||
if tags:
|
||||
for tag in tags:
|
||||
click.echo(f"* {format_tag_name(tag)}\t{tag['url']}")
|
||||
else:
|
||||
click.echo("You're not following any hashtags.")
|
||||
for tag in tags:
|
||||
click.echo(f"* {format_tag_name(tag)}\t{tag['url']}")
|
||||
|
||||
|
||||
def print_lists(lists):
|
||||
|
Loading…
x
Reference in New Issue
Block a user