Enable support for deleting entries through Micropub :D
This commit is contained in:
parent
427dcde672
commit
fa8419976d
4 changed files with 84 additions and 13 deletions
|
@ -146,6 +146,24 @@ class Entry(ModelMeta, TimeStampedModel):
|
||||||
base = 'https://' + DjangoSite.objects.get_current().domain
|
base = 'https://' + DjangoSite.objects.get_current().domain
|
||||||
return urljoin(base, self.url)
|
return urljoin(base, self.url)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def affected_urls(self):
|
||||||
|
base = 'https://' + DjangoSite.objects.get_current().domain
|
||||||
|
kind = kinds.from_id[self.kind]
|
||||||
|
urls = {
|
||||||
|
self.url,
|
||||||
|
reverse('entries:index', kwargs={'kind': kind}),
|
||||||
|
reverse('entries:atom_by_kind', kwargs={'kind': kind}),
|
||||||
|
reverse('entries:rss_by_kind', kwargs={'kind': kind}),
|
||||||
|
} | {cat.url for cat in self.cats.all()}
|
||||||
|
if kind.on_home:
|
||||||
|
urls |= {
|
||||||
|
reverse('home:index'),
|
||||||
|
reverse('entries:atom'),
|
||||||
|
reverse('entries:rss')
|
||||||
|
}
|
||||||
|
return {urljoin(base, u) for u in urls}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
kind = kinds.from_id[self.kind]
|
kind = kinds.from_id[self.kind]
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
|
import json
|
||||||
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
|
|
||||||
from lemonauth import tokens
|
from lemonauth import tokens
|
||||||
|
|
||||||
from .create import create
|
from .create import create
|
||||||
|
from .delete import delete
|
||||||
from .query import query
|
from .query import query
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
'create': create,
|
||||||
|
'delete': delete,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@require_http_methods(['GET', 'HEAD', 'POST'])
|
@require_http_methods(['GET', 'HEAD', 'POST'])
|
||||||
|
@ -14,7 +22,13 @@ def micropub(request):
|
||||||
if hasattr(token, 'content'):
|
if hasattr(token, 'content'):
|
||||||
return token
|
return token
|
||||||
request.token = token
|
request.token = token
|
||||||
if request.method == 'POST':
|
|
||||||
return create(request)
|
|
||||||
if request.method in ('GET', 'HEAD'):
|
if request.method in ('GET', 'HEAD'):
|
||||||
return query(request)
|
return query(request)
|
||||||
|
|
||||||
|
action = request.POST.get('action', 'create')
|
||||||
|
if request.content_type == 'application/json':
|
||||||
|
request.json = json.load(request)
|
||||||
|
action = request.json.get('action', 'create')
|
||||||
|
if action in actions:
|
||||||
|
return actions[action](request)
|
||||||
|
return error.bad_req('unknown action: {}'.format(action))
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
@ -30,7 +29,7 @@ def form_to_mf2(request):
|
||||||
|
|
||||||
def create(request):
|
def create(request):
|
||||||
normalise = {
|
normalise = {
|
||||||
'application/json': json.load,
|
'application/json': lambda r: r.json,
|
||||||
'application/x-www-form-urlencoded': form_to_mf2,
|
'application/x-www-form-urlencoded': form_to_mf2,
|
||||||
}
|
}
|
||||||
if 'create' not in request.token:
|
if 'create' not in request.token:
|
||||||
|
@ -77,15 +76,7 @@ def create(request):
|
||||||
base = utils.origin(request)
|
base = utils.origin(request)
|
||||||
perma = urljoin(base, entry.url)
|
perma = urljoin(base, entry.url)
|
||||||
short = urljoin(base, entry.short_url)
|
short = urljoin(base, entry.short_url)
|
||||||
others = [urljoin(base, url) for url in (
|
ping_hub.delay(*entry.affected_urls)
|
||||||
reverse('home:index'),
|
|
||||||
reverse('entries:atom'),
|
|
||||||
reverse('entries:rss'),
|
|
||||||
reverse('entries:index', kwargs={'kind': kind}),
|
|
||||||
reverse('entries:atom_by_kind', kwargs={'kind': kind}),
|
|
||||||
reverse('entries:rss_by_kind', kwargs={'kind': kind}),
|
|
||||||
)] + [urljoin(base, cat.url) for cat in cats]
|
|
||||||
ping_hub.delay(perma, *others)
|
|
||||||
send_mentions.delay(perma)
|
send_mentions.delay(perma)
|
||||||
|
|
||||||
res = HttpResponse(status=201)
|
res = HttpResponse(status=201)
|
||||||
|
|
48
micropub/views/delete.py
Normal file
48
micropub/views/delete.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.urls import resolve, Resolver404
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from entries.jobs import ping_hub
|
||||||
|
from entries.models import Entry
|
||||||
|
|
||||||
|
from . import error
|
||||||
|
|
||||||
|
def delete(request):
|
||||||
|
normalise = {
|
||||||
|
'application/json': lambda r: r.json.get('url'),
|
||||||
|
'application/x-www-form-urlencoded': lambda r: r.POST.get('url'),
|
||||||
|
}
|
||||||
|
if 'delete' not in request.token:
|
||||||
|
return error.bad_scope('delete')
|
||||||
|
if request.content_type not in normalise:
|
||||||
|
return error.unsupported_type(request.content_type)
|
||||||
|
url = normalise[request.content_type](request)
|
||||||
|
if not url:
|
||||||
|
return error.bad_req('url parameter required')
|
||||||
|
|
||||||
|
if '//' not in url:
|
||||||
|
url = '//' + url
|
||||||
|
url = urlparse(url, scheme='https')
|
||||||
|
|
||||||
|
if url.scheme not in ('http', 'https') or url.netloc != request.site.domain:
|
||||||
|
return error.bad_req('url does not point to this site')
|
||||||
|
try:
|
||||||
|
match = resolve(url.path)
|
||||||
|
except Resolver404:
|
||||||
|
return error.bad_req('url does not point to a valid page on this site')
|
||||||
|
|
||||||
|
if match.view_name != 'entries:entry':
|
||||||
|
return error.bad_req('url does not point to an entry on this site')
|
||||||
|
|
||||||
|
try:
|
||||||
|
entry = Entry.objects.get(pk=match.kwargs['id'])
|
||||||
|
except Entry.DoesNotExist:
|
||||||
|
return error.bad_req('url does not point to an existing entry')
|
||||||
|
|
||||||
|
if entry.author != request.token.user:
|
||||||
|
return error.forbid('entry belongs to another user')
|
||||||
|
|
||||||
|
urls = entry.affected_urls
|
||||||
|
entry.delete()
|
||||||
|
ping_hub.delay(urls)
|
||||||
|
return HttpResponse(status=204)
|
Loading…
Reference in a new issue