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 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 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 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 post(self, comment_id): sanitize_comment = get_sanitizer_func(self, allow_attributes = ['href'], blacklist_tags = ['img', 'script', 'iframe'] ) tmp_hash = restful.get_sent_properties(self.request.get, [('key', cgi.escape), ('commentEmail', cgi.escape), ('commentHomepage', cgi.escape), ('commentTitle', cgi.escape), ('commentName', cgi.escape), ('commentBody', sanitize_comment), ('article_id', cgi.escape), 'captcha', ('published', get_datetime)]) property_hash = {} props = (("key", "key"), ("commentEmail", "email"), ("commentHomepage", "homepage"), ("commentTitle", "title"), ("commentBody", "body"), ("published", "published"), ("article_id", "article_id"), ("captcha", "captcha"), ('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 "article_id" not in property_hash: logging.error("No article_id found: %s", str(property_hash)) self.error(400) return article = db.Query(models.blog.Article).filter('permalink =', property_hash["article_id"]).get() # 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())) self.error(403) self.response.out.write("Invalid CAPTCHA"); return # Generate a thread string. if article: thread_string = article.next_comment_thread_string() else: logging.error("No article with ID %s found!", property_hash["article_id"]) self.error(400) return logging.debug("New thread string: %s", 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 Exception, e: logging.error(e) logging.error("Bad comment: %s", property_hash) handler.error(400) return
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)
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_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)