~ubuntu-branches/ubuntu/lucid/python-webob/lucid

« back to all changes in this revision

Viewing changes to docs/wiki-example-code/example.py

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ożarowski
  • Date: 2010-01-13 22:07:40 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100113220740-51qlp569n69lqn88
Tags: 0.9.7.1-1
* New upstream release
* 01-autoclass-autodata patch removed, no longer needed
* Add add_docs_conf.patch (missing in upstream tarball)
* Bump Standards-Version to 3.8.3 (no changes needed)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import os
2
 
import re
3
 
from webob import Request, Response
4
 
from webob import exc
5
 
from tempita import HTMLTemplate
6
 
 
7
 
VIEW_TEMPLATE = HTMLTemplate("""\
8
 
<html>
9
 
 <head>
10
 
  <title>{{page.title}}</title>
11
 
 </head>
12
 
 <body>
13
 
<h1>{{page.title}}</h1>
14
 
{{if message}}
15
 
<div style="background-color: #99f">{{message}}</div>
16
 
{{endif}}
17
 
 
18
 
<div>{{page.content|html}}</div>
19
 
 
20
 
<hr>
21
 
<a href="{{req.url}}?action=edit">Edit</a>
22
 
 </body>
23
 
</html>
24
 
""")
25
 
 
26
 
EDIT_TEMPLATE = HTMLTemplate("""\
27
 
<html>
28
 
 <head>
29
 
  <title>Edit: {{page.title}}</title>
30
 
 </head>
31
 
 <body>
32
 
{{if page.exists}}
33
 
<h1>Edit: {{page.title}}</h1>
34
 
{{else}}
35
 
<h1>Create: {{page.title}}</h1>
36
 
{{endif}}
37
 
 
38
 
<form action="{{req.path_url}}" method="POST">
39
 
 <input type="hidden" name="mtime" value="{{page.mtime}}">
40
 
 Title: <input type="text" name="title" style="width: 70%" value="{{page.title}}"><br>
41
 
 Content: <input type="submit" value="Save"> 
42
 
 <a href="{{req.path_url}}">Cancel</a>
43
 
   <br>
44
 
 <textarea name="content" style="width: 100%; height: 75%" rows="40">{{page.content}}</textarea>
45
 
   <br>
46
 
 <input type="submit" value="Save">
47
 
 <a href="{{req.path_url}}">Cancel</a>
48
 
</form>
49
 
</body></html>
50
 
""")
51
 
 
52
 
class WikiApp(object):
53
 
 
54
 
    view_template = VIEW_TEMPLATE
55
 
    edit_template = EDIT_TEMPLATE
56
 
 
57
 
    def __init__(self, storage_dir):
58
 
        self.storage_dir = os.path.abspath(os.path.normpath(storage_dir))
59
 
 
60
 
    def __call__(self, environ, start_response):
61
 
        req = Request(environ)
62
 
        action = req.params.get('action', 'view')
63
 
        page = self.get_page(req.path_info)
64
 
        try:
65
 
            try:
66
 
                meth = getattr(self, 'action_%s_%s' % (action, req.method))
67
 
            except AttributeError:
68
 
                raise exc.HTTPBadRequest('No such action %r' % action).exception
69
 
            resp = meth(req, page)
70
 
        except exc.HTTPException, e:
71
 
            resp = e
72
 
        return resp(environ, start_response)
73
 
 
74
 
    def get_page(self, path):
75
 
        path = path.lstrip('/')
76
 
        if not path:
77
 
            path = 'index'
78
 
        path = os.path.join(self.storage_dir, path)
79
 
        path = os.path.normpath(path)
80
 
        if path.endswith('/'):
81
 
            path += 'index'
82
 
        if not path.startswith(self.storage_dir):
83
 
            raise exc.HTTPBadRequest("Bad path").exception
84
 
        path += '.html'
85
 
        return Page(path)
86
 
 
87
 
    def action_view_GET(self, req, page):
88
 
        if not page.exists:
89
 
            return exc.HTTPTemporaryRedirect(
90
 
                location=req.url + '?action=edit')
91
 
        if req.cookies.get('message'):
