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 edit_album(album): photos = Photo.list_photos(album) if photos is None: flash("That album doesn't exist.") return redirect(url_for(".albums")) if request.method == "POST": # Collect the form details. new_name = request.form["name"] description = request.form["description"] layout = request.form["format"] # Renaming the album? if new_name != album: ok = Photo.rename_album(album, new_name) if not ok: flash("Failed to rename album: already exists?") return redirect(url_for(".edit_album", album=album)) album = new_name # Update album settings. Photo.edit_album(album, dict( description=description, format=layout, )) return redirect(url_for(".albums")) g.info["album"] = album g.info["album_info"] = Photo.get_album(album) g.info["photos"] = photos return template("photos/edit_album.html")
def edit(thread, cid): """Edit an existing comment.""" url = request.args.get("url") comment = Comment.get_comment(thread, cid) if not comment: flash("The comment wasn't found!") return redirect(url or url_for("index")) # Submitting? if request.method == "POST": action = request.form.get("action") message = request.form.get("message") url = request.form.get("url") # Preserve the URL! if len(message) == 0: flash("The comment must have a message!") return redirect(url_for(".edit", thread=thread, cid=cid, url=url)) # Update the real comment data with the submitted message (for preview), # if they clicked Save it will then be saved back to disk. comment["message"] = message if action == "save": # Saving the changes! Comment.update_comment(thread, cid, comment) flash("Comment updated successfully!") return redirect(url or url_for("index")) # Render the Markdown. comment["formatted_message"] = Comment.format_message(comment["message"]) g.info["thread"] = thread g.info["cid"] = cid g.info["comment"] = comment g.info["url"] = url or "" return template("comment/edit.html")
def list_pages(): """Wiki page list.""" g.info["pages"] = [ {"name": name, "link": Wiki.name_to_url(name)} \ for name in Wiki.list_pages() ] return template("wiki/list.html")
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 crop(photo): pic = Photo.get_photo(photo) if not pic: flash("The photo you want to crop wasn't found!") return redirect(url_for(".albums")) # Saving? if request.method == "POST": try: x = int(request.form.get("x", 0)) y = int(request.form.get("y", 0)) length = int(request.form.get("length", 0)) except: flash("Error with form inputs.") return redirect(url_for(".crop", photo=photo)) # Re-crop the photo! Photo.crop_photo(photo, x, y, length) flash("The photo has been cropped!") return redirect(url_for(".albums")) # TODO go to photo # Get the photo's true size. true_width, true_height = Photo.get_image_dimensions(pic) g.info["true_width"] = true_width g.info["true_height"] = true_height g.info["photo"] = photo g.info["preview"] = pic["large"] return template("photos/crop.html")
def unsubscribe(): """Unsubscribe an e-mail from a comment thread (or all threads).""" # This endpoint can be called with either method. For the unsubscribe links # inside the e-mails, it uses GET. For the global out-opt, it uses POST. thread, email = None, None if request.method == "POST": thread = request.form.get("thread", "") email = request.form.get("email", "") # Spam check. trap1 = request.form.get("url", "x") != "http://" trap2 = request.form.get("message", "x") != "" if trap1 or trap2: flash("Wanna try that again?") return redirect(url_for("index")) else: thread = request.args.get("thread", "") email = request.args.get("who", "") # Input validation. if not thread: flash("Comment thread not found.") return redirect(url_for("index")) if not email: flash("E-mail address not provided.") return redirect(url_for("index")) # Do the unsubscribe. If thread is *, this means a global unsubscribe from # all threads. Comment.unsubscribe(thread, email) g.info["thread"] = thread g.info["email"] = email return template("comment/unsubscribed.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 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 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 users(): # Get the list of existing users. users = User.list_users() return template( "admin/users.html", users=users, )
def edit(): """Wiki page editor.""" title = request.args.get("name", "") body = "" history = True # Update History box is always checked by default note = request.args.get("note", "") # Editing an existing page? page = Wiki.get_page(title) if page: head = page["revisions"][0] body = head["body"] if request.method == "POST": # Submitting the form. action = request.form.get("action", "preview") title = request.form.get("name", "") body = request.form.get("body", "") history = request.form.get("history", "false") == "true" note = request.form.get("note", "") if action == "preview": # Just previewing it. g.info["preview"] = True # Render markdown g.info["rendered_body"] = Wiki.render_page(body) # Render emoticons. g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"]) elif action == "publish": # Publishing! Validate inputs. invalid = False if len(title) == 0: invalid = True flash("You must have a page title.") if len(body) == 0: invalid = True flash("You must have a page body.") if not invalid: # Update the page. Wiki.edit_page( author=g.info["session"]["uid"], name=title, body=body, note=note, history=history, ) return redirect( url_for("wiki.view_page", name=Wiki.name_to_url(title))) g.info["title"] = title g.info["body"] = body g.info["note"] = note g.info["history"] = history return template("wiki/edit.html")
def upload(): """Upload a photo.""" if request.method == "POST": # We're posting the upload. # Is this an ajax post or a direct post? is_ajax = request.form.get("__ajax", "false") == "true" # Album name. album = request.form.get("album") or request.form.get("new-album") # What source is the pic from? result = None location = request.form.get("location") if location == "pc": # An upload from the PC. result = Photo.upload_from_pc(request) elif location == "www": # An upload from the Internet. result = Photo.upload_from_www(request.form) else: flash("Stop messing around.") return redirect(url_for(".upload")) # How'd it go? if result["success"] is not True: if is_ajax: return ajax_response(False, result["error"]) else: flash("The upload has failed: {}".format(result["error"])) return redirect(url_for(".upload")) # Good! if is_ajax: # Was it a multiple upload? if result.get("multi"): return ajax_response(True, url_for(".album_index", name=album)) else: return ajax_response(True, url_for(".crop", photo=result["photo"])) else: if result["multi"]: return redirect(url_for(".album_index", name=album)) else: return redirect(url_for(".crop", photo=result["photo"])) # Get the list of available albums. g.info["album_list"] = [ "My Photos", # the default ] g.info["selected"] = Config.photo.default_album albums = Photo.list_albums() if len(albums): g.info["album_list"] = [ x["name"] for x in albums ] g.info["selected"] = albums[0] return template("photos/upload.html")
def albums(): """View the index of the photo albums.""" albums = Photo.list_albums() # If there's only one album, jump directly to that one. if len(albums) == 1: return redirect(url_for(".album_index", name=albums[0]["name"])) g.info["albums"] = albums return template("photos/albums.html")
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 preview(): # Get the form fields. form = get_comment_form(request.form) thread = sanitize_name(form["thread"]) # Trap fields. trap1 = request.form.get("website", "x") != "http://" trap2 = request.form.get("email", "x") != "" if trap1 or trap2: flash("Wanna try that again?") return redirect(url_for("index")) # Validate things. if len(form["message"]) == 0: flash("You must provide a message with your comment.") return redirect(form["url"]) # Gravatar? gravatar = Comment.gravatar(form["contact"]) # Are they submitting? if form["action"] == "submit": Comment.add_comment( thread=thread, uid=g.info["session"]["uid"], ip=remote_addr(), time=int(time.time()), image=gravatar, name=form["name"], subject=form["subject"], message=form["message"], url=form["url"], ) # Are we subscribing to the thread? if form["subscribe"] == "true": email = form["contact"] if "@" in email: Comment.add_subscriber(thread, email) flash( "You have been subscribed to future comments on this page." ) flash("Your comment has been added!") return redirect(form["url"]) # Gravatar. g.info["gravatar"] = gravatar g.info["preview"] = Comment.format_message(form["message"]) g.info["pretty_time"] = pretty_time(Config.comment.time_format, time.time()) g.info.update(form) return template("comment/preview.html")
def preview(): # Get the form fields. form = get_comment_form(request.form) thread = sanitize_name(form["thread"]) # Trap fields. trap1 = request.form.get("website", "x") != "http://" trap2 = request.form.get("email", "x") != "" if trap1 or trap2: flash("Wanna try that again?") return redirect(url_for("index")) # Validate things. if len(form["message"]) == 0: flash("You must provide a message with your comment.") return redirect(form["url"]) # Gravatar? gravatar = Comment.gravatar(form["contact"]) # Are they submitting? if form["action"] == "submit": Comment.add_comment( thread=thread, uid=g.info["session"]["uid"], ip=remote_addr(), time=int(time.time()), image=gravatar, name=form["name"], subject=form["subject"], message=form["message"], url=form["url"], ) # Are we subscribing to the thread? if form["subscribe"] == "true": email = form["contact"] if "@" in email: Comment.add_subscriber(thread, email) flash("You have been subscribed to future comments on this page.") flash("Your comment has been added!") return redirect(form["url"]) # Gravatar. g.info["gravatar"] = gravatar g.info["preview"] = Comment.format_message(form["message"]) g.info["pretty_time"] = pretty_time(Config.comment.time_format, time.time()) g.info.update(form) return template("comment/preview.html")
def edit(): """Wiki page editor.""" title = request.args.get("name", "") body = "" history = True # Update History box is always checked by default note = request.args.get("note", "") # Editing an existing page? page = Wiki.get_page(title) if page: head = page["revisions"][0] body = head["body"] if request.method == "POST": # Submitting the form. action = request.form.get("action", "preview") title = request.form.get("name", "") body = request.form.get("body", "") history = request.form.get("history", "false") == "true" note = request.form.get("note", "") if action == "preview": # Just previewing it. g.info["preview"] = True # Render markdown g.info["rendered_body"] = Wiki.render_page(body) # Render emoticons. g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"]) elif action == "publish": # Publishing! Validate inputs. invalid = False if len(title) == 0: invalid = True flash("You must have a page title.") if len(body) == 0: invalid = True flash("You must have a page body.") if not invalid: # Update the page. Wiki.edit_page(author=g.info["session"]["uid"], name=title, body=body, note=note, history=history) return redirect(url_for("wiki.view_page", name=Wiki.name_to_url(title))) g.info["title"] = title g.info["body"] = body g.info["note"] = note g.info["history"] = history return template("wiki/edit.html")
def delete_revision(name, revision): """Delete a wiki page revision from history.""" link = name name = Wiki.url_to_name(name) if request.method == "POST": Wiki.delete_history(name, revision) flash("Revision deleted.") return redirect(url_for("wiki.view_page", name=Wiki.name_to_url(name))) g.info["confirm_url"] = url_for("wiki.delete_revision", name=link, revision=revision) g.info["title"] = name g.info["type"] = "revision" return template("wiki/delete.html")
def delete_page(name): """Delete a wiki page entirely.""" link = name name = Wiki.url_to_name(name) if request.method == "POST": Wiki.delete_page(name) flash("Page completely deleted.") return redirect(url_for("wiki.index")) g.info["confirm_url"] = url_for("wiki.delete_page", name=link) g.info["title"] = name g.info["type"] = "page" return template("wiki/delete.html")
def index(): """List the available emoticons.""" theme = Emoticons.load_theme() smileys = [] for img in sorted(theme["map"]): smileys.append({ "img": img, "triggers": theme["map"][img], }) g.info["theme"] = Config.emoticons.theme g.info["theme_name"] = theme["name"] g.info["smileys"] = smileys return template("emoticons/index.html")
def arrange_albums(): """Rearrange the photo album order.""" albums = Photo.list_albums() if len(albums) == 0: flash("There are no albums yet.") return redirect(url_for(".albums")) if request.method == "POST": order = request.form.get("order", "").split(";") Photo.order_albums(order) flash("The albums have been rearranged!") return redirect(url_for(".albums")) g.info["albums"] = albums return template("photos/arrange_albums.html")
def referrers(): g.info["referrers"] = Tracking.get_referrers() # Filter some of the links. for i, link in enumerate(g.info["referrers"]["referrers"]): # Clean up useless Google links. if "google" in link[0] and re.search( r'/(?:imgres|url|search|translate\w+)?/', link[0]): g.info["referrers"]["referrers"][i] = None # Make the links word-wrap properly. filtered = [[re.sub(r'(.{20})', r'\1<wbr>', x[0]), x[1]] for x in g.info["referrers"]["referrers"] if x is not None] g.info["referrers"]["referrers"] = filtered return template("tracking/referrers.html")
def arrange_photos(album): """Rearrange the photos in an album.""" photos = Photo.list_photos(album) if photos is None: flash("That album doesn't exist.") return redirect(url_for(".albums")) if request.method == "POST": order = request.form.get("order", "").split(";") Photo.order_photos(album, order) flash("The albums have been rearranged!") return redirect(url_for(".album_index", name=album)) g.info["album"] = album g.info["photos"] = photos return template("photos/arrange_photos.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 legacy_download(): form = None if request.method == "POST": form = request.form else: # CNET links to the MS-DOS download using semicolon delimiters in the # query string. Fix that if detected. query = request.query_string.decode() if not '&' in query and ';' in query: url = re.sub(r';|%3b', '&', request.url, flags=re.IGNORECASE) return redirect(url) form = request.args method = form.get("method", "index") project = form.get("project", "") filename = form.get("file", "") root = "/home/kirsle/www/projects" if project and filename: # Filter the sections. project = re.sub(r'[^A-Za-z0-9]', '', project) # Project name is alphanumeric only. filename = re.sub(r'[^A-Za-z0-9\-_\.]', '', filename) # Check that all the files exist. if os.path.isdir(os.path.join(root, project)) and os.path.isfile(os.path.join(root, project, filename)): # Hit counters. hits = { "hits": 0 } db = "data/downloads/{}-{}".format(project, filename) if JsonDB.exists(db.format(project, filename)): hits = JsonDB.get(db) # Actually getting the file? if method == "get": # Up the hit counter. hits["hits"] += 1 JsonDB.commit(db, hits) g.info["method"] = method g.info["project"] = project g.info["file"] = filename g.info["hits"] = hits["hits"] return template("download.html") flash("The file or project wasn't found.") return redirect(url_for("index"))
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 delete(key): """Delete a photo.""" pic = Photo.get_photo(key) if not pic: flash("The photo wasn't found!") return redirect(url_for(".albums")) if request.method == "POST": # Do it. Photo.delete_photo(key) flash("The photo has been deleted.") return redirect(url_for(".albums")) g.info["key"] = key g.info["photo"] = pic return template("photos/delete.html")
def delete_album(album): """Delete an entire album.""" photos = Photo.list_photos(album) if photos is None: flash("That album doesn't exist.") return redirect(url_for(".albums")) if request.method == "POST": # Do it. for photo in photos: Photo.delete_photo(photo["key"]) flash("The album has been deleted.") return redirect(url_for(".albums")) g.info["album"] = album return template("photos/delete_album.html")
def album_index(name): """View the photos inside an album.""" photos = Photo.list_photos(name) if photos is None: flash("That album doesn't exist.") return redirect(url_for(".albums")) g.info["album"] = name g.info["album_info"] = Photo.get_album(name) g.info["markdown"] = render_markdown(g.info["album_info"]["description"]) g.info["photos"] = photos # Render Markdown descriptions for photos. for photo in g.info["photos"]: photo["data"]["markdown"] = render_markdown(photo["data"].get("description", "")) return template("photos/album.html")
def setup(): """Initial setup to create the Admin user account.""" # This can't be done if users already exist on the CMS! if User.exists(uid=1): flash( "This website has already been configured (users already created)." ) return redirect(url_for("index")) if request.method == "POST": # Submitting the form. username = request.form.get("username", "") name = request.form.get("name", "") pw1 = request.form.get("password1", "") pw2 = request.form.get("password2", "") # Default name = username. if name == "": name = username # Lowercase the user. username = username.lower() if User.exists(username=username): flash("That username already exists.") return redirect(url_for(".setup")) # Validate the form. errors = validate_create_form(username, pw1, pw2) if errors: for error in errors: flash(error) return redirect(url_for(".setup")) # Create the account. uid = User.create( username=username, password=pw1, name=name, role="admin", ) flash("Admin user created! Please log in now.".format(uid)) return redirect(url_for(".login")) return template("account/setup.html")
def setup(): """Initial setup to create the Admin user account.""" # This can't be done if users already exist on the CMS! if User.exists(uid=1): flash("This website has already been configured (users already created).") return redirect(url_for("index")) if request.method == "POST": # Submitting the form. username = request.form.get("username", "") name = request.form.get("name", "") pw1 = request.form.get("password1", "") pw2 = request.form.get("password2", "") # Default name = username. if name == "": name = username # Lowercase the user. username = username.lower() if User.exists(username=username): flash("That username already exists.") return redirect(url_for(".setup")) # Validate the form. errors = validate_create_form(username, pw1, pw2) if errors: for error in errors: flash(error) return redirect(url_for(".setup")) # Create the account. uid = User.create( username=username, password=pw1, name=name, role="admin", ) flash("Admin user created! Please log in now.".format(uid)) return redirect(url_for(".login")) return template("account/setup.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 referrers(): g.info["referrers"] = Tracking.get_referrers() # Filter some of the links. for i, link in enumerate(g.info["referrers"]["referrers"]): # Clean up useless Google links. if "google" in link[0] and re.search(r'/(?:imgres|url|search|translate\w+)?/', link[0]): g.info["referrers"]["referrers"][i] = None # Make the links word-wrap properly. filtered = [ [ re.sub(r'(.{20})', r'\1<wbr>', x[0]), x[1] ] for x in g.info["referrers"]["referrers"] if x is not None ] g.info["referrers"]["referrers"] = filtered return template("tracking/referrers.html")
def legacy_download(): form = None if request.method == "POST": form = request.form else: form = request.args method = form.get("method", "index") project = form.get("project", "") filename = form.get("file", "") root = "/home/kirsle/www/projects" if project and filename: # Filter the sections. project = re.sub(r'[^A-Za-z0-9]', '', project) # Project name is alphanumeric only. filename = re.sub(r'[^A-Za-z0-9\-_\.]', '', filename) # Check that all the files exist. if os.path.isdir(os.path.join(root, project)) and os.path.isfile( os.path.join(root, project, filename)): # Hit counters. hits = {"hits": 0} db = "data/downloads/{}-{}".format(project, filename) if JsonDB.exists(db.format(project, filename)): hits = JsonDB.get(db) # Actually getting the file? if method == "get": # Up the hit counter. hits["hits"] += 1 JsonDB.commit(db, hits) g.info["method"] = method g.info["project"] = project g.info["file"] = filename g.info["hits"] = hits["hits"] return template("download.html") flash("The file or project wasn't found.") return redirect(url_for("index"))
def partial_tags(): """Get a listing of tags and their quantities for the nav bar.""" tags = Blog.get_categories() # Sort the tags by popularity. sort_tags = [ tag for tag in sorted(tags.keys(), key=lambda y: tags[y], reverse=True) ] result = [] has_small = False for tag in sort_tags: result.append(dict( category=tag, count=tags[tag], small=tags[tag] < 3, # TODO: make this configurable )) if tags[tag] < 3: has_small = True g.info["tags"] = result g.info["has_small"] = has_small return template("blog/categories.inc.html")
def partial_tags(): """Get a listing of tags and their quantities for the nav bar.""" tags = Blog.get_categories() # Sort the tags by popularity. sort_tags = [ tag for tag in sorted(tags.keys(), key=lambda y: tags[y], reverse=True) ] result = [] has_small = False for tag in sort_tags: result.append(dict( category=tag if len(tag) else Config.blog.default_category, count=tags[tag], small=tags[tag] < 10, # TODO: make this configurable )) if tags[tag] < 10: has_small = True g.info["tags"] = result g.info["has_small"] = has_small return template("blog/categories.inc.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 legacy_download(): form = None if request.method == "POST": form = request.form else: form = request.args method = form.get("method", "index") project = form.get("project", "") filename = form.get("file", "") root = "/home/kirsle/www/projects" if project and filename: # Filter the sections. project = re.sub(r'[^A-Za-z0-9]', '', project) # Project name is alphanumeric only. filename = re.sub(r'[^A-Za-z0-9\-_\.]', '', filename) # Check that all the files exist. if os.path.isdir(os.path.join(root, project)) and os.path.isfile(os.path.join(root, project, filename)): # Hit counters. hits = { "hits": 0 } db = "data/downloads/{}-{}".format(project, filename) if JsonDB.exists(db.format(project, filename)): hits = JsonDB.get(db) # Actually getting the file? if method == "get": # Up the hit counter. hits["hits"] += 1 JsonDB.commit(db, hits) g.info["method"] = method g.info["project"] = project g.info["file"] = filename g.info["hits"] = hits["hits"] return template("download.html") flash("The file or project wasn't found.") return redirect(url_for("index"))
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 delete(): """Delete a blog post.""" post_id = request.args.get("id") # Resolve the post ID. post_id = Blog.resolve_id(post_id) if not post_id: flash("That blog post wasn't found.") return redirect(url_for(".index")) if request.method == "POST": confirm = request.form.get("confirm") if confirm == "true": Blog.delete_entry(post_id) flash("The blog entry has been deleted.") return redirect(url_for(".index")) # Get the entry's subject. post = Blog.get_entry(post_id) g.info["subject"] = post["subject"] g.info["post_id"] = post_id return template("blog/delete.html")
def delete(): """Delete a blog post.""" post_id = request.args.get("id") # Resolve the post ID. post_id = Blog.resolve_id(post_id, drafts=True) if not post_id: flash("That blog post wasn't found.") return redirect(url_for(".index")) if request.method == "POST": confirm = request.form.get("confirm") if confirm == "true": Blog.delete_entry(post_id) flash("The blog entry has been deleted.") return redirect(url_for(".index")) # Get the entry's subject. post = Blog.get_entry(post_id) g.info["subject"] = post["subject"] g.info["post_id"] = post_id return template("blog/delete.html")
def index(): return template("tracking/index.html")
def legacy_firered(page=""): g.info["page"] = str(page) or "1" return template("firered.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 update(): """Post/edit a blog entry.""" # Get our available avatars. g.info["avatars"] = Blog.list_avatars() g.info["userpic"] = User.get_picture(uid=g.info["session"]["uid"]) # Default vars. g.info.update(dict( post_id="", fid="", author=g.info["session"]["uid"], subject="", body="", format="markdown", avatar="", categories="", privacy=Config.blog.default_privacy, emoticons=True, comments=Config.blog.allow_comments, month="", day="", year="", hour="", min="", sec="", preview=False, )) # Editing an existing post? post_id = request.args.get("id", None) if post_id: post_id = Blog.resolve_id(post_id) if post_id: logger.info("Editing existing blog post {}".format(post_id)) post = Blog.get_entry(post_id) g.info["post_id"] = post_id g.info["post"] = post # Copy fields. for field in ["author", "fid", "subject", "format", "format", "body", "avatar", "categories", "privacy", "emoticons", "comments"]: g.info[field] = post[field] # Dissect the time. date = datetime.datetime.fromtimestamp(post["time"]) g.info.update(dict( month="{:02d}".format(date.month), day="{:02d}".format(date.day), year=date.year, hour="{:02d}".format(date.hour), min="{:02d}".format(date.minute), sec="{:02d}".format(date.second), )) # Are we SUBMITTING the form? if request.method == "POST": action = request.form.get("action") # Get all the fields from the posted params. g.info["post_id"] = request.form.get("id") for field in ["fid", "subject", "format", "body", "avatar", "categories", "privacy"]: g.info[field] = request.form.get(field) for boolean in ["emoticons", "comments"]: g.info[boolean] = True if request.form.get(boolean, None) == "true" else False for number in ["author", "month", "day", "year", "hour", "min", "sec"]: g.info[number] = int(request.form.get(number, 0)) # What action are they doing? if action == "preview": g.info["preview"] = True # Render markdown? if g.info["format"] == "markdown": g.info["rendered_body"] = render_markdown(g.info["body"]) else: g.info["rendered_body"] = g.info["body"] # Render emoticons. if g.info["emoticons"]: g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"]) elif action == "publish": # Publishing! Validate inputs first. invalid = False if len(g.info["body"]) == 0: invalid = True flash("You must enter a body for your blog post.") if len(g.info["subject"]) == 0: invalid = True flash("You must enter a subject for your blog post.") # Make sure the times are valid. date = None try: date = datetime.datetime( g.info["year"], g.info["month"], g.info["day"], g.info["hour"], g.info["min"], g.info["sec"], ) except ValueError as e: invalid = True flash("Invalid date/time: " + str(e)) # Format the categories. tags = [] for tag in g.info["categories"].split(","): tags.append(tag.strip()) # Okay to update? if invalid is False: # Convert the date into a Unix time stamp. epoch = float(date.strftime("%s")) new_id, new_fid = Blog.post_entry( post_id = g.info["post_id"], epoch = epoch, author = g.info["author"], subject = g.info["subject"], fid = g.info["fid"], avatar = g.info["avatar"], categories = tags, privacy = g.info["privacy"], ip = remote_addr(), emoticons = g.info["emoticons"], comments = g.info["comments"], format = g.info["format"], body = g.info["body"], ) return redirect(url_for(".entry", fid=new_fid)) if type(g.info["categories"]) is list: g.info["categories"] = ", ".join(g.info["categories"]) return template("blog/update.html")
def index(): return template("admin/index.html")
def visitors(): g.info["history"] = Tracking.get_visitor_details() return template("tracking/visitors.html")
def category(category): g.info["url_category"] = category return template("blog/index.html")
def privacy(): """The privacy policy and global unsubscribe page.""" return template("comment/privacy.html")
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 index(): return template("blog/index.html")