def process_article_submission(handler, article_type): property_hash = restful.get_sent_properties(handler.request.get, [ 'title', ('body', get_sanitizer_func(handler, trusted_source=True)), 'legacy_id', ('format', get_format), ('published', get_datetime), ('updated', get_datetime), ('tags', get_tags), ('html', get_html, 'body', 'format'), ('permalink', permalink_funcs[article_type], 'title', 'published') ]) if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [ get_tag_key(name) for name in property_hash['tags'] ] property_hash['format'] = 'html' # For now, convert all to HTML property_hash['article_type'] = article_type article = models.blog.Article(**property_hash) article.set_associated_data({ 'relevant_links': handler.request.get('relevant_links'), 'amazon_items': handler.request.get('amazon_items') }) process_embedded_code(article) article.put() # Ensure there is a year entity for this entry's year models.blog.Year.get_or_insert('Y%d' % (article.published.year, )) # Update tags for key in article.tag_keys: db.get(key).counter.increment() do_sitemap_ping() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache() else: handler.error(400)
def process_article_edit(handler, permalink): # For http PUT, the parameters are passed in URIencoded string in body body = handler.request.body params = cgi.parse_qs(body) for key, value in params.iteritems(): params[key] = value[0] property_hash = restful.get_sent_properties(params.get, [ 'title', ('body', get_sanitizer_func(handler, trusted_source=True)), ('format', get_format), ('updated', get_datetime), ('tags', get_tags), ('html', get_html, 'body', 'format') ]) if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [ get_tag_key(name) for name in property_hash['tags'] ] article = db.Query(models.blog.Article).filter('permalink =', permalink).get() before_tags = set(article.tag_keys) for key, value in property_hash.iteritems(): setattr(article, key, value) after_tags = set(article.tag_keys) for removed_tag in before_tags - after_tags: db.get(removed_tag).counter.decrement() for added_tag in after_tags - before_tags: db.get(added_tag).counter.increment() process_embedded_code(article) article.put() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache() else: handler.error(400)
def process_article_submission(handler, article_type): property_hash = restful.get_hash_from_request(handler.request, ['title', 'body', 'format', 'legacy_id', ('published', get_datetime), ('updated', get_datetime), ('tags', get_tags), ('html', get_html, 'body', 'format'), ('permalink', permalink_funcs[article_type], 'title', 'published')]) article = model.Article( permalink = property_hash['permalink'], article_type = article_type, title = property_hash['title'], body = property_hash['body'], html = property_hash['html'], published = property_hash['published'], updated = property_hash['updated'], format = 'html') # We are converting everything to HTML from Drupal # since it can mix formats within articles fill_optional_properties(article, property_hash) article.set_associated_data( {'relevant_links': handler.request.get('relevant_links'), 'amazon_items': handler.request.get('amazon_items')}) article.put() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache()
def process_article_edit(handler, permalink): # For http PUT, the parameters are passed in URIencoded string in body body = handler.request.body params = cgi.parse_qs(body) for key,value in params.iteritems(): params[key] = value[0] property_hash = restful.get_sent_properties(params.get, ['title', ('body', get_sanitizer_func(handler, trusted_source=True)), ('format', get_format), ('updated', get_datetime), ('tags', get_tags), ('html', get_html, 'body', 'format')]) if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [get_tag_key(name) for name in property_hash['tags']] article = db.Query(models.blog.Article).filter('permalink =', permalink).get() before_tags = set(article.tag_keys) for key,value in property_hash.iteritems(): setattr(article, key, value) after_tags = set(article.tag_keys) for removed_tag in before_tags - after_tags: db.get(removed_tag).counter.decrement() for added_tag in after_tags - before_tags: db.get(added_tag).counter.increment() process_embedded_code(article) article.put() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache() else: handler.error(400)
def process_article_submission(handler, article_type): property_hash = restful.get_sent_properties(handler.request.get, ['title', ('body', get_sanitizer_func(handler, trusted_source=True)), 'legacy_id', ('format', get_format), ('published', get_datetime), ('updated', get_datetime), ('tags', get_tags), ('html', get_html, 'body', 'format'), ('permalink', permalink_funcs[article_type], 'title', 'published')]) if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [get_tag_key(name) for name in property_hash['tags']] property_hash['format'] = 'html' # For now, convert all to HTML property_hash['article_type'] = article_type article = models.blog.Article(**property_hash) article.set_associated_data( {'relevant_links': handler.request.get('relevant_links'), 'amazon_items': handler.request.get('amazon_items')}) process_embedded_code(article) article.put() for key in article.tag_keys: db.get(key).counter.increment() do_sitemap_ping() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache() else: handler.error(400)
def delete(self, year, month, perm_stem): permalink = year + '/' + month + '/' + perm_stem logging.debug("Deleting blog entry %s", permalink) article = db.Query(model.Article). \ filter('permalink =', permalink).get() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete(self, comment_id): logging.info("Deleting comment %s", comment_id) comment = models.blog.Comment.get(db.Key(comment_id)) article = comment.article article.num_comments -= 1 article.put() comment.delete() view.invalidate_cache(article.permalink) restful.send_successful_response(self, "/")
def delete_entity(query): targets = query.fetch(limit=1) if len(targets) > 0: permalink = targets[0].permalink logging.debug('Deleting %s %s', model_class, permalink) targets[0].delete() self.response.out.write('Deleted ' + permalink) view.invalidate_cache() else: self.error(404)
def delete(self, category, year, month, perm_stem): permalink = '/'.join((category, year, month, perm_stem)) logging.debug("Deleting %s entry %s" % (category, permalink)) article = db.Query(models.blog.Article). \ filter('permalink =', permalink).get() for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete(self, year, month, perm_stem): permalink = 'blog/' + year + '/' + month + '/' + day + '/' + perm_stem logging.debug("Deleting blog entry %s", permalink) article = db.Query(models.blog.Article). \ filter('permalink =', permalink).get() for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete(self, year, month, perm_stem): permalink = year + '/' + month + '/' + perm_stem logging.debug("Deleting blog entry %s", permalink) article = db.Query(models.blog.Article). \ filter('permalink =', permalink).get() for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete(self, path): logging.debug("Deleting article %s", path) if path=='article': # hack to pick out the 'top' article for bulk delete return delete_entity(self, models.blog.Article.all()) article = db.Query(models.blog.Article).filter('permalink =', path).get() if not article: return self.error(404) for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete_entity(handler, query): target = query.get() if not target: return handler.response.set_status(204, 'No more entities') if hasattr(target, 'title'): title = target.title elif hasattr(target, 'name'): title = target.name else: title = '' logging.debug('Deleting %s', title) target.delete() handler.response.out.write('Deleted %s' % title) view.invalidate_cache() restful.send_successful_response(handler, "/")
def delete_entity(handler, query): target = query.get() if not target: return handler.response.set_status(204, 'No more entities') if hasattr(target, 'title'): title = target.title elif hasattr(target, 'name'): title = target.name else: title = '' logging.debug('Deleting %s', title) target.delete() handler.response.out.write('Deleted %s' % title) view.invalidate_cache() restful.send_successful_response(handler, "/")
def delete(self, path): """ By using DELETE on /Article, /Comment, /Tag, you can delete the first entity of the desired kind. This is useful for writing utilities like clear_datastore.py. """ # TODO: Add DELETE for articles off root like blog entry DELETE. model_class = path.lower() aio.debug("blog.ArticleHandler#delete on %s", path) def delete_entity(query): targets = query.fetch(limit = 1) if len(targets) > 0: if hasattr(targets[0], 'title'): title = targets[0].title elif hasattr(targets[0], 'name'): title = targets[0].name else: title = '' aio.debug('Deleting %s %s', model_class, title) targets[0].delete() self.response.out.write('Deleted ' + model_class + ' ' + title) view.invalidate_cache(path) else: self.response.set_status(204, 'No more ' + model_class + ' entities') if model_class == 'article': query = models.blog.Article.all() delete_entity(query) elif model_class == 'comment': query = models.blog.Comment.all() delete_entity(query) elif model_class == 'tag': query = models.blog.Tag.all() delete_entity(query) else: article = db.Query(models.blog.Article). \ filter('permalink =', path).get() for key in article.tag_keys: tag = db.get(key) logging.debug("Decrementing tag %s with initial value %d", tag.name, tag.counter.count) tag.counter.decrement() if tag.counter.count == 0: logging.debug("Tag %s has count 0, removing tag", tag.name) tag.delete_counter() tag.delete() for comment in article.comments: comment.delete() article.delete() view.invalidate_cache(path) restful.send_successful_response(self, "/")
def put(self, comment_id): logging.debug("CommentHandler#put for comment %s", comment_id) # For HTTP PUT, the parameters are passed in URIencoded string in body sanitize_comment = get_sanitizer_func(self, allow_attributes = ['href', 'src'], blacklist_tags = ['img', 'script']) body = self.request.body params = cgi.parse_qs(body) for key, value in params.iteritems(): params[key] = value[0] if not isinstance(params[key], unicode): params[key] = params[key].decode(config.APP['charset']) tmp_hash = restful.get_sent_properties(self.request.get, [('commentEmail', cgi.escape), ('commentHomepage', cgi.escape), ('commentTitle', cgi.escape), ('commentName', cgi.escape), ('commentBody', sanitize_comment)]) property_hash = {} props = (("commentEmail", "email"), ("commentHomepage", "homepage"), ("commentTitle", "title"), ("commentBody", "body"), ('commentName', 'name')) for pair in props: if pair[0] in tmp_hash: logging.debug("Copying '%s' from received properties to '%s' in property hash (value: %s)", pair[0], pair[1], str(tmp_hash[pair[0]])) property_hash[pair[1]] = tmp_hash[pair[0]] if property_hash: comment = models.blog.Comment.get(db.Key(comment_id)) for key, value in property_hash.iteritems(): setattr(comment, key, value) comment.put() # Render just this comment and send it to client view_path = view.find_file(view.templates, "gablog/blog/comment.html") allow_comments = comment.article.allow_comments if allow_comments is None: age = (datetime.datetime.now() - comment.article.published).days allow_comments = (age <= config.BLOG['comment_window']) # response = template.render(os.path.join(config.APP['template_dir'], view_path), response = render_to_string(os.path.join(config.APP['template_dir'], view_path), { 'comment': comment, "use_gravatars": config.BLOG["use_gravatars"], "allow_comments": allow_comments, "user_is_admin": users.is_current_user_admin()}, debug = config.DEBUG) self.response.out.write(response) view.invalidate_cache(comment.article.permalink) else: self.error(400)
def delete(self, path): logging.debug("Deleting article %s", path) if path == 'article': # hack to pick out the 'top' article for bulk delete return delete_entity(self, models.blog.Article.all()) article = db.Query(models.blog.Article).filter('permalink =', path).get() if not article: return self.error(404) for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete_entity(query): targets = query.fetch(limit=1) if len(targets) > 0: if hasattr(targets[0], 'title'): title = targets[0].title elif hasattr(targets[0], 'name'): title = targets[0].name else: title = '' logging.debug('Deleting %s %s', model_class, title) targets[0].delete() self.response.out.write('Deleted ' + model_class + ' ' + title) view.invalidate_cache() else: self.response.set_status(204, 'No more ' + model_class + ' entities')
def delete(self, comment_id): if not comment_id: return delete_entity(self, models.blog.Comment.all()) logging.debug("Deleting comment %s", comment_id) comment = models.blog.Comment.get(db.Key(comment_id)) if not comment: return self.error(404) article = comment.article comment.delete() # TODO replace with counter? article.num_comments -= 1 # decrement comment count article.put() view.invalidate_cache(comment.article.permalink) restful.send_successful_response(self, "/")
def delete(self,comment_id): if not comment_id: return delete_entity( self, models.blog.Comment.all() ) logging.debug("Deleting comment %s", comment_id) comment = models.blog.Comment.get(db.Key(comment_id)) if not comment: return self.error(404) article = comment.article comment.delete() # TODO replace with counter? article.num_comments -=1 # decrement comment count article.put() view.invalidate_cache(comment.article.permalink) restful.send_successful_response(self, "/")
def delete_entity(query): targets = query.fetch(limit=1) if len(targets) > 0: if hasattr(targets[0], 'title'): title = targets[0].title elif hasattr(targets[0], 'name'): title = targets[0].name else: title = '' logging.debug('Deleting %s %s', model_class, title) targets[0].delete() self.response.out.write('Deleted ' + model_class + ' ' + title) view.invalidate_cache() else: self.response.set_status( 204, 'No more ' + model_class + ' entities')
def process_article_edit(handler, permalink): # For http PUT, the parameters are passed in URIencoded string in body body = handler.request.body params = cgi.parse_qs(body) logging.debug(params) article = db.Query(model.Article).filter('permalink =', permalink).get() if 'title' in params: article.title = params['title'][0] if 'tags' in params: article.tags = get_tags(params['tags'][0]) article.body = params['body'][0] article.html = params['body'][0] article.updated = get_datetime() article.put() restful.send_successful_response(handler, '/' + article.permalink) view.invalidate_cache()
def delete(self, path): """ By using DELETE on /Article, /Comment, /Tag, you can delete the first entity of the desired kind. This is useful for writing utilities like clear_datastore.py. """ # TODO: Add DELETE for articles off root like blog entry DELETE. model_class = path.lower() logging.debug("ArticleHandler#delete on %s", path) def delete_entity(query): targets = query.fetch(limit=1) if len(targets) > 0: if hasattr(targets[0], 'title'): title = targets[0].title elif hasattr(targets[0], 'name'): title = targets[0].name else: title = '' logging.debug('Deleting %s %s', model_class, title) targets[0].delete() self.response.out.write('Deleted ' + model_class + ' ' + title) view.invalidate_cache() else: self.response.set_status( 204, 'No more ' + model_class + ' entities') if model_class == 'article': query = models.blog.Article.all() delete_entity(query) elif model_class == 'comment': query = models.blog.Comment.all() delete_entity(query) elif model_class == 'tag': query = models.blog.Tag.all() delete_entity(query) else: article = db.Query(models.blog.Article). \ filter('permalink =', path).get() for key in article.tag_keys: db.get(key).counter.decrement() article.delete() view.invalidate_cache() restful.send_successful_response(self, "/")
def delete(self, year, month, permalink): perm_stem = [t for t in permalink.split("/") if len(t)][-1] permalink = year + '/' + month + '/' + perm_stem aio.debug("BlogEntryHandler. delete Deleting blog entry %s", permalink) article = db.Query(models.blog.Article).filter('permalink =', permalink).get() for key in article.tag_keys: tag = db.get(key) aio.debug("BlogEntryHandler.delete: Decrementing tag '%s' with current count %d", tag.name, tag.counter.count) tag.counter.decrement() if tag.counter.count == 0: aio.debug("Tag '%s' has count 0, removing tag", tag.name) tag.delete_counter() tag.delete() article.delete() view.invalidate_cache(perm_stem) restful.send_successful_response(self, "/")
def process_comment_submission(handler, article): if not article: handler.error(404) return # Get and store some pieces of information from parent article. # TODO: See if this overhead can be avoided if not article.num_comments: article.num_comments = 1 else: article.num_comments += 1 article_key = article.put() property_hash = restful.get_hash_from_request(handler.request, ['name', 'email', 'title', 'body', 'thread', ('published', get_datetime)]) # Compute a comment key by hashing name, email, and body. # If these aren't different, don't bother adding comment. comment_key = str( hash((property_hash['name'], property_hash['email'], property_hash['body']))) comment = model.Comment( permalink = comment_key, body = property_hash['body'], article = article_key, thread = property_hash['thread']) fill_optional_properties(comment, property_hash) comment.put() restful.send_successful_response(handler, '/' + comment.permalink) view.invalidate_cache()
def process_comment_submission(handler, article): sanitize_comment = get_sanitizer_func(handler, allow_attributes=['href', 'src'], blacklist_tags=['img']) property_hash = restful.get_sent_properties(handler.request.get, ['name', 'email', 'homepage', 'title', ('body', sanitize_comment), 'key', 'thread', # If it's given, use it. Else generate it. 'captcha', ('published', get_datetime)]) # If we aren't administrator, abort if bad captcha if not users.is_current_user_admin(): if property_hash.get('captcha', None) != get_captcha(article.key()): logging.info("Received captcha (%s) != %s", property_hash.get('captcha', None), get_captcha(article.key())) handler.error(401) # Unauthorized return if 'key' not in property_hash and 'thread' not in property_hash: handler.error(401) return # Generate a thread string. if 'thread' not in property_hash: matchobj = re.match(r'[^#]+#comment-(?P<key>\w+)', property_hash['key']) if matchobj: logging.debug("Comment has parent: %s", matchobj.group('key')) comment_key = matchobj.group('key') # TODO -- Think about GQL injection security issue since # it can be submitted by public parent = models.blog.Comment.get(db.Key(comment_key)) thread_string = parent.next_child_thread_string() else: logging.debug("Comment is off main article") comment_key = None thread_string = article.next_comment_thread_string() if not thread_string: handler.error(400) return property_hash['thread'] = thread_string del property_hash['key'] # Get and store some pieces of information from parent article. # TODO: See if this overhead can be avoided if not article.num_comments: article.num_comments = 1 else: article.num_comments += 1 property_hash['article'] = article.put() try: comment = models.blog.Comment(**property_hash) comment.put() except: logging.debug("Bad comment: %s", property_hash) handler.error(400) return # Notify the author of a new comment (from matteocrippa.it) if config.BLOG['send_comment_notification']: recipient = "%s <%s>" % (config.BLOG['author'], config.BLOG['email'],) body = ("A new comment has just been posted on %s/%s by %s." % (config.BLOG['root_url'], article.permalink, comment.name)) mail.send_mail(sender=config.BLOG['email'], to=recipient, subject="New comment by %s" % (comment.name,), body=body) # Render just this comment and send it to client view_path = view.find_file(view.templates, "bloog/blog/comment.html") response = template.render( os.path.join("views", view_path), { 'comment': comment, "use_gravatars": config.BLOG["use_gravatars"] }, debug=config.DEBUG) handler.response.out.write(response) view.invalidate_cache()
def process_comment_submission(handler, parent=None): sanitize_comment = get_sanitizer_func(handler, allow_attributes=['href', 'src'], blacklist_tags=['img', 'script']) property_hash = restful.get_sent_properties( handler.request.get, [('name', cgi.escape), ('email', cgi.escape), ('homepage', cgi.escape), ('title', cgi.escape), ('body', sanitize_comment), ('article_id', cgi.escape), 'recaptcha_challenge_field', 'recaptcha_response_field', ('published', get_datetime)]) # If we aren't administrator, abort if bad captcha if not users.is_current_user_admin(): cap_challenge = property_hash.get('recaptcha_challenge_field') cap_response = property_hash.get('recaptcha_response_field') cap_validation = captcha.RecaptchaResponse(False) if cap_challenge and cap_response: cap_validation = captcha.submit(cap_challenge, cap_response, config.BLOG['recap_private_key'], handler.request.remote_addr) if not cap_validation.is_valid: logging.info("Invalid captcha: %s", cap_validation.error_code) handler.response.set_status(401, 'Invalid Captcha') # Unauthorized return if 'article_id' not in property_hash: return handler.error(400) article = db.Query(models.blog.Article).filter( 'permalink =', property_hash['article_id']).get() # Generate a thread string. if parent: logging.debug("Comment has parent: %s", parent.key()) thread_string = parent.next_child_thread_string() else: logging.debug("Comment is off main article") thread_string = article.next_comment_thread_string() property_hash['thread'] = thread_string # Get and store some pieces of information from parent article. # TODO: See if this overhead can be avoided if not article.num_comments: article.num_comments = 1 else: article.num_comments += 1 property_hash['article'] = article.put() try: comment = models.blog.Comment(**property_hash) comment.put() except: logging.debug("Bad comment: %s", property_hash) return handler.error(400) # Notify the author of a new comment (from matteocrippa.it) if config.BLOG[ 'send_comment_notification'] and not users.is_current_user_admin(): recipient = "%s <%s>" % (config.BLOG['author'], config.BLOG['email']) article_link = config.BLOG['root_url'] + "/" + article.permalink comment_link = '%s#comment-%s' % (article_link, comment.key()) body = ('''A new comment has just been posted on %s by %s:\n\n"%s" \n\nReply to the comment here: %s''' % (article_link, comment.name, comment.body, comment_link)) mail.send_mail(sender=config.BLOG['email'], to=recipient, subject="New comment by %s" % (comment.name), body=body) # Render just this comment and send it to client view_path = view.find_file(view.templates, "bloog/blog/comment.html") response = template.render(os.path.join("views", view_path), { 'comment': comment, "use_gravatars": config.BLOG["use_gravatars"] }, debug=config.DEBUG) handler.response.out.write(response) view.invalidate_cache(comment.article.permalink)
def process_comment_submission(handler, parent=None): sanitize_comment = get_sanitizer_func(handler, allow_attributes=['href', 'src'], blacklist_tags=['img', 'script']) property_hash = restful.get_sent_properties(handler.request.get, [('name', cgi.escape), ('email', cgi.escape), ('homepage', cgi.escape), ('title', cgi.escape), ('body', sanitize_comment), ('article_id', cgi.escape), 'recaptcha_challenge_field', 'recaptcha_response_field', ('published', get_datetime)]) # If we aren't administrator, abort if bad captcha if not users.is_current_user_admin(): cap_challenge = property_hash.get('recaptcha_challenge_field') cap_response = property_hash.get('recaptcha_response_field') cap_validation = captcha.RecaptchaResponse(False) if cap_challenge and cap_response: cap_validation = captcha.submit( cap_challenge, cap_response, config.BLOG['recap_private_key'], handler.request.remote_addr ) if not cap_validation.is_valid: logging.info( "Invalid captcha: %s", cap_validation.error_code ) handler.response.set_status(401, 'Invalid Captcha') # Unauthorized return if 'article_id' not in property_hash: return handler.error(400) article = db.Query(models.blog.Article).filter( 'permalink =', property_hash['article_id'] ).get() # Generate a thread string. if parent: logging.debug("Comment has parent: %s", parent.key()) thread_string = parent.next_child_thread_string() else: logging.debug("Comment is off main article") thread_string = article.next_comment_thread_string() property_hash['thread'] = thread_string # Get and store some pieces of information from parent article. # TODO: See if this overhead can be avoided if not article.num_comments: article.num_comments = 1 else: article.num_comments += 1 property_hash['article'] = article.put() try: comment = models.blog.Comment(**property_hash) comment.put() except: logging.debug("Bad comment: %s", property_hash) return handler.error(400) # Notify the author of a new comment (from matteocrippa.it) if config.BLOG['send_comment_notification'] and not users.is_current_user_admin(): recipient = "%s <%s>" % (config.BLOG['author'], config.BLOG['email']) article_link = config.BLOG['root_url'] + "/" + article.permalink comment_link = '%s#comment-%s' % (article_link, comment.key()) body = ('''A new comment has just been posted on %s by %s:\n\n"%s" \n\nReply to the comment here: %s''' % (article_link, comment.name, comment.body, comment_link)) mail.send_mail(sender=config.BLOG['email'], to=recipient, subject="New comment by %s" % (comment.name), body=body) # Render just this comment and send it to client view_path = view.find_file(view.templates, "bloog/blog/comment.html") response = template.render( os.path.join("views", view_path), { 'comment': comment, "use_gravatars": config.BLOG["use_gravatars"] }, debug=config.DEBUG) handler.response.out.write(response) view.invalidate_cache(comment.article.permalink)
def process_comment_submission(handler, article): sanitize_comment = get_sanitizer_func(handler, allow_attributes=['href', 'src'], blacklist_tags=['img', 'script']) property_hash = restful.get_sent_properties( handler.request.get, [ ('name', cgi.escape), ('email', cgi.escape), ('homepage', cgi.escape), ('title', cgi.escape), ('body', sanitize_comment), ('key', cgi.escape), 'thread', # If it's given, use it. Else generate it. 'captcha', ('published', get_datetime) ]) # If we aren't administrator, abort if bad captcha if not users.is_current_user_admin(): if property_hash.get('captcha', None) != get_captcha(article.key()): logging.info("Received captcha (%s) != %s", property_hash.get('captcha', None), get_captcha(article.key())) handler.error(401) # Unauthorized return if 'key' not in property_hash and 'thread' not in property_hash: handler.error(401) return # Generate a thread string. if 'thread' not in property_hash: matchobj = re.match(r'[^#]+#comment-(?P<key>\w+)', property_hash['key']) if matchobj: logging.debug("Comment has parent: %s", matchobj.group('key')) comment_key = matchobj.group('key') # TODO -- Think about GQL injection security issue since # it can be submitted by public parent = models.blog.Comment.get(db.Key(comment_key)) thread_string = parent.next_child_thread_string() else: logging.debug("Comment is off main article") comment_key = None thread_string = article.next_comment_thread_string() if not thread_string: handler.error(400) return property_hash['thread'] = thread_string del property_hash['key'] # Get and store some pieces of information from parent article. # TODO: See if this overhead can be avoided if not article.num_comments: article.num_comments = 1 else: article.num_comments += 1 property_hash['article'] = article.put() try: comment = models.blog.Comment(**property_hash) comment.put() except: logging.debug("Bad comment: %s", property_hash) handler.error(400) return # Notify the author of a new comment (from matteocrippa.it) if config.BLOG['send_comment_notification']: recipient = "%s <%s>" % ( config.BLOG['author'], config.BLOG['email'], ) body = ("A new comment has just been posted on %s/%s by %s." % (config.BLOG['root_url'], article.permalink, comment.name)) mail.send_mail(sender=config.BLOG['email'], to=recipient, subject="New comment by %s" % (comment.name, ), body=body) # Render just this comment and send it to client view_path = view.find_file(view.templates, "bloog/blog/comment.html") response = template.render(os.path.join("views", view_path), { 'comment': comment, "use_gravatars": config.BLOG["use_gravatars"] }, debug=config.DEBUG) handler.response.out.write(response) view.invalidate_cache()
def process_article_submission(handler, article_type): """ takes care of permalink """ aio.debug("blog.process_article_submission article_type: %s", article_type) tmp_hash = restful.get_sent_properties(handler.request.get, [ ('postTitle', get_sanitizer_func(handler, trusted_source = True)), ('postBody', get_sanitizer_func(handler, trusted_source = True)), ('postFormat', get_format), ('postType', get_type), ('postUpdated', get_datetime), ('postTags', get_tags), ('html', get_html, 'postBody', 'postFormat'), ('permalink', permalink_funcs[article_type], 'postTitle', 'postPublished'), 'postExcerpt', 'postThumb' ]) property_hash = {} props = ( ("key", "key"), ("postTitle", "title"), ("postBody", "body"), ("postExcerpt", "excerpt"), ("postThumb", "thumb"), ("postFormat", "format"), ("postType", "article_type"), ("postPublished", "published"), ("postUpdated", "updated"), ("article_id", "article_id"), ("permalink", "permalink"), ("html", "html"), ("postTags", "tags"), ) for pair in props: if pair[0] in tmp_hash: property_hash[pair[1]] = tmp_hash[pair[0]] if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [get_tag_key(name) for name in property_hash['tags']] # property_hash['format'] = 'html' # For now, convert all to HTML # property_hash['article_type'] = article_type article = models.blog.Article(**property_hash) article.set_associated_data({'relevant_links': handler.request.get('relevant_links'), }) process_embedded_code(article) article.put() time.sleep(1) # Ensure there is a year entity for this entry's year if article.published : models.blog.Year.get_or_insert('Y%d' % (article.published.year, )) # Update tags for key in article.tag_keys: db.get(key).counter.increment() aio.debug("blog.process_article_submission perm: %s, key: %s", article.permalink, article.key()) # restful.send_successful_response(handler, '/' + article.permalink) restful.send_successful_response(handler, '/post/edit/' + str(article.key())) view.invalidate_cache(article.permalink) else: aio.debug("blog.process_article_submission no property_hash") handler.error(400)
def process_article_edit(handler, postlink): # For HTTP PUT, the parameters are passed in URIencoded string in body body = handler.request.body params = cgi.parse_qs(body) for key, value in params.iteritems(): params[key] = value[0] if not isinstance(params[key], unicode): params[key] = params[key].decode(config.APP['charset']) aio.debug("blog.process_article_edit: params.keys: %s", params.keys()) # article_type = restful.get_sent_properties(params.get, [('postType', get_type)])['postType'] article_type = params['postType'] aio.debug("blog.process_article_edit article with postlink: %s, type: %s/%s", postlink, article_type, params['postFormat']) tmp_hash = restful.get_sent_properties(params.get, [ ('postTitle', cgi.escape), ('postBody', get_sanitizer_func(handler, trusted_source = True)), ('postFormat', get_format), ## markdown, html, text ('postType', get_type), ## draft, post, article ('postTags', get_tags), ('html', get_html, 'postBody', 'postFormat'), ('postPublished', get_datetime, 'postPublished'), ('permalink', permalink_funcs[article_type], 'postTitle', 'postPublished'), 'postThumb', # 'postPublished', ]) # aio.debug("blog.process_article_edit tmp_hash: %s", tmp_hash) property_hash = {} props = ( ("postTitle", "title"), ("postBody", "body"), ("postFormat", "format"), ("postPublished", "published"), ("postThumb", "thumb"), ("legacy_id", "legacy_id"), ("article_id", "article_id"), ("postType", "article_type"), ("postTags", "tags"), ("html", "html"), ("postPerma", "permalink") ) for pair in props : # aio.debug("PAIR: %s", pair) if pair is not None: if pair[0] in tmp_hash : # logging.info("COPY PAIR %s", pair) property_hash[pair[1]] = tmp_hash[pair[0]] else : pass # aio.debug("IGNORE %s from sent properties to %s in property hash", pair[0], pair[1]) else : aio.debug("ERROR '%s' with pair", pair) if property_hash: if 'tags' in property_hash: property_hash['tag_keys'] = [get_tag_key(name) for name in property_hash['tags'] if name != ""] aio.debug("blog.process_article_edit search article by postlink: %s", postlink) ## adjust dates property_hash['updated'] = datetime.datetime.utcnow() if property_hash['article_type'] == 'draft' : property_hash['published'] = None else : # property_hash['published'] = get_datetime(property_hash['published']) property_hash['published'] = property_hash['published'] aio.debug("blog.process_article_edit pub: %s: upd: %s", property_hash['published'], property_hash['updated']) article = db.Query(models.blog.Article).filter('permalink =', postlink).get() before_tags = set(article.tag_keys) for key, value in property_hash.iteritems(): # aio.debug("blog.process_article_edit: SAVE: " + key + " > " + aio.asciify(value)[:10]) ## utf errors setattr(article, key, value) after_tags = set(article.tag_keys) for removed_tag in before_tags - after_tags: tag = db.get(removed_tag) logging.debug("Decrementing tag '%s' with initial value %d", tag.name, tag.counter.count) tag.counter.decrement() if tag.counter.count == 0: logging.debug("Tag %s has count 0, removing tag", tag.name) tag.delete_counter() tag.delete() for added_tag in after_tags - before_tags: db.get(added_tag).counter.increment() process_embedded_code(article) article.put() # restful.send_successful_response(handler, '/' + article.permalink) restful.send_successful_response(handler, '/post/edit/' + str(article.key())) view.invalidate_cache(article.permalink) else: handler.error(400)