You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.6 KiB
Python

5 years ago
from __future__ import print_function
from __future__ import unicode_literals
from builtins import str, bytes, dict, int
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
from pattern.server import App, template, threadsafe
from io import open
# This example demonstrates a simple wiki served by pattern.server.
# A wiki is a web app where each page can be edited (e.g, Wikipedia).
# We will store the contents of each page as a file in /data.
app = App(name="wiki")
# Our wiki app has a single URL handler listening at the root ("/").
# It takes any combination of positional and keyword arguments.
# This means that any URL will be routed to the index() function.
# For example, http://127.0.0.1:8080/pages/bio.html?edit calls index()
# with path=("pages", "bio.html") and data={"edit": ""}.
@app.route("/")
def index(*path, **data):
#print("path:", path)
#print("data:", data)
# Construct a file name in /data from the URL path.
# For example, path=("pages", "bio.html")
# is mapped to "/data/pages/bio.html.txt".
page = "/".join(path)
page = page if page else "index.html"
page = page.replace(" ", "-")
page = page + ".txt"
page = os.path.join(app.path, "data", page) # Absolute paths are safer.
#print("page:", page)
# If the URL ends in "?save", update the page content.
if "save" in data and "content" in data:
return save(page, src=data["content"])
# If the URL ends in "?edit", show the page editor.
if "edit" in data:
return edit(page)
# If the page does not exist, show the page editor.
if not os.path.exists(page):
return edit(page)
# Show the page.
else:
return view(page)
# The pattern.server module has a simple template() function
# that takes a file path or a string and optional parameters.
# Placeholders in the template source (e.g., "$name")
# are replaced with the parameter values.
# Below is a template with placeholders for page name and content.
# The page content is loaded from a file stored in /data.
# The page name is parsed from the filename,
# e.g., "/data/index.html.txt" => "index.html".
wiki = """
<!doctype html>
<html>
<head>
<title>$name</title>
<meta charset="utf-8">
</head>
<body>
<h3>$name</h3>
$content
<br>
<a href="?edit">edit</a>
</body>
</html>
"""
# The name() function takes a file path (e.g., "/data/index.html.txt")
# and returns the page name ("index.html").
def name(page):
name = os.path.basename(page) # "/data/index.html.txt" => "index.html.txt"
name = os.path.splitext(name)[0] # ("index.html", ".txt") => "index.html"
return name
# We could also have a function for a *display* name (e.g., "Index").
# Something like:
def displayname(page):
return name(name(page)).replace("-", " ").title()
# The view() function is called when a page needs to be displayed.
# Our template has two placeholders: the page $name and $content.
# We load the $content from the contents of the given file path.
# We load the $name using the name() function above.
def view(page):
print(displayname(page))
return template(wiki, name=name(page), content=open(page).read())
# The edit() function is called when a URL ends in "?edit",
# e.g., http://127.0.0.1:8080/index.html?edit.
# In this case, we don't show the contents of "/data/index.html.txt" directly,
# but wrapped inside a <textarea> for editing instead.
# Once the user is done editing and clicks "Submit",
# the browser redirects to http://127.0.0.1:8080/index.html?save,
# posting the data inside the <textarea> to the server.
# We can catch it as the optional "content" parameter of the index() function
# (since the name of the <textarea> is "content").
def edit(page):
s = open(page).read() if os.path.exists(page) else ""
s = '<form method="post" action="?save">' \
'<textarea name="content" rows="10" cols="80">%s</textarea><br>' \
'<input type="submit">' \
'</form>' % s
return template(wiki, name=name(page), content=s)
# The save() function is called when edited content is posted to the server.
# It creates a file in /data and stores the content.
@threadsafe
def save(page, src):
f = open(page, "w")
f.write(src.encode("utf-8"))
f.close()
return view(page)
# Writing HTML by hand in the <textarea> becomes tedious after a while,
# so we could for example extend save() with a parser for Markdown syntax:
# http://en.wikipedia.org/wiki/Markdown,
# http://pythonhosted.org/Markdown/,
# or replace the <textarea> with a visual TinyMCE editor:
# http://www.tinymce.com.
app.run("127.0.0.1", port=8080)