File: wiki.py

package info (click to toggle)
python-pattern 2.6%2Bgit20150109-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 78,672 kB
  • sloc: python: 53,865; xml: 11,965; ansic: 2,318; makefile: 94
file content (130 lines) | stat: -rw-r--r-- 4,579 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import os, sys; sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))

from pattern.server import App, template, threadsafe

from codecs 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)