Enable Webmentions for public posts

This commit is contained in:
Thomas Sileo 2019-09-08 12:09:34 +02:00
parent 4d968264f2
commit 018b7bf553
7 changed files with 65 additions and 7 deletions

View file

@ -32,8 +32,8 @@ from config import MEDIA_CACHE
from config import _drop_db
from core import feed
from core.activitypub import activity_url
from core.activitypub import post_to_outbox
from core.activitypub import new_context
from core.activitypub import post_to_outbox
from core.meta import Box
from core.meta import MetaKey
from core.meta import _meta

View file

@ -24,6 +24,7 @@ from core.activitypub import Box
from core.activitypub import _actor_hash
from core.activitypub import _add_answers_to_question
from core.activitypub import _cache_actor_icon
from core.activitypub import is_from_outbox
from core.activitypub import post_to_outbox
from core.activitypub import save_reply
from core.activitypub import update_cached_actor
@ -48,6 +49,7 @@ from core.shared import p
from core.tasks import Tasks
from utils import opengraph
from utils.media import is_video
from utils.webmentions import discover_webmention_endpoint
blueprint = flask.Blueprint("tasks", __name__)
@ -305,6 +307,41 @@ def task_cache_attachment() -> _Response:
return ""
@blueprint.route("/task/send_webmention", methods=["POST"])
def task_send_webmention() -> _Response:
task = p.parse(flask.request)
app.logger.info(f"task={task!r}")
note_url = task.payload["note_url"]
link = task.payload["link"]
remote_id = task.payload["remote_id"]
try:
app.logger.info(f"trying to send webmention source={note_url} target={link}")
webmention_endpoint = discover_webmention_endpoint(link)
if not webmention_endpoint:
app.logger.info("no webmention endpoint")
return ""
resp = requests.post(
webmention_endpoint,
data={"source": note_url, "target": link},
headers={"User-Agent": config.USER_AGENT},
)
app.logger.info(f"webmention endpoint resp={resp}/{resp.text}")
resp.raise_for_status()
except HTTPError as err:
app.logger.exception("request failed")
if 400 >= err.response.status_code >= 499:
app.logger.info("client error, no retry")
return ""
raise TaskError() from err
except Exception as err:
app.logger.exception(f"failed to cache actor for {link}/{remote_id}/{note_url}")
raise TaskError() from err
return ""
@blueprint.route("/task/cache_actor", methods=["POST"])
def task_cache_actor() -> _Response:
task = p.parse(flask.request)
@ -319,10 +356,18 @@ def task_cache_actor() -> _Response:
# Fetch the Open Grah metadata if it's a `Create`
if activity.has_type(ap.ActivityType.CREATE):
links = opengraph.links_from_note(activity.get_object().to_dict())
obj = activity.get_object()
links = opengraph.links_from_note(obj.to_dict())
if links:
Tasks.fetch_og_meta(iri)
# Send Webmentions only if it's from the outbox, and public
if (
is_from_outbox(obj)
and ap.get_visibility(obj) == ap.Visibility.PUBLIC
):
Tasks.send_webmentions(activity, links)
if activity.has_type(ap.ActivityType.FOLLOW):
if actor.id == config.ID:
# It's a new following, cache the "object" (which is the actor we follow)

View file

@ -6,11 +6,11 @@ from enum import Enum
from pathlib import Path
import yaml
from bleach import linkify
from itsdangerous import JSONWebSignatureSerializer
from little_boxes import strtobool
from little_boxes.activitypub import CTX_AS as AP_DEFAULT_CTX
from pymongo import MongoClient
from bleach import linkify
import sass
from utils.emojis import _load_emojis

View file

@ -9,6 +9,7 @@ from little_boxes.errors import NotAnActivityError
import config
from core.activitypub import _answer_key
from core.activitypub import handle_replies
from core.activitypub import new_context
from core.activitypub import post_to_outbox
from core.activitypub import update_cached_actor
from core.db import DB
@ -163,6 +164,7 @@ def _follow_process_inbox(activity: ap.Follow, new_meta: _NewMeta) -> None:
actor_id = activity.get_actor().id
accept = ap.Accept(
actor=config.ID,
context=new_context(activity),
object={
"type": "Follow",
"id": activity.id,

View file

@ -3,6 +3,7 @@ from datetime import datetime
from datetime import timezone
from typing import Any
from typing import Dict
from typing import Set
from little_boxes import activitypub as ap
from poussetaches import PousseTaches
@ -40,6 +41,18 @@ class Tasks:
p.push({"url": url, "iri": iri}, "/task/cache_emoji")
@staticmethod
def send_webmentions(activity: ap.Create, links: Set[str]) -> None:
for link in links:
p.push(
{
"link": link,
"note_url": activity.get_object().get_url(),
"remote_id": activity.id,
},
"/task/send_webmention",
)
@staticmethod
def cache_emojis(activity: ap.BaseActivity) -> None:
for emoji in activity.get_emojis():

View file

@ -1,5 +1,3 @@
import json
import little_boxes.activitypub as ap
import mf2py
import requests
@ -49,7 +47,7 @@ def lookup(url: str) -> ap.BaseActivity:
# Maybe the page was JSON-LD?
data = resp.json()
return ap.parse_activity(data)
except json.JSONDecodeError:
except Exception:
pass
# Try content negotiation (retry with the AP Accept header)

View file

@ -40,7 +40,7 @@ def _discover_webmention_endoint(url: str) -> Optional[str]:
return None
def discover_webmention_endoint(url: str) -> Optional[str]:
def discover_webmention_endpoint(url: str) -> Optional[str]:
"""Discover the Webmention endpoint of a given URL, if any.
Passes all the tests at https://webmention.rocks!