mirror of
https://github.com/ihabunek/toot.git
synced 2025-02-02 15:07:51 -05:00
Add featured tag commands
This commit is contained in:
parent
743dfd715e
commit
381e3583ef
@ -1,11 +1,14 @@
|
|||||||
from toot import cli
|
import re
|
||||||
from toot.entities import Tag, from_dict, from_dict_list
|
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")
|
result = run(cli.tags, "followed")
|
||||||
assert result.exit_code == 0
|
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")
|
result = run(cli.tags, "follow", "foo")
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -13,7 +16,7 @@ def test_tags(run, base_url):
|
|||||||
|
|
||||||
result = run(cli.tags, "followed")
|
result = run(cli.tags, "followed")
|
||||||
assert result.exit_code == 0
|
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")
|
result = run(cli.tags, "follow", "bar")
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -21,10 +24,7 @@ def test_tags(run, base_url):
|
|||||||
|
|
||||||
result = run(cli.tags, "followed")
|
result = run(cli.tags, "followed")
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
assert result.stdout.strip() == "\n".join([
|
assert _find_tags(result.stdout) == ["#bar", "#foo"]
|
||||||
f"* #bar\t{base_url}/tags/bar",
|
|
||||||
f"* #foo\t{base_url}/tags/foo",
|
|
||||||
])
|
|
||||||
|
|
||||||
result = run(cli.tags, "unfollow", "foo")
|
result = run(cli.tags, "unfollow", "foo")
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -32,7 +32,7 @@ def test_tags(run, base_url):
|
|||||||
|
|
||||||
result = run(cli.tags, "followed")
|
result = run(cli.tags, "followed")
|
||||||
assert result.exit_code == 0
|
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")
|
result = run(cli.tags, "unfollow", "bar")
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -40,7 +40,7 @@ def test_tags(run, base_url):
|
|||||||
|
|
||||||
result = run(cli.tags, "followed")
|
result = run(cli.tags, "followed")
|
||||||
assert result.exit_code == 0
|
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):
|
def test_tags_json(run_json):
|
||||||
@ -82,3 +82,82 @@ def test_tags_json(run_json):
|
|||||||
|
|
||||||
result = run_json(cli.tags, "followed", "--json")
|
result = run_json(cli.tags, "followed", "--json")
|
||||||
assert result == []
|
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)
|
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):
|
def whois(app, user, account):
|
||||||
return http.get(app, user, f'/api/v1/accounts/{account}').json()
|
return http.get(app, user, f'/api/v1/accounts/{account}').json()
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ def followed(ctx: Context, json: bool):
|
|||||||
if json:
|
if json:
|
||||||
click.echo(pyjson.dumps(tags))
|
click.echo(pyjson.dumps(tags))
|
||||||
else:
|
else:
|
||||||
print_tag_list(tags)
|
if tags:
|
||||||
|
print_tag_list(tags)
|
||||||
|
else:
|
||||||
|
click.echo("You're not following any hashtags")
|
||||||
|
|
||||||
|
|
||||||
@tags.command()
|
@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")
|
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 -------------------------------------------------------
|
# -- Deprecated commands -------------------------------------------------------
|
||||||
|
|
||||||
@cli.command(name="tags_followed", hidden=True)
|
@cli.command(name="tags_followed", hidden=True)
|
||||||
|
@ -411,6 +411,10 @@ class Relationship:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TagHistory:
|
class TagHistory:
|
||||||
|
"""
|
||||||
|
Usage statistics for given days (typically the past week).
|
||||||
|
https://docs.joinmastodon.org/entities/Tag/#history
|
||||||
|
"""
|
||||||
day: str
|
day: str
|
||||||
uses: str
|
uses: str
|
||||||
accounts: str
|
accounts: str
|
||||||
@ -428,6 +432,19 @@ class Tag:
|
|||||||
following: Optional[bool]
|
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
|
# Generic data class instance
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
@ -115,11 +115,8 @@ def print_acct_list(accounts):
|
|||||||
|
|
||||||
|
|
||||||
def print_tag_list(tags):
|
def print_tag_list(tags):
|
||||||
if tags:
|
for tag in tags:
|
||||||
for tag in tags:
|
click.echo(f"* {format_tag_name(tag)}\t{tag['url']}")
|
||||||
click.echo(f"* {format_tag_name(tag)}\t{tag['url']}")
|
|
||||||
else:
|
|
||||||
click.echo("You're not following any hashtags.")
|
|
||||||
|
|
||||||
|
|
||||||
def print_lists(lists):
|
def print_lists(lists):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user