-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
application.py
94 lines (77 loc) · 3.42 KB
/
application.py
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
"""Implements the wiki WSGI application which dispatches requests to
specific wiki pages and actions.
"""
from os import path
from sqlalchemy import create_engine
from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.utils import redirect
from werkzeug.wsgi import ClosingIterator
from . import actions
from .database import metadata
from .database import session
from .specialpages import page_not_found
from .specialpages import pages
from .utils import href
from .utils import local
from .utils import local_manager
from .utils import Request
#: path to shared data
SHARED_DATA = path.join(path.dirname(__file__), "shared")
class SimpleWiki:
"""
Our central WSGI application.
"""
def __init__(self, database_uri):
self.database_engine = create_engine(database_uri)
# apply our middlewares. we apply the middlewars *inside* the
# application and not outside of it so that we never lose the
# reference to the `SimpleWiki` object.
self._dispatch = SharedDataMiddleware(
self.dispatch_request, {"/_shared": SHARED_DATA}
)
# free the context locals at the end of the request
self._dispatch = local_manager.make_middleware(self._dispatch)
def init_database(self):
"""Called from the management script to generate the db."""
metadata.create_all(bind=self.database_engine)
def bind_to_context(self):
"""
Useful for the shell. Binds the application to the current active
context. It's automatically called by the shell command.
"""
local.application = self
def dispatch_request(self, environ, start_response):
"""Dispatch an incoming request."""
# set up all the stuff we want to have for this request. That is
# creating a request object, propagating the application to the
# current context and instantiating the database session.
self.bind_to_context()
request = Request(environ)
request.bind_to_context()
# get the current action from the url and normalize the page name
# which is just the request path
action_name = request.args.get("action") or "show"
page_name = "_".join([x for x in request.path.strip("/").split() if x])
# redirect to the Main_Page if the user requested the index
if not page_name:
response = redirect(href("Main_Page"))
# check special pages
elif page_name.startswith("Special:"):
if page_name[8:] not in pages:
response = page_not_found(request, page_name)
else:
response = pages[page_name[8:]](request)
# get the callback function for the requested action from the
# action module. It's "on_" + the action name. If it doesn't
# exists call the missing_action method from the same module.
else:
action = getattr(actions, f"on_{action_name}", None)
if action is None:
response = actions.missing_action(request, action_name)
else:
response = action(request, page_name)
# make sure the session is removed properly
return ClosingIterator(response(environ, start_response), session.remove)
def __call__(self, environ, start_response):
"""Just forward a WSGI call to the first internal middleware."""
return self._dispatch(environ, start_response)