def history(name): """Page history.""" name = Wiki.url_to_name(name) # Look up the page. page = Wiki.get_page(name) if not page: flash("Wiki page not found.") return redirect(url_for(".index")) authors = dict() history = list() for rev in page["revisions"]: uid = rev["author"] if not uid in authors: authors[uid] = User.get_user(uid=uid) history.append( dict( id=rev["id"], author=authors[uid], note=rev["note"], pretty_time=pretty_time(Config.wiki.time_format, rev["time"]), )) g.info["link"] = Wiki.name_to_url(name) g.info["title"] = name g.info["history"] = history return template("wiki/history.html")
def before_request(): """Called before all requests. Initialize global template variables.""" # Default template vars. g.info = rophako.utils.default_vars() # Default session vars. if not "login" in session: session.update(g.info["session"]) # CSRF protection. if request.method == "POST": token = session.pop("_csrf", None) if not token or str(token) != str(request.form.get("token")): abort(403) # Refresh their login status from the DB. if session["login"]: import rophako.model.user as User if not User.exists(uid=session["uid"]): # Weird! Log them out. from rophako.modules.account import logout logout() return db = User.get_user(uid=session["uid"]) session["username"] = db["username"] session["name"] = db["name"] session["role"] = db["role"] # Copy session params into g.info. The only people who should touch the # session are the login/out pages. for key in session: g.info["session"][key] = session[key]
def history(name): """Page history.""" name = Wiki.url_to_name(name) # Look up the page. page = Wiki.get_page(name) if not page: flash("Wiki page not found.") return redirect(url_for(".index")) authors = dict() history = list() for rev in page["revisions"]: uid = rev["author"] if not uid in authors: authors[uid] = User.get_user(uid=uid) history.append( dict( id=rev["id"], author=authors[uid], note=rev["note"], pretty_time=pretty_time(Config.wiki.time_format, rev["time"]), ) ) g.info["link"] = Wiki.name_to_url(name) g.info["title"] = name g.info["history"] = history return template("wiki/history.html")
def login(): """Log into an account.""" if request.method == "POST": username = request.form.get("username", "") password = request.form.get("password", "") # Lowercase the username. username = username.lower() if User.check_auth(username, password): # OK! db = User.get_user(username=username) session["login"] = True session["username"] = username session["uid"] = db["uid"] session["name"] = db["name"] session["role"] = db["role"] # Redirect them to a local page? url = request.form.get("url", "") if url.startswith("/"): return redirect(url) return redirect(url_for("index")) else: flash("Authentication failed.") return redirect(url_for(".login")) return template("account/login.html")
def impersonate(uid): """Impersonate a user.""" # Check that they exist. if not User.exists(uid=uid): flash("That user ID wasn't found.") return redirect(url_for(".users")) db = User.get_user(uid=uid) if db["role"] == "deleted": flash("That user was deleted!") return redirect(url_for(".users")) # Log them in! orig_uid = session["uid"] session.update( login=True, uid=uid, username=db["username"], name=db["name"], role=db["role"], impersonator=orig_uid, ) flash("Now logged in as {}".format(db["name"])) return redirect(url_for("index"))
def login(): """Log into an account.""" if request.method == "POST": username = request.form.get("username", "") password = request.form.get("password", "") # Lowercase the username. username = username.lower() if User.check_auth(username, password): # OK! db = User.get_user(username=username) session["login"] = True session["username"] = username session["uid"] = db["uid"] session["name"] = db["name"] session["role"] = db["role"] # Redirect them to a local page? url = request.form.get("url", "") if url.startswith("/"): return redirect(url) return redirect(url_for("index")) else: flash("Authentication failed.") return redirect(url_for(".login")) return template("account/login.html")
def edit_user(uid): uid = int(uid) user = User.get_user(uid=uid) # Submitting? if request.method == "POST": action = request.form.get("action", "") username = request.form.get("username", "") name = request.form.get("name", "") pw1 = request.form.get("password1", "") pw2 = request.form.get("password2", "") role = request.form.get("role", "") username = username.lower() if action == "save": # Validate... errors = None # Don't allow them to change the username to one that exists. if username != user["username"]: if User.exists(username=username): flash("That username already exists.") return redirect(url_for(".edit_user", uid=uid)) # Password provided? if len(pw1) > 0: errors = validate_create_form(username, pw1, pw2) elif username != user["username"]: # Just validate the username, then. errors = validate_create_form(username, skip_passwd=True) if errors: for error in errors: flash(error) return redirect(url_for(".edit_user", uid=uid)) # Update the user. user["username"] = username user["name"] = name or username user["role"] = role if len(pw1) > 0: user["password"] = User.hash_password(pw1) User.update_user(uid, user) flash("User account updated!") return redirect(url_for(".users")) elif action == "delete": # Don't let them delete themself! if uid == g.info["session"]["uid"]: flash("You shouldn't delete yourself!") return redirect(url_for(".edit_user", uid=uid)) User.delete_user(uid) flash("User deleted!") return redirect(url_for(".users")) return template("admin/edit_user.html", info=user)
def entry(fid): """Endpoint to view a specific blog entry.""" # Resolve the friendly ID to a real ID. post_id = Blog.resolve_id(fid) if not post_id: flash("That blog post wasn't found.") return redirect(url_for(".index")) # Look up the post. post = Blog.get_entry(post_id) post["post_id"] = post_id # Body has a snipped section? if "<snip>" in post["body"]: post["body"] = re.sub(r'\s*<snip>\s*', '\n\n', post["body"]) # Render the body. if post["format"] == "markdown": post["rendered_body"] = render_markdown(post["body"]) else: post["rendered_body"] = post["body"] # Render emoticons. if post["emoticons"]: post["rendered_body"] = Emoticons.render(post["rendered_body"]) # Get the author's information. post["profile"] = User.get_user(uid=post["author"]) post["photo"] = User.get_picture(uid=post["author"]) post["photo_url"] = Config.photo.root_public # Pretty-print the time. post["pretty_time"] = pretty_time(Config.blog.time_format, post["time"]) # Count the comments for this post post["comment_count"] = Comment.count_comments("blog-{}".format(post_id)) # Inject information about this post's siblings. index = Blog.get_index() siblings = [None, None] # previous, next sorted_ids = list(map(lambda y: int(y), sorted(index.keys(), key=lambda x: index[x]["time"], reverse=True))) for i in range(0, len(sorted_ids)): if sorted_ids[i] == post_id: # Found us! if i > 0: # We have an older post. siblings[0] = index[ str(sorted_ids[i-1]) ] if i < len(sorted_ids) - 1: # We have a newer post. siblings[1] = index[ str(sorted_ids[i+1]) ] post["siblings"] = siblings g.info["post"] = post return template("blog/entry.html")
def unimpersonate(): """Unimpersonate a user.""" # Must be impersonating, first! if not "impersonator" in session: flash("Stop messing around.") return redirect(url_for("index")) uid = session.pop("impersonator") db = User.get_user(uid=uid) session.update(login=True, uid=uid, username=db["username"], name=db["name"], role=db["role"]) flash("No longer impersonating.") return redirect(url_for("index"))
def view_page(name): """Show a specific wiki page.""" link = name name = Wiki.url_to_name(name) g.info["link"] = link g.info["title"] = name # Look up the page. page = Wiki.get_page(name) if not page: # Page doesn't exist... yet! g.info["title"] = Wiki.url_to_name(name) return template("wiki/missing.html"), 404 # Which revision to show? version = request.args.get("revision", None) if version: # Find this one. rev = None for item in page["revisions"]: if item["id"] == version: rev = item break if rev is None: flash("That revision was not found for this page.") rev = page["revisions"][0] else: # Show the latest one. rev = page["revisions"][0] # Getting the plain text source? if request.args.get("source", None): g.info["markdown"] = render_markdown( "\n".join(["# Source: {}".format(name), "", "```markdown", rev["body"], "```"]) ) return template("markdown.inc.html") # Render it! g.info["rendered_body"] = Wiki.render_page(rev["body"]) g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"]) g.info["pretty_time"] = pretty_time(Config.wiki.time_format, rev["time"]) # Author info g.info["author"] = User.get_user(uid=rev["author"]) return template("wiki/page.html")
def view_page(name): """Show a specific wiki page.""" link = name name = Wiki.url_to_name(name) g.info["link"] = link g.info["title"] = name # Look up the page. page = Wiki.get_page(name) if not page: # Page doesn't exist... yet! g.info["title"] = Wiki.url_to_name(name) return template("wiki/missing.html"), 404 # Which revision to show? version = request.args.get("revision", None) if version: # Find this one. rev = None for item in page["revisions"]: if item["id"] == version: rev = item break if rev is None: flash("That revision was not found for this page.") rev = page["revisions"][0] else: # Show the latest one. rev = page["revisions"][0] # Getting the plain text source? if request.args.get("source", None): g.info["markdown"] = render_markdown("\n".join([ "# Source: {}".format(name), "", "```markdown", rev["body"], "```" ])) return template("markdown.inc.html") # Render it! g.info["rendered_body"] = Wiki.render_page(rev["body"]) g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"]) g.info["pretty_time"] = pretty_time(Config.wiki.time_format, rev["time"]) # Author info g.info["author"] = User.get_user(uid=rev["author"]) return template("wiki/page.html")
def partial_index(thread, subject, header=True, addable=True): """Partial template for including the index view of a comment thread. Parameters: thread (str): the unique name for the comment thread. subject (str): subject name for the comment thread. header (bool): show the 'Comments' H1 header. addable (bool): can new comments be added to the thread? """ # Get all the comments on this thread. comments = Comment.get_comments(thread) # Sort the comments by most recent on bottom. sorted_cids = [ x for x in sorted(comments, key=lambda y: comments[y]["time"]) ] sorted_comments = [] for cid in sorted_cids: comment = comments[cid] comment["id"] = cid # Was the commenter logged in? if comment["uid"] > 0: user = User.get_user(uid=comment["uid"]) avatar = User.get_picture(uid=comment["uid"]) comment["name"] = user["name"] comment["username"] = user["username"] comment["image"] = avatar # Add the pretty time. comment["pretty_time"] = pretty_time(Config.comment.time_format, comment["time"]) # Format the message for display. comment["formatted_message"] = Comment.format_message(comment["message"]) # Was this comment posted by the current user viewing it? comment["editable"] = Comment.is_editable(thread, cid, comment) sorted_comments.append(comment) g.info["header"] = header g.info["thread"] = thread g.info["subject"] = subject g.info["commenting_disabled"] = not addable g.info["url"] = request.url g.info["comments"] = sorted_comments g.info["photo_url"] = Config.photo.root_public return template("comment/index.inc.html")
def view_photo(key): """View a specific photo.""" photo = Photo.get_photo(key) if photo is None: flash("That photo wasn't found!") return redirect(url_for(".albums")) # Get the author info. author = User.get_user(uid=photo["author"]) if author: g.info["author"] = author g.info["photo"] = photo g.info["photo"]["key"] = key g.info["photo"]["pretty_time"] = pretty_time(Config.photo.time_format, photo["uploaded"]) g.info["photo"]["markdown"] = render_markdown(photo.get("description", "")) return template("photos/view.html")
def partial_index(thread, subject, header=True, addable=True): """Partial template for including the index view of a comment thread. * thread: unique name for the comment thread * subject: subject name for the comment thread * header: show the Comments h1 header * addable: boolean, can new comments be added to the thread""" comments = Comment.get_comments(thread) # Sort the comments by most recent on bottom. sorted_cids = [ x for x in sorted(comments, key=lambda y: comments[y]["time"]) ] sorted_comments = [] for cid in sorted_cids: comment = comments[cid] comment["id"] = cid # Was the commenter logged in? if comment["uid"] > 0: user = User.get_user(uid=comment["uid"]) avatar = User.get_picture(uid=comment["uid"]) comment["name"] = user["name"] comment["username"] = user["username"] comment["image"] = avatar # Add the pretty time. comment["pretty_time"] = pretty_time(Config.comment.time_format, comment["time"]) # Format the message for display. comment["formatted_message"] = Comment.format_message( comment["message"]) sorted_comments.append(comment) g.info["header"] = header g.info["thread"] = thread g.info["subject"] = subject g.info["commenting_disabled"] = not addable g.info["url"] = request.url g.info["comments"] = sorted_comments g.info["photo_url"] = Config.photo.root_public return template("comment/index.inc.html")
def unimpersonate(): """Unimpersonate a user.""" # Must be impersonating, first! if not "impersonator" in session: flash("Stop messing around.") return redirect(url_for("index")) uid = session.pop("impersonator") db = User.get_user(uid=uid) session.update( login=True, uid=uid, username=db["username"], name=db["name"], role=db["role"], ) flash("No longer impersonating.") return redirect(url_for("index"))
def impersonate(uid): """Impersonate a user.""" # Check that they exist. if not User.exists(uid=uid): flash("That user ID wasn't found.") return redirect(url_for(".users")) db = User.get_user(uid=uid) if db["role"] == "deleted": flash("That user was deleted!") return redirect(url_for(".users")) # Log them in! orig_uid = session["uid"] session.update( login=True, uid=uid, username=db["username"], name=db["name"], role=db["role"], impersonator=orig_uid ) flash("Now logged in as {}".format(db["name"])) return redirect(url_for("index"))
def partial_index(thread, subject, header=True, addable=True): """Partial template for including the index view of a comment thread. * thread: unique name for the comment thread * subject: subject name for the comment thread * header: show the Comments h1 header * addable: boolean, can new comments be added to the thread""" comments = Comment.get_comments(thread) # Sort the comments by most recent on bottom. sorted_cids = [ x for x in sorted(comments, key=lambda y: comments[y]["time"]) ] sorted_comments = [] for cid in sorted_cids: comment = comments[cid] comment["id"] = cid # Was the commenter logged in? if comment["uid"] > 0: user = User.get_user(uid=comment["uid"]) avatar = User.get_picture(uid=comment["uid"]) comment["name"] = user["name"] comment["username"] = user["username"] comment["image"] = avatar # Add the pretty time. comment["pretty_time"] = pretty_time(Config.comment.time_format, comment["time"]) # Format the message for display. comment["formatted_message"] = Comment.format_message(comment["message"]) sorted_comments.append(comment) g.info["header"] = header g.info["thread"] = thread g.info["subject"] = subject g.info["commenting_disabled"] = not addable g.info["url"] = request.url g.info["comments"] = sorted_comments g.info["photo_url"] = Config.photo.root_public return template("comment/index.inc.html")
def archive(): """List all blog posts over time on one page.""" index = Blog.get_index() # Group by calendar month, and keep track of friendly versions of months. groups = dict() friendly_months = dict() for post_id, data in index.items(): ts = datetime.datetime.fromtimestamp(data["time"]) date = ts.strftime("%Y-%m") if not date in groups: groups[date] = dict() friendly = ts.strftime("%B %Y") friendly_months[date] = friendly # Get author's profile && Pretty-print the time. data["profile"] = User.get_user(uid=data["author"]) data["pretty_time"] = pretty_time(Config.blog.time_format, data["time"]) groups[date][post_id] = data # Sort by calendar month. sort_months = sorted(groups.keys(), reverse=True) # Prepare the results. result = list() for month in sort_months: data = dict( month=month, month_friendly=friendly_months[month], posts=list() ) # Sort the posts by time created, descending. for post_id in sorted(groups[month].keys(), key=lambda x: groups[month][x]["time"], reverse=True): data["posts"].append(groups[month][post_id]) result.append(data) g.info["archive"] = result return template("blog/archive.html")
def archive(): """List all blog posts over time on one page.""" index = Blog.get_index() # Group by calendar month, and keep track of friendly versions of months. groups = dict() friendly_months = dict() for post_id, data in index.items(): ts = datetime.datetime.fromtimestamp(data["time"]) date = ts.strftime("%Y-%m") if not date in groups: groups[date] = dict() friendly = ts.strftime("%B %Y") friendly_months[date] = friendly # Get author's profile && Pretty-print the time. data["profile"] = User.get_user(uid=data["author"]) data["pretty_time"] = pretty_time(Config.blog.time_format, data["time"]) groups[date][post_id] = data # Sort by calendar month. sort_months = sorted(groups.keys(), reverse=True) # Prepare the results. result = list() for month in sort_months: data = dict( month=month, month_friendly=friendly_months[month], posts=list() ) # Sort the posts by time created, descending. for post_id in sorted(groups[month].keys(), key=lambda x: groups[month][x]["time"], reverse=True): data["posts"].append(groups[month][post_id]) result.append(data) g.info["archive"] = result return template("blog/archive.html")
def before_request(): """Called before all requests. Initialize global template variables.""" # Session lifetime. app.permanent_session_lifetime = datetime.timedelta(days=Config.security.session_lifetime) session.permanent = True # Default template vars. g.info = rophako.utils.default_vars() # Default session vars. if not "login" in session: session.update(g.info["session"]) # CSRF protection. if request.method == "POST": token = session.pop("_csrf", None) if not token or str(token) != str(request.form.get("token")): abort(403) # Refresh their login status from the DB. if session["login"]: import rophako.model.user as User if not User.exists(uid=session["uid"]): # Weird! Log them out. from rophako.modules.account import logout logout() return db = User.get_user(uid=session["uid"]) session["username"] = db["username"] session["name"] = db["name"] session["role"] = db["role"] # Copy session params into g.info. The only people who should touch the # session are the login/out pages. for key in session: g.info["session"][key] = session[key]
def edit_user(uid): uid = int(uid) user = User.get_user(uid=uid) # Submitting? if request.method == "POST": action = request.form.get("action", "") username = request.form.get("username", "") name = request.form.get("name", "") pw1 = request.form.get("password1", "") pw2 = request.form.get("password2", "") role = request.form.get("role", "") username = username.lower() if action == "save": # Validate... errors = None # Don't allow them to change the username to one that exists. if username != user["username"]: if User.exists(username=username): flash("That username already exists.") return redirect(url_for(".edit_user", uid=uid)) # Password provided? if len(pw1) > 0: errors = validate_create_form(username, pw1, pw2) elif username != user["username"]: # Just validate the username, then. errors = validate_create_form(username, skip_passwd=True) if errors: for error in errors: flash(error) return redirect(url_for(".edit_user", uid=uid)) # Update the user. user["username"] = username user["name"] = name or username user["role"] = role if len(pw1) > 0: user["password"] = User.hash_password(pw1) User.update_user(uid, user) flash("User account updated!") return redirect(url_for(".users")) elif action == "delete": # Don't let them delete themself! if uid == g.info["session"]["uid"]: flash("You shouldn't delete yourself!") return redirect(url_for(".edit_user", uid=uid)) User.delete_user(uid) flash("User deleted!") return redirect(url_for(".users")) return template( "admin/edit_user.html", info=user, )
def add_comment(thread, uid, name, subject, message, url, time, ip, token=None, image=None): """Add a comment to a comment thread. Parameters: thread (str): the unique comment thread name. uid (int): 0 for guest posts, otherwise the UID of the logged-in user. name (str): the commenter's name (if a guest) subject (str) message (str) url (str): the URL where the comment can be read (i.e. the blog post) time (int): epoch time of the comment. ip (str): the user's IP address. token (str): the user's session's comment deletion token. image (str): the URL to a Gravatar image, if any. """ # Get the comments for this thread. comments = get_comments(thread) # Make up a unique ID for the comment. cid = random_hash() while cid in comments: cid = random_hash() # Add the comment. comments[cid] = dict( uid=uid, name=name or "Anonymous", image=image or "", message=message, time=time or int(time.time()), ip=ip, token=token, ) write_comments(thread, comments) # Get info about the commenter. if uid > 0: user = User.get_user(uid=uid) if user: name = user["name"] # Send the e-mail to the site admins. send_email( to=Config.site.notify_address, subject="Comment Added: {}".format(subject), message="""{name} has left a comment on: {subject} {message} ----- To view this comment, please go to <{url}> Was this comment spam? [Delete it]({deletion_link}).""".format( name=name, subject=subject, message=message, url=url, deletion_link=url_for("comment.quick_delete", token=make_quick_delete_token(thread, cid), url=url, _external=True, ) ), ) # Notify any subscribers. subs = get_subscribers(thread) for sub in subs.keys(): # Make the unsubscribe link. unsub = url_for("comment.unsubscribe", thread=thread, who=sub, _external=True) send_email( to=sub, subject="New Comment: {}".format(subject), message="""Hello, {name} has left a comment on: {subject} {message} ----- To view this comment, please go to <{url}>""".format( thread=thread, name=name, subject=subject, message=message, url=url, unsub=unsub, ), footer="You received this e-mail because you subscribed to the " "comment thread that this comment was added to. You may " "[**unsubscribe**]({unsub}) if you like.".format( unsub=unsub, ), )
def partial_index(template_name="blog/index.inc.html"): """Partial template for including the index view of the blog.""" # Get the blog index. index = Blog.get_index() pool = {} # The set of blog posts to show. category = g.info.get("url_category", None) if category == Config.blog.default_category: category = "" # Are we narrowing by category? if category is not None: # Narrow down the index to just those that match the category. for post_id, data in index.items(): if not category in data["categories"]: continue pool[post_id] = data # No such category? if len(pool) == 0: flash("There are no posts with that category.") return redirect(url_for(".index")) else: pool = index # Get the posts we want. posts = get_index_posts(pool) # Handle pagination. offset = request.args.get("skip", 0) try: offset = int(offset) except: offset = 0 # Handle the offsets, and get those for the "older" and "earlier" posts. # "earlier" posts count down (towards index 0), "older" counts up. g.info["offset"] = offset g.info["earlier"] = offset - int(Config.blog.entries_per_page) if offset > 0 else 0 g.info["older"] = offset + int(Config.blog.entries_per_page) if g.info["earlier"] < 0: g.info["earlier"] = 0 if g.info["older"] < 0 or g.info["older"] > len(posts): g.info["older"] = 0 g.info["count"] = 0 # Can we go to other pages? g.info["can_earlier"] = True if offset > 0 else False g.info["can_older"] = False if g.info["older"] == 0 else True # Load the selected posts. selected = [] stop = offset + int(Config.blog.entries_per_page) if stop > len(posts): stop = len(posts) index = 1 # Let each post know its position on-page. for i in range(offset, stop): post_id = posts[i] post = Blog.get_entry(post_id) post["post_id"] = post_id # Body has a snipped section? if "<snip>" in post["body"]: post["body"] = post["body"].split("<snip>")[0] post["snipped"] = True # Render the body. if post["format"] == "markdown": post["rendered_body"] = render_markdown(post["body"]) else: post["rendered_body"] = post["body"] # Render emoticons. if post["emoticons"]: post["rendered_body"] = Emoticons.render(post["rendered_body"]) # Get the author's information. post["profile"] = User.get_user(uid=post["author"]) post["photo"] = User.get_picture(uid=post["author"]) post["photo_url"] = Config.photo.root_public post["pretty_time"] = pretty_time(Config.blog.time_format, post["time"]) # Count the comments for this post post["comment_count"] = Comment.count_comments("blog-{}".format(post_id)) post["position_index"] = index index += 1 selected.append(post) g.info["count"] += 1 g.info["category"] = category g.info["posts"] = selected return template(template_name)
def partial_index(template_name="blog/index.inc.html", mode="normal"): """Partial template for including the index view of the blog. Args: template_name (str): The name of the template to be rendered. mode (str): The view mode of the posts, one of: - normal: Only list public entries, or private posts for users who are logged in. - drafts: Only list draft entries for logged-in users. """ # Get the blog index. if mode == "normal": index = Blog.get_index() elif mode == "drafts": index = Blog.get_drafts() elif mode == "private": index = Blog.get_private() else: return "Invalid partial_index mode." # Let the pages know what mode they're in. g.info["mode"] = mode pool = {} # The set of blog posts to show. category = g.info.get("url_category", None) if category == Config.blog.default_category: category = "" # Are we narrowing by category? if category is not None: # Narrow down the index to just those that match the category. for post_id, data in index.items(): if not category in data["categories"]: continue pool[post_id] = data # No such category? if len(pool) == 0: flash("There are no posts with that category.") return redirect(url_for(".index")) else: pool = index # Get the posts we want. posts = get_index_posts(pool) # Handle pagination. offset = request.args.get("skip", 0) try: offset = int(offset) except: offset = 0 # Handle the offsets, and get those for the "older" and "earlier" posts. # "earlier" posts count down (towards index 0), "older" counts up. g.info["offset"] = offset g.info["earlier"] = offset - int(Config.blog.entries_per_page) if offset > 0 else 0 g.info["older"] = offset + int(Config.blog.entries_per_page) if g.info["earlier"] < 0: g.info["earlier"] = 0 if g.info["older"] < 0 or g.info["older"] > len(posts) - 1: g.info["older"] = 0 g.info["count"] = 0 # Can we go to other pages? g.info["can_earlier"] = True if offset > 0 else False g.info["can_older"] = False if g.info["older"] == 0 else True # Load the selected posts. selected = [] stop = offset + int(Config.blog.entries_per_page) if stop > len(posts): stop = len(posts) index = 1 # Let each post know its position on-page. for i in range(offset, stop): post_id = posts[i] post = Blog.get_entry(post_id) post["post_id"] = post_id # Body has a snipped section? if "<snip>" in post["body"]: post["body"] = post["body"].split("<snip>")[0] post["snipped"] = True # Render the body. if post["format"] == "markdown": post["rendered_body"] = render_markdown(post["body"]) else: post["rendered_body"] = post["body"] # Render emoticons. if post["emoticons"]: post["rendered_body"] = Emoticons.render(post["rendered_body"]) # Get the author's information. post["profile"] = User.get_user(uid=post["author"]) post["photo"] = User.get_picture(uid=post["author"]) post["photo_url"] = Config.photo.root_public post["pretty_time"] = pretty_time(Config.blog.time_format, post["time"]) # Count the comments for this post post["comment_count"] = Comment.count_comments("blog-{}".format(post_id)) post["position_index"] = index index += 1 selected.append(post) g.info["count"] += 1 g.info["category"] = category g.info["posts"] = selected return template(template_name)
def entry(fid): """Endpoint to view a specific blog entry.""" # Resolve the friendly ID to a real ID. post_id = Blog.resolve_id(fid, drafts=True) if not post_id: # See if the friendly ID contains any extraneous dashes at the front # or end, and remove them and see if we have a match. This allows for # fixing blog fid's that allowed leading/trailing dashes and having the # old URL just redirect to the new one. fid = fid.strip("-") post_id = Blog.resolve_id(fid, drafts=True) # If still nothing, try consolidating extra dashes into one. if not post_id: fid = re.sub(r'-+', '-', fid) post_id = Blog.resolve_id(fid, drafts=True) # Did we find one now? if post_id: return redirect(url_for(".entry", fid=fid)) flash("That blog post wasn't found.") return redirect(url_for(".index")) # Look up the post. post = Blog.get_entry(post_id) post["post_id"] = post_id # Body has a snipped section? if "<snip>" in post["body"]: post["body"] = re.sub(r'\s*<snip>\s*', '\n\n', post["body"]) # Render the body. if post["format"] == "markdown": post["rendered_body"] = render_markdown(post["body"]) else: post["rendered_body"] = post["body"] # Render emoticons. if post["emoticons"]: post["rendered_body"] = Emoticons.render(post["rendered_body"]) # Get the author's information. post["profile"] = User.get_user(uid=post["author"]) post["photo"] = User.get_picture(uid=post["author"]) post["photo_url"] = Config.photo.root_public # Pretty-print the time. post["pretty_time"] = pretty_time(Config.blog.time_format, post["time"]) # Count the comments for this post post["comment_count"] = Comment.count_comments("blog-{}".format(post_id)) # Inject information about this post's siblings. index = Blog.get_index() siblings = [None, None] # previous, next sorted_ids = list(map(lambda y: int(y), sorted(index.keys(), key=lambda x: index[x]["time"], reverse=True))) for i in range(0, len(sorted_ids)): if sorted_ids[i] == post_id: # Found us! if i > 0: # We have an older post. siblings[0] = index[ str(sorted_ids[i-1]) ] if i < len(sorted_ids) - 1: # We have a newer post. siblings[1] = index[ str(sorted_ids[i+1]) ] post["siblings"] = siblings g.info["post"] = post return template("blog/entry.html")
def add_comment(thread, uid, name, subject, message, url, time, ip, image=None): """Add a comment to a comment thread. * uid is 0 if it's a guest post, otherwise the UID of the user. * name is the commenter's name (if a guest) * subject is for the e-mails that are sent out * message is self explanatory. * url is the URL where the comment can be read. * time, epoch time of comment. * ip is the IP address of the commenter. * image is a Gravatar image URL etc. """ # Get the comments for this thread. comments = get_comments(thread) # Make up a unique ID for the comment. cid = random_hash() while cid in comments: cid = random_hash() # Add the comment. comments[cid] = dict( uid=uid, name=name or "Anonymous", image=image or "", message=message, time=time or int(time.time()), ip=ip, ) write_comments(thread, comments) # Get info about the commenter. if uid > 0: user = User.get_user(uid=uid) if user: name = user["name"] # Send the e-mail to the site admins. send_email( to=Config.site.notify_address, subject="New comment: {}".format(subject), message="""{name} has left a comment on: {subject} {message} To view this comment, please go to {url} ===================== This e-mail was automatically generated. Do not reply to it.""".format( name=name, subject=subject, message=message, url=url, ), ) # Notify any subscribers. subs = get_subscribers(thread) for sub in subs.keys(): # Make the unsubscribe link. unsub = url_for("comment.unsubscribe", thread=thread, who=sub, _external=True) send_email( to=sub, subject="New Comment: {}".format(subject), message="""Hello, You are currently subscribed to the comment thread '{thread}', and somebody has just added a new comment! {name} has left a comment on: {subject} {message} To view this comment, please go to {url} ===================== This e-mail was automatically generated. Do not reply to it. If you wish to unsubscribe from this comment thread, please visit the following URL: {unsub}""".format( thread=thread, name=name, subject=subject, message=message, url=url, unsub=unsub, ) )
def add_comment(thread, uid, name, subject, message, url, time, ip, image=None): """Add a comment to a comment thread. * uid is 0 if it's a guest post, otherwise the UID of the user. * name is the commenter's name (if a guest) * subject is for the e-mails that are sent out * message is self explanatory. * url is the URL where the comment can be read. * time, epoch time of comment. * ip is the IP address of the commenter. * image is a Gravatar image URL etc. """ # Get the comments for this thread. comments = get_comments(thread) # Make up a unique ID for the comment. cid = random_hash() while cid in comments: cid = random_hash() # Add the comment. comments[cid] = dict( uid=uid, name=name or "Anonymous", image=image or "", message=message, time=time or int(time.time()), ip=ip, ) write_comments(thread, comments) # Get info about the commenter. if uid > 0: user = User.get_user(uid=uid) if user: name = user["name"] # Send the e-mail to the site admins. send_email( to=Config.site.notify_address, subject="New comment: {}".format(subject), message="""{name} has left a comment on: {subject} {message} To view this comment, please go to {url} ===================== This e-mail was automatically generated. Do not reply to it.""".format( name=name, subject=subject, message=message, url=url, ), ) # Notify any subscribers. subs = get_subscribers(thread) for sub in subs.keys(): # Make the unsubscribe link. unsub = url_for("comment.unsubscribe", thread=thread, who=sub, _external=True) send_email(to=sub, subject="New Comment: {}".format(subject), message="""Hello, You are currently subscribed to the comment thread '{thread}', and somebody has just added a new comment! {name} has left a comment on: {subject} {message} To view this comment, please go to {url} ===================== This e-mail was automatically generated. Do not reply to it. If you wish to unsubscribe from this comment thread, please visit the following URL: {unsub}""".format( thread=thread, name=name, subject=subject, message=message, url=url, unsub=unsub, ))