92
 
            message = req.cookies['message']
93
 
        else:
94
 
            message = None
95
 
        text = self.view_template.substitute(
96
 
            page=page, req=req, message=message)
97
 
        resp = Response(text)
98
 
        if message:
99
 
            resp.delete_cookie('message')
100
 
        else:
101
 
            resp.last_modified = page.mtime
102
 
            resp.conditional_response = True
103
 
        return resp
104
 
 
105
 
    def action_view_POST(self, req, page):
106
 
        submit_mtime = int(req.params.get('mtime') or '0') or None
107
 
        if page.mtime != submit_mtime:
108
 
            return exc.HTTPPreconditionFailed(
109
 
                "The page has been updated since you started editing it")
110
 
        page.set(
111
 
            title=req.params['title'],
112
 
            content=req.params['content'])
113
 
        resp = exc.HTTPSeeOther(
114
 
            location=req.path_url)
115
 
        resp.set_cookie('message', 'Page updated')
116
 
        return resp
117
 
 
118
 
    def action_edit_GET(self, req, page):
119
 
        text = self.edit_template.substitute(
120
 
            page=page, req=req)
121
 
        return Response(text)
122
 
 
123
 
class Page(object):
124
 
    def __init__(self, filename):
125
 
        self.filename = filename
126
 
 
127
 
    @property
128
 
    def exists(self):
129
 
        return os.path.exists(self.filename)
130
 
 
131
 
    @property
132
 
    def title(self):
133
 
        if not self.exists:
134
 
            # we need to guess the title
135
 
            basename = os.path.splitext(os.path.basename(self.filename))[0]
136
 
            basename = re.sub(r'[_-]', ' ', basename)
137
 
            return basename.capitalize()
138
 
        content = self.full_content
139
 
        match = re.search(r'<title>(.*?)</title>', content, re.I|re.S)
140
 
        return match.group(1)
141
 
    
142
 
    @property
143
 
    def full_content(self):
144
 
        f = open(self.filename, 'rb')
145
 
        try:
146
 
            return f.read()
147
 
        finally:
148
 
            f.close()
149
 
    
150
 
    @property
151
 
    def content(self):
152
 
        if not self.exists:
153
 
            return ''
154
 
        content = self.full_content
155
 
        match = re.search(r'<body[^>]*>(.*?)</body>', content, re.I|re.S)
156
 
        return match.group(1)
157
 
 
158
 
    @property
159
 
    def mtime(self):
160
 
        if not self.exists:
161
 
            return None
162
 
        else:
163
 
            return os.stat(self.filename).st_mtime
164
 
 
165
 
    def set(self, title, content):
166
 
        dir = os.path.dirname(self.filename)
167
 
        if not os.path.exists(dir):
168
 
            os.makedirs(dir)
169
 
        new_content = """<html><head><title>%s</title></head><body>%s</body></html>""" % (
170
 
            title, content)
171
 
        f = open(self.filename, 'wb')
172
 
        f.write(new_content)
173
 
        f.close()
174
 
 
175
 
if __name__ == '__main__':
176
 
    import optparse
177
 
    parser = optparse.OptionParser(
178
 
        usage='%prog --port=PORT'
179
 
        )
180
 
    parser.add_option(
181
 
        '-p', '--port',
182
 
        default='8080',
183
 
        dest='port',
184
 
        type='int',
185
 
        help='Port to serve on (default 8080)')
186
 
    parser.add_option(
187
 
        '--wiki-data',
188
 
        default='./wiki',
189
 
        dest='wiki_data',
190
 
        help='Place to put wiki data into (default ./wiki/)')
191
 
    options, args = parser.parse_args()
192
 
    print 'Writing wiki pages to %s' % options.wiki_data
193
 
    app = WikiApp(options.wiki_data)
194
 
    from wsgiref.simple_server import make_server
195
 
    httpd = make_server('localhost', options.port, app)
196
 
    print 'Serving on http://localhost:%s' % options.port
197
 
    try:
198
 
        httpd.serve_forever()
199
 
    except KeyboardInterrupt:
200
 
        print '^C'