Exemple #1
0
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")
Exemple #2
0
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")
Exemple #3
0
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")
Exemple #4
0
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")
Exemple #5
0
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)
Exemple #6
0
def rss():
    """RSS feed for the blog."""
    doc = Document()

    rss = doc.createElement("rss")
    rss.setAttribute("version", "2.0")
    rss.setAttribute("xmlns:blogChannel", "http://backend.userland.com/blogChannelModule")
    doc.appendChild(rss)

    channel = doc.createElement("channel")
    rss.appendChild(channel)

    rss_time = "%a, %d %b %Y %H:%M:%S GMT"

    ######
    ## Channel Information
    ######

    today = time.strftime(rss_time, time.gmtime())

    xml_add_text_tags(doc, channel, [
        ["title", Config.blog.title],
        ["link", Config.blog.link],
        ["description", Config.blog.description],
        ["language", Config.blog.language],
        ["copyright", Config.blog.copyright],
        ["pubDate", today],
        ["lastBuildDate", today],
        ["webmaster", Config.blog.webmaster],
    ])

    ######
    ## Image Information
    ######

    image = doc.createElement("image")
    channel.appendChild(image)
    xml_add_text_tags(doc, image, [
        ["title", Config.blog.image_title],
        ["url", Config.blog.image_url],
        ["link", Config.blog.link],
        ["width", Config.blog.image_width],
        ["height", Config.blog.image_height],
        ["description", Config.blog.image_description],
    ])

    ######
    ## Add the blog posts
    ######

    index = Blog.get_index()
    posts = get_index_posts(index)
    for post_id in posts[:int(Config.blog.entries_per_feed)]:
        post = Blog.get_entry(post_id)
        item = doc.createElement("item")
        channel.appendChild(item)

        # 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"])

        xml_add_text_tags(doc, item, [
            ["title", post["subject"]],
            ["link", url_for("blog.entry", fid=post["fid"], _external=True)],
            ["description", post["rendered_body"]],
            ["pubDate", time.strftime(rss_time, time.gmtime(post["time"]))],
        ])

    resp = make_response(doc.toprettyxml(encoding="utf-8"))
    resp.headers["Content-Type"] = "application/rss+xml; charset=utf-8"
    return resp
Exemple #7
0
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)
Exemple #8
0
def rss():
    """RSS feed for the blog."""
    doc = Document()

    rss = doc.createElement("rss")
    rss.setAttribute("version", "2.0")
    rss.setAttribute("xmlns:blogChannel", "http://backend.userland.com/blogChannelModule")
    doc.appendChild(rss)

    channel = doc.createElement("channel")
    rss.appendChild(channel)

    rss_time = "%a, %d %b %Y %H:%M:%S GMT"

    ######
    ## Channel Information
    ######

    today = time.strftime(rss_time, time.gmtime())

    xml_add_text_tags(doc, channel, [
        ["title", Config.blog.title],
        ["link", Config.blog.link],
        ["description", Config.blog.description],
        ["language", Config.blog.language],
        ["copyright", Config.blog.copyright],
        ["pubDate", today],
        ["lastBuildDate", today],
        ["webmaster", Config.blog.webmaster],
    ])

    ######
    ## Image Information
    ######

    image = doc.createElement("image")
    channel.appendChild(image)
    xml_add_text_tags(doc, image, [
        ["title", Config.blog.image_title],
        ["url", Config.blog.image_url],
        ["link", Config.blog.link],
        ["width", Config.blog.image_width],
        ["height", Config.blog.image_height],
        ["description", Config.blog.image_description],
    ])

    ######
    ## Add the blog posts
    ######

    index = Blog.get_index()
    posts = get_index_posts(index)
    for post_id in posts[:int(Config.blog.entries_per_feed)]:
        post = Blog.get_entry(post_id)
        item = doc.createElement("item")
        channel.appendChild(item)

        # 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"])

        xml_add_text_tags(doc, item, [
            ["title", post["subject"]],
            ["link", url_for("blog.entry", fid=post["fid"], _external=True)],
            ["description", post["rendered_body"]],
            ["pubDate", time.strftime(rss_time, time.gmtime(post["time"]))],
        ])

    resp = make_response(doc.toprettyxml(encoding="utf-8"))
    resp.headers["Content-Type"] = "application/rss+xml; charset=utf-8"
    return resp