Skip to content

Commit

Permalink
micropub: drop url param requirement
Browse files Browse the repository at this point in the history
  • Loading branch information
snarfed committed Sep 21, 2022
1 parent 97fc8e6 commit 7bf3d9e
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 71 deletions.
37 changes: 14 additions & 23 deletions micropub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Micropub spec: https://www.w3.org/TR/micropub/
"""
import logging
import urllib.request, urllib.parse, urllib.error

from flask import jsonify, request
from granary import microformats2
Expand All @@ -20,8 +19,9 @@
from oauth_dropins.mastodon import MastodonAuth
from oauth_dropins.twitter import TwitterAuth
from mastodon import Mastodon
from publish import PublishBase
from models import Publish
import models
from publish import PublishBase
from twitter import Twitter
import util
import webmention
Expand Down Expand Up @@ -89,7 +89,9 @@ def dispatch_request(self):
'properties': remove_reserved(request.form.to_dict()),
}
elif request.files:
pass
return self.error(error='not_implemented', extra_json={
'error_description': 'Multipart/file upload is not yet supported',
})
else:
return self.error(error='invalid_request', extra_json={
'error_description': f'Unsupported Content-Type {request.content_type}',
Expand All @@ -98,33 +100,21 @@ def dispatch_request(self):
obj = microformats2.json_to_object(mf2)
logging.debug(f'Converted to ActivityStreams object: {json_dumps(obj, indent=2)}')

# TODO: is this the right idea to require mf2 url so I can de-dupe?
url = request.values.get('url') or util.get_url(obj)
assert url

# done with the sanity checks, create the Publish entity
self.entity = self.get_or_add_publish_entity(url)
if not self.entity: # get_or_add_publish_entity() populated the error response
return

# check that we haven't already published this URL
if self.entity.status == 'complete' and not appengine_info.LOCAL:
return self.error("Sorry, you've already published that page, and Bridgy Publish doesn't support updating existing posts. Details: https://github.com/snarfed/bridgy/issues/84",
extra_json={'original': self.entity.published})

# TODO: convert form-encoded, multipart to JSON

# done with the sanity checks, start publishing
self.preprocess(obj)

self.entity = Publish(source=self.source.key, mf2=mf2)
self.entity.put()
result = self.source.gr_source.create(obj)

logger.info(f'Result: {result}')
if result.error_plain:
self.entity.status = 'failed'
self.entity.put()
return self.error(result.error_plain)

self.entity.published = result.content
if 'url' not in self.entity.published:
self.entity.published['url'] = obj.get('url')
self.entity.type = self.entity.published.get('type') or models.get_type(obj)
self.entity.put()

# except HTTPException:
# # raised by us, probably via self.error()
Expand All @@ -149,7 +139,8 @@ def dispatch_request(self):
self.entity.status = 'complete'
self.entity.put()

return '', 201, {'Location': self.entity.published['url']}
url = self.entity.published.get('url')
return '', 201, ({'Location': url} if url else {})


app.add_url_rule('/micropub', view_func=Micropub.as_view('micropub'), methods=['GET', 'POST'])
1 change: 1 addition & 0 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ class Publish(ndb.Model):
status = ndb.StringProperty(choices=STATUSES, default='new')
source = ndb.KeyProperty()
html = ndb.TextProperty() # raw HTML fetched from source
mf2 = ndb.JsonProperty() # mf2 from micropub request
published = ndb.JsonProperty(compressed=True)
created = ndb.DateTimeProperty(auto_now_add=True, tzinfo=timezone.utc)
updated = ndb.DateTimeProperty(auto_now=True, tzinfo=timezone.utc)
Expand Down
49 changes: 1 addition & 48 deletions tests/test_micropub.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ def assert_response(self, status=201, token='towkin', **kwargs):
self.assertEqual('http://fake/url', resp.headers['Location'])
return resp

def check_entity(self, url='http://foo', **kwargs):
self.assertTrue(PublishedPage.get_by_id(url))
def check_entity(self, **kwargs):
publish = Publish.query().get()
self.assertEqual(self.source.key, publish.source)
self.assertEqual('complete', publish.status)
Expand Down Expand Up @@ -77,51 +76,18 @@ def test_invalid_token(self):

def test_token_query_param(self):
self.assert_response(data={
'url': 'http://foo',
'h': 'entry',
'content': 'foo bar baz',
'access_token': 'towkin',
})

def test_already_published(self):
page = PublishedPage(id='http://foo')
Publish(parent=page.key, source=self.source.key, status='complete',
type='post', published={'content': 'foo'}).put()

self.assert_response(status=400, data={
'url': 'http://foo',
'h': 'entry',
'content': 'foo bar baz',
})

def test_create_form_encoded(self):
resp = self.assert_response(data={
'url': 'http://foo',
'h': 'entry',
'content': 'foo bar baz',
})
self.check_entity(content='foo bar baz')

# def test_create_form_encoded_token_param(self):
# resp = self.client.post('/micropub', data={
# 'h': 'entry',
# 'content': 'Micropub+test+of+creating+a+basic+h-entry',
# })
# body = html.unescape(resp.get_data(as_text=True))
# self.assertEqual(201, resp.status_code,
# f'201 != {resp.status_code}: {body}')
# self.assertEqual('xyz', resp.headers['Location'])

# def test_create_form_encoded_multiple_categories(self):
# resp = self.assert_response(data={
# 'url': 'http://foo',
# 'h': 'entry',
# 'content': 'foo bar baz',
# 'category[]': 'A',
# 'category[]': 'B',
# })
# self.check_entity(content='foo bar baz')

# def test_create_form_encoded_photo_url(self):
# Content-type: application/x-www-form-urlencoded; charset=utf-8

Expand Down Expand Up @@ -155,23 +121,10 @@ def test_create_json(self):
'type': ['h-entry'],
'properties': {
'content': ['foo bar baz'],
'url': ['http://foo'],
},
})
self.check_entity()

# def test_create_json_multiple_categories(self):
# {
# "type": ["h-entry"],
# "properties": {
# "content": ["Micropub test of creating an h-entry with a JSON request containing multiple categories. This post should have two categories, test1 and test2."],
# "category": [
# "test1",
# "test2"
# ]
# }
# }

# def test_create_json_html_content(self):
# {
# "type": ["h-entry"],
Expand Down

0 comments on commit 7bf3d9e

Please sign in to comment.