def micropub(event, mpData): if event == 'POST': properties = mpData['properties'] if 'h' in properties and properties['h'] is not None: if properties['h'].lower() not in ('entry',): return ('Micropub CREATE requires a valid action parameter', 400, {}) elif properties['content'] is None: return ('Micropub CREATE requires a content property', 400, {}) else: try: utcdate = datetime.datetime.utcnow() tzLocal = pytz.timezone('America/New_York') timestamp = tzLocal.localize(utcdate, is_dst=None) title = determineTitle(properties, timestamp) slug = createSlug(title) location = generateLocation(timestamp, slug) if os.path.exists(os.path.join(current_app.config['SITE_CONTENT'], '%s.md' % location)): return ('Micropub CREATE failed, location already exists', 406) else: data = { 'slug': slug, 'title': title, 'location': location, 'timestamp': timestamp.strftime('%Y-%m-%d %H:%M:%S'), 'micropub': properties, } current_app.logger.info('micropub create event for [%s]' % slug) kakuEvent('post', 'create', data) return ('Micropub CREATE successful for %s' % location, 202, {'Location': location}) except: current_app.logger.exception('Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) elif 'mp-action' in properties and properties['mp-action'] is not None: action = properties['mp-action'].lower() if action in ('delete', 'undelete'): if 'url' in properties and properties['url'] is not None: url = properties['url'] try: data = { 'url': url } kakuEvent('post', action, data) return ('Micropub %s successful for %s' % (action, url), 202, {'Location': url}) except: current_app.logger.exception('Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Micropub %s request requires a URL' % action, 400, {}) else: return ('Invalid Micropub CREATE request', 400, {}) else: return ('Unable to process Micropub %s' % data['event'], 400, {})
def micropub(event, mpData): if event == 'POST': properties = mpData['properties'] if 'action' in properties: action = properties['action'].lower() elif 'mp-action' in properties and properties['mp-action'] is not None: action = properties['mp-action'].lower() else: action = None if action == 'create': # https://www.w3.org/TR/2016/CR-micropub-20160816/#create if 'content' not in properties and 'summary' in properties: properties['content'] = ['\n'.join(properties['summary'])] properties['summary'] = [] if 'content' in properties or 'html' in properties: try: utcdate = datetime.datetime.utcnow() tzLocal = pytz.timezone('America/New_York') timestamp = tzLocal.localize(utcdate, is_dst=None) title = determineSummary(properties, timestamp) slug = createSlug(title) location = generateLocation(timestamp, slug) targetFile = os.path.join( current_app.config['SITE_CONTENT'], '%s.md' % location) if os.path.exists(targetFile): return ( 'Micropub CREATE failed, location already exists', 406) else: data = { 'slug': slug, 'title': title, 'location': location, 'timestamp': timestamp.strftime('%Y-%m-%d %H:%M:%S'), 'micropub': properties, } for key in data: current_app.logger.info(' %s = %s' % (key, data[key])) current_app.logger.info( 'micropub create event for [%s]' % slug) kakuEvent('post', 'create', data) return ('Micropub CREATE successful for %s' % location, 202, { 'Location': location }) except: current_app.logger.exception( 'Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Micropub CREATE requires a content or html property', 400, {}) elif action == 'update': # https://www.w3.org/TR/2016/CR-micropub-20160816/#update if 'url' not in properties: return ('Micropub UPDATE requires a url property', 400, {}) location = properties['url'].strip() targetPath = urlparse(location).path pathItems = targetPath.split('.') current_app.logger.info('[%s] %s' % (targetPath, pathItems)) if pathItems[-1].lower() == 'html': targetPath = '.'.join(pathItems[:-1]) slug = targetPath.replace(current_app.config['BASEROUTE'], '') targetFile = '%s.json' % os.path.join( current_app.config['SITE_CONTENT'], slug) data = { 'slug': slug, 'url': location, } if not os.path.exists(targetFile): return ( 'Micropub UPDATE failed for %s - location does not exist' % location, 404, {}) else: for key in ('add', 'delete', 'replace'): if key in properties: # "The values of each property inside the replace, add or delete keys must be an array, # even if there is only a single value." if type(properties[key]) is dict: data['micropub'] = properties[key] data['actionkey'] = key current_app.logger.info( 'micropub UPDATE (%s) event for [%s]' % (key, slug)) try: kakuEvent('post', 'update', data) return ('Micropub UPDATE successful for %s' % location, 200, { 'Location': location }) except: current_app.logger.exception( 'Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Unable to process Micropub request', 400, {}) else: return ( 'Micropub UPDATE failed for %s - currently only REPLACE is supported' % location, 406, {}) elif action in ('delete', 'undelete'): # https://www.w3.org/TR/2016/CR-micropub-20160816/#delete if 'url' in properties and properties['url'] is not None: url = properties['url'] data = {'url': url} try: kakuEvent('post', action, data) return ('Micropub %s of %s successful' % (action, url), 200, { 'Location': url }) except: current_app.logger.exception( 'Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Micropub %s request requires a URL' % action, 400, {}) else: return ('Invalid Micropub CREATE request', 400, {}) else: return ('Unable to process Micropub %s' % data['event'], 400, {})
def micropub(event, mpData): if event == 'POST': properties = mpData['properties'] if 'action' in properties: action = properties['action'].lower() elif 'mp-action' in properties and properties['mp-action'] is not None: action = properties['mp-action'].lower() else: action = None if action == 'create': # https://www.w3.org/TR/2016/CR-micropub-20160816/#create if 'content' not in properties and 'summary' in properties: properties['content'] = [ '\n'.join(properties['summary']) ] properties['summary'] = [] if 'content' in properties or 'html' in properties: try: utcdate = datetime.datetime.utcnow() tzLocal = pytz.timezone('America/New_York') timestamp = tzLocal.localize(utcdate, is_dst=None) title = determineSummary(properties, timestamp) slug = createSlug(title) location = generateLocation(timestamp, slug) targetFile = os.path.join(current_app.config['SITE_CONTENT'], '%s.md' % location) if os.path.exists(targetFile): return ('Micropub CREATE failed, location already exists', 406) else: data = { 'slug': slug, 'title': title, 'location': location, 'timestamp': timestamp.strftime('%Y-%m-%d %H:%M:%S'), 'micropub': properties, } for key in data: current_app.logger.info(' %s = %s' % (key, data[key])) current_app.logger.info('micropub create event for [%s]' % slug) kakuEvent('post', 'create', data) return ('Micropub CREATE successful for %s' % location, 202, {'Location': location}) except: current_app.logger.exception('Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Micropub CREATE requires a content or html property', 400, {}) elif action == 'update': # https://www.w3.org/TR/2016/CR-micropub-20160816/#update if 'url' not in properties: return ('Micropub UPDATE requires a url property', 400, {}) location = properties['url'].strip() targetPath = urlparse(location).path pathItems = targetPath.split('.') current_app.logger.info('[%s] %s' % (targetPath, pathItems)) if pathItems[-1].lower() == 'html': targetPath = '.'.join(pathItems[:-1]) slug = targetPath.replace(current_app.config['BASEROUTE'], '') targetFile = '%s.json' % os.path.join(current_app.config['SITE_CONTENT'], slug) data = { 'slug': slug, 'url': location, } if not os.path.exists(targetFile): return ('Micropub UPDATE failed for %s - location does not exist' % location, 404, {}) else: for key in ('add', 'delete', 'replace'): if key in properties: # "The values of each property inside the replace, add or delete keys must be an array, # even if there is only a single value." if type(properties[key]) is dict: data['micropub'] = properties[key] data['actionkey'] = key current_app.logger.info('micropub UPDATE (%s) event for [%s]' % (key, slug)) try: kakuEvent('post', 'update', data) return ('Micropub UPDATE successful for %s' % location, 200, {'Location': location}) except: current_app.logger.exception('Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Unable to process Micropub request', 400, {}) else: return ('Micropub UPDATE failed for %s - currently only REPLACE is supported' % location, 406, {}) elif action in ('delete', 'undelete'): # https://www.w3.org/TR/2016/CR-micropub-20160816/#delete if 'url' in properties and properties['url'] is not None: url = properties['url'] data = { 'url': url } try: kakuEvent('post', action, data) return ('Micropub %s of %s successful' % (action, url), 200, {'Location': url}) except: current_app.logger.exception('Exception during micropub handling') return ('Unable to process Micropub request', 400, {}) else: return ('Micropub %s request requires a URL' % action, 400, {}) else: return ('Invalid Micropub CREATE request', 400, {}) else: return ('Unable to process Micropub %s' % data['event'], 400, {})
def mention(sourceURL, targetURL, vouchDomain=None): """Process the incoming Webmention from the sourceURL. To verify that the targetURL being referenced by the sourceURL is a valid reference we run findMentions() at it and scan the resulting href list. This does the following checks: 1. The sourceURL exists 2. The sourceURL indeed does reference our targetURL 3. The sourceURL is a valid Vouch (if configured to check) 4. The sourceURL is active and not deleted, if deleted then remove it from our list of mentions for targetURL """ current_app.logger.info('handling Webmention from %s' % sourceURL) try: result = False vouched = False mentions = ronkyuu.findMentions(sourceURL) current_app.logger.info('mentions %s' % mentions) if mentions['status'] == 410: data = { 'targetURL': targetURL, 'sourceURL': sourceURL } current_app.logger.info('mention removal event from [%s] of [%s]' % (targetURL, sourceURL)) kakuEvent('mention', 'deleted', data) else: for href in mentions['refs']: if href != sourceURL and href == targetURL: current_app.logger.info('post at %s was referenced by %s' % (targetURL, sourceURL)) if current_app.config['VOUCH_REQUIRED']: if vouchDomain is None: vouched = False result = False else: vouched = processVouch(sourceURL, targetURL, vouchDomain) result = vouched else: vouched = False result = True if result: utcdate = datetime.datetime.utcnow() tzLocal = pytz.timezone('America/New_York') timestamp = tzLocal.localize(utcdate, is_dst=None) mf2Data = Parser(doc=mentions['content']).to_dict() hcard = extractHCard(mf2Data) data = { 'sourceURL': sourceURL, 'targetURL': targetURL, 'vouchDomain': vouchDomain, 'vouched': vouched, 'postDate': timestamp.strftime('%Y-%m-%dT%H:%M:%S'), 'hcard': hcard, 'mf2data': mf2Data, } current_app.logger.info('mention created for [%s] from [%s]' % (targetURL, sourceURL)) current_app.logger.info(json.dumps(data, indent=2)) kakuEvent('mention', 'create', data) current_app.logger.info('mention() returning %s' % result) except ValueError: current_app.logger.exception('Exception raised during webmention processing') result = False return result, vouched