86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
from django.http import HttpResponse
|
|
from django.urls import resolve, reverse, Resolver404
|
|
from django.shortcuts import get_object_or_404
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
from django.views.decorators.http import require_GET, require_POST
|
|
from entries.models import Entry
|
|
from lemoncurry.utils import bad_req
|
|
from urllib.parse import urljoin, urlparse
|
|
|
|
from .models import State, Webmention
|
|
|
|
|
|
@csrf_exempt
|
|
@require_POST
|
|
def accept(request):
|
|
if 'source' not in request.POST:
|
|
return bad_req('missing source url')
|
|
source_url = request.POST['source']
|
|
|
|
if 'target' not in request.POST:
|
|
return bad_req('missing target url')
|
|
target_url = request.POST['target']
|
|
|
|
source = urlparse(source_url)
|
|
target = urlparse(target_url)
|
|
if source.scheme not in ('http', 'https'):
|
|
return bad_req('unsupported source scheme')
|
|
if target.scheme not in ('http', 'https'):
|
|
return bad_req('unsupported target scheme')
|
|
if target.netloc != request.site.domain:
|
|
return bad_req('target not on this site')
|
|
origin = 'https://' + target.netloc
|
|
|
|
try:
|
|
match = resolve(target.path)
|
|
except Resolver404:
|
|
return bad_req('target not found')
|
|
|
|
if match.view_name != 'entries:entry':
|
|
return bad_req('target does not accept webmentions')
|
|
|
|
try:
|
|
entry = Entry.objects.get(pk=match.kwargs['id'])
|
|
except Entry.DoesNotExist:
|
|
return bad_req('target not found')
|
|
|
|
try:
|
|
mention = Webmention.objects.get(source=source_url, target=target_url)
|
|
except Webmention.DoesNotExist:
|
|
mention = Webmention()
|
|
mention.source = source_url
|
|
mention.target = target_url
|
|
|
|
mention.entry = entry
|
|
mention.state = State.PENDING
|
|
mention.save()
|
|
status_url = reverse('webmention:status', kwargs={'id': mention.id})
|
|
|
|
res = HttpResponse(status=201)
|
|
res['Location'] = urljoin(origin, status_url)
|
|
return res
|
|
|
|
|
|
@require_GET
|
|
def status(mention_id):
|
|
"""
|
|
Retrieve the verification status of the specified webmention.
|
|
|
|
A webmention is accepted synchronously by the target site (me, in this
|
|
case) and then must be verified asynchronously - this means contacting the
|
|
source URL and confirming that it really does link to the target URL it
|
|
claimed to. Until this verification is complete, we can't assume the
|
|
mention is real and shouldn't display it anywhere.
|
|
|
|
Therefore, when a webmention is accepted, we return a Location header
|
|
pointing to this endpoint. The source site may, if desired, use this
|
|
endpoint to check whether their webmention has been verified or not.
|
|
|
|
The status is currently returned as a plain string, e.g., 'pending'.
|
|
However, eventually this will use a nice template instead, possibly
|
|
displaying additional information about the mention. There's no
|
|
standardised format for the status response, and most implementations
|
|
currently use a friendly human-readable format, so I'll be doing the same.
|
|
"""
|
|
mention = get_object_or_404(Webmention.objects, pk=mention_id)
|
|
return HttpResponse(mention.get_state_display())
|