diff --git a/lemoncurry/settings/base.py b/lemoncurry/settings/base.py index 2deb829..52eea8f 100644 --- a/lemoncurry/settings/base.py +++ b/lemoncurry/settings/base.py @@ -85,6 +85,7 @@ INSTALLED_APPS = [ 'entries', 'home', 'lemonauth', + 'micropub', 'users', 'wellknowns', ] diff --git a/lemoncurry/templates/lemoncurry/layout.html b/lemoncurry/templates/lemoncurry/layout.html index 014c4dc..ee50daa 100644 --- a/lemoncurry/templates/lemoncurry/layout.html +++ b/lemoncurry/templates/lemoncurry/layout.html @@ -13,6 +13,7 @@ + diff --git a/lemoncurry/urls.py b/lemoncurry/urls.py index 27ccc89..6e3e5a7 100644 --- a/lemoncurry/urls.py +++ b/lemoncurry/urls.py @@ -39,6 +39,7 @@ urlpatterns = [ url('^.well-known/', include('wellknowns.urls')), url('^admin/', otp_admin_site.urls), url('^auth/', include('lemonauth.urls')), + url('^micropub', include('micropub.urls')), url('^s/', include('shorturls.urls')), url(r'^sitemap\.xml$', sitemap.index, maps, name='sitemap'), diff --git a/micropub/__init__.py b/micropub/__init__.py new file mode 100644 index 0000000..520e21e --- /dev/null +++ b/micropub/__init__.py @@ -0,0 +1 @@ +default_app_config = 'micropub.apps.MicropubConfig' diff --git a/micropub/apps.py b/micropub/apps.py new file mode 100644 index 0000000..d5259ee --- /dev/null +++ b/micropub/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MicropubConfig(AppConfig): + name = 'micropub' diff --git a/micropub/urls.py b/micropub/urls.py new file mode 100644 index 0000000..b6c48bb --- /dev/null +++ b/micropub/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import url +from . import views + +app_name = 'micropub' +urlpatterns = ( + url('^$', views.micropub, name='micropub'), +) diff --git a/micropub/views.py b/micropub/views.py new file mode 100644 index 0000000..35a726e --- /dev/null +++ b/micropub/views.py @@ -0,0 +1,52 @@ +from django.contrib.auth import get_user_model +from django.http import HttpResponse +from django_push.publisher import ping_hub +from django.urls import reverse +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_POST +from urllib.parse import urljoin + +from entries.models import Entry +from entries.kinds import Article, Note +from lemoncurry import utils +from lemonauth import tokens + + +@csrf_exempt +@require_POST +def micropub(request): + auth = request.META.get('HTTP_AUTHORIZATION', '').split(' ') + if auth[0] != 'Bearer': + return utils.bad_req('only Bearer auth supported') + try: + token = tokens.decode(auth[1]) + except Exception: + return utils.forbid('invalid token') + user = get_user_model().objects.get(pk=token['uid']) + + post = request.POST + if post.get('h') != 'entry': + return utils.bad_req('only h=entry supported') + entry = Entry(author=user, kind=Note.id) + if 'name' in post: + entry.name = post['name'] + entry.kind = Article.id + if 'content' in post: + entry.content = post['content'] + + entry.save() + + base = utils.origin(request) + perma = urljoin(base, entry.url) + others = (urljoin(base, url) for url in ( + reverse('home:index'), + reverse('entries:atom'), + reverse('entries:rss'), + )) + ping_hub(perma) + for url in others: + ping_hub(url) + + res = HttpResponse(status=201) + res['Location'] = perma + return res