a Django-based indieweb.org site https://00dani.me/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

87 lines
3.1 KiB

  1. from django.http import HttpResponse
  2. from django.urls import resolve, reverse, Resolver404
  3. from django.shortcuts import get_object_or_404
  4. from django.views.decorators.csrf import csrf_exempt
  5. from django.views.decorators.http import require_GET, require_POST
  6. from entries.models import Entry
  7. from lemoncurry.utils import bad_req
  8. from urllib.parse import urljoin, urlparse
  9. from .models import State, Webmention
  10. @csrf_exempt
  11. @require_POST
  12. def accept(request):
  13. if 'source' not in request.POST:
  14. return bad_req('missing source url')
  15. source_url = request.POST['source']
  16. if 'target' not in request.POST:
  17. return bad_req('missing target url')
  18. target_url = request.POST['target']
  19. source = urlparse(source_url)
  20. target = urlparse(target_url)
  21. if source.scheme not in ('http', 'https'):
  22. return bad_req('unsupported source scheme')
  23. if target.scheme not in ('http', 'https'):
  24. return bad_req('unsupported target scheme')
  25. if target.netloc != request.site.domain:
  26. return bad_req('target not on this site')
  27. origin = 'https://' + target.netloc
  28. try:
  29. match = resolve(target.path)
  30. except Resolver404:
  31. return bad_req('target not found')
  32. if match.view_name != 'entries:entry':
  33. return bad_req('target does not accept webmentions')
  34. try:
  35. entry = Entry.objects.get(pk=match.kwargs['id'])
  36. except Entry.DoesNotExist:
  37. return bad_req('target not found')
  38. try:
  39. mention = Webmention.objects.get(source=source_url, target=target_url)
  40. except Webmention.DoesNotExist:
  41. mention = Webmention()
  42. mention.source = source_url
  43. mention.target = target_url
  44. mention.entry = entry
  45. mention.state = State.PENDING
  46. mention.save()
  47. status_url = reverse('webmention:status', kwargs={'id': mention.id})
  48. res = HttpResponse(status=201)
  49. res['Location'] = urljoin(origin, status_url)
  50. return res
  51. @require_GET
  52. def status(mention_id):
  53. """
  54. Retrieve the verification status of the specified webmention.
  55. A webmention is accepted synchronously by the target site (me, in this
  56. case) and then must be verified asynchronously - this means contacting the
  57. source URL and confirming that it really does link to the target URL it
  58. claimed to. Until this verification is complete, we can't assume the
  59. mention is real and shouldn't display it anywhere.
  60. Therefore, when a webmention is accepted, we return a Location header
  61. pointing to this endpoint. The source site may, if desired, use this
  62. endpoint to check whether their webmention has been verified or not.
  63. The status is currently returned as a plain string, e.g., 'pending'.
  64. However, eventually this will use a nice template instead, possibly
  65. displaying additional information about the mention. There's no
  66. standardised format for the status response, and most implementations
  67. currently use a friendly human-readable format, so I'll be doing the same.
  68. """
  69. mention = get_object_or_404(Webmention.objects, pk=mention_id)
  70. return HttpResponse(mention.get_state_display())