thirdparty/google_appengine/lib/webob/docs/wiki-example-code/example.py
changeset 109 620f9b141567
equal deleted inserted replaced
108:261778de26ff 109:620f9b141567
       
     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)
       
    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'