mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2025-04-19 17:16:42 +00:00
* add `typing-extensions` dev dependency * make sure `Self` import falls back to `typing-extensions` * let setuptools find sub-packages * pass global `Application` instance to cli commands * move `RELAY_SOFTWARE` to relay/misc.py * allow `str` for `follow` in `Message.new_unfollow`
169 lines
4.1 KiB
Python
169 lines
4.1 KiB
Python
import asyncio
|
|
import click
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
from . import cli, pass_app
|
|
|
|
from .. import http_client as http
|
|
from ..application import Application
|
|
from ..database.schema import Instance
|
|
from ..misc import ACTOR_FORMATS, Message
|
|
|
|
|
|
@cli.group("inbox")
|
|
def cli_inbox() -> None:
|
|
"Manage the inboxes in the database"
|
|
|
|
|
|
@cli_inbox.command("list")
|
|
@pass_app
|
|
def cli_inbox_list(app: Application) -> None:
|
|
"List the connected instances or relays"
|
|
|
|
click.echo("Connected to the following instances or relays:")
|
|
|
|
with app.database.session() as conn:
|
|
for row in conn.get_inboxes():
|
|
click.echo(f"- {row.inbox}")
|
|
|
|
|
|
@cli_inbox.command("follow")
|
|
@click.argument("actor")
|
|
@pass_app
|
|
def cli_inbox_follow(app: Application, actor: str) -> None:
|
|
"Follow an actor (Relay must be running)"
|
|
|
|
instance: Instance | None = None
|
|
|
|
with app.database.session() as conn:
|
|
if conn.get_domain_ban(actor):
|
|
click.echo(f"Error: Refusing to follow banned actor: {actor}")
|
|
return
|
|
|
|
if (instance := conn.get_inbox(actor)) is not None:
|
|
inbox = instance.inbox
|
|
|
|
else:
|
|
if not actor.startswith("http"):
|
|
actor = f"https://{actor}/actor"
|
|
|
|
if (actor_data := asyncio.run(http.get(actor, sign_headers = True))) is None:
|
|
click.echo(f"Failed to fetch actor: {actor}")
|
|
return
|
|
|
|
inbox = actor_data.shared_inbox
|
|
|
|
message = Message.new_follow(
|
|
host = app.config.domain,
|
|
actor = actor
|
|
)
|
|
|
|
asyncio.run(http.post(inbox, message, instance))
|
|
click.echo(f"Sent follow message to actor: {actor}")
|
|
|
|
|
|
@cli_inbox.command("unfollow")
|
|
@click.argument("actor")
|
|
@pass_app
|
|
def cli_inbox_unfollow(app: Application, actor: str) -> None:
|
|
"Unfollow an actor (Relay must be running)"
|
|
|
|
instance: Instance | None = None
|
|
|
|
with app.database.session() as conn:
|
|
if conn.get_domain_ban(actor):
|
|
click.echo(f"Error: Refusing to follow banned actor: {actor}")
|
|
return
|
|
|
|
if (instance := conn.get_inbox(actor)):
|
|
inbox = instance.inbox
|
|
message = Message.new_unfollow(
|
|
host = app.config.domain,
|
|
actor = actor,
|
|
follow = instance.followid
|
|
)
|
|
|
|
else:
|
|
if not actor.startswith("http"):
|
|
actor = f"https://{actor}/actor"
|
|
|
|
actor_data = asyncio.run(http.get(actor, sign_headers = True))
|
|
|
|
if not actor_data:
|
|
click.echo("Failed to fetch actor")
|
|
return
|
|
|
|
inbox = actor_data.shared_inbox
|
|
message = Message.new_unfollow(
|
|
host = app.config.domain,
|
|
actor = actor,
|
|
follow = {
|
|
"type": "Follow",
|
|
"object": actor,
|
|
"actor": f"https://{app.config.domain}/actor"
|
|
}
|
|
)
|
|
|
|
asyncio.run(http.post(inbox, message, instance))
|
|
click.echo(f"Sent unfollow message to: {actor}")
|
|
|
|
|
|
@cli_inbox.command("add")
|
|
@click.argument("inbox")
|
|
@click.option("--actor", "-a", help = "Actor url for the inbox")
|
|
@click.option("--followid", "-f", help = "Url for the follow activity")
|
|
@click.option("--software", "-s", help = "Nodeinfo software name of the instance")
|
|
@pass_app
|
|
def cli_inbox_add(
|
|
app: Application,
|
|
inbox: str,
|
|
actor: str | None = None,
|
|
followid: str | None = None,
|
|
software: str | None = None) -> None:
|
|
"Add an inbox to the database"
|
|
|
|
if not inbox.startswith("http"):
|
|
domain = inbox
|
|
inbox = f"https://{inbox}/inbox"
|
|
|
|
else:
|
|
domain = urlparse(inbox).netloc
|
|
|
|
if not software:
|
|
if (nodeinfo := asyncio.run(http.fetch_nodeinfo(domain))):
|
|
software = nodeinfo.sw_name
|
|
|
|
if not actor and software:
|
|
try:
|
|
actor = ACTOR_FORMATS[software].format(domain = domain)
|
|
|
|
except KeyError:
|
|
pass
|
|
|
|
with app.database.session() as conn:
|
|
if conn.get_domain_ban(domain):
|
|
click.echo(f"Refusing to add banned inbox: {inbox}")
|
|
return
|
|
|
|
if conn.get_inbox(inbox):
|
|
click.echo(f"Error: Inbox already in database: {inbox}")
|
|
return
|
|
|
|
conn.put_inbox(domain, inbox, actor, followid, software)
|
|
|
|
click.echo(f"Added inbox to the database: {inbox}")
|
|
|
|
|
|
@cli_inbox.command("remove")
|
|
@click.argument("inbox")
|
|
@pass_app
|
|
def cli_inbox_remove(app: Application, inbox: str) -> None:
|
|
"Remove an inbox from the database"
|
|
|
|
with app.database.session() as conn:
|
|
if not conn.del_inbox(inbox):
|
|
click.echo(f"Inbox not in database: {inbox}")
|
|
return
|
|
|
|
click.echo(f"Removed inbox from the database: {inbox}")
|