Moved common, translation, template, and url code out of util.py and into tools/...
[mediagoblin.git] / mediagoblin / app.py
CommitLineData
8e1e744d 1# GNU MediaGoblin -- federated, autonomous media hosting
12a100e4 2# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
e5572c60
ML
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
571198c9 17import os
31a8ff42
CAW
18import urllib
19
31a8ff42 20import routes
b61874b2 21from webob import Request, exc
31a8ff42 22
0c8a30e6 23from mediagoblin import routing, util, middleware
ae3bc7fa 24from mediagoblin.tools import translate, template
6e7ce8d1 25from mediagoblin.mg_globals import setup_globals
073b61fe 26from mediagoblin.init.celery import setup_celery_from_config
50854db0
WKG
27from mediagoblin.init import (get_jinja_loader, get_staticdirector,
28 setup_global_and_app_config, setup_workbench, setup_database,
0533f117 29 setup_storage, setup_beaker_cache)
90e342f9 30
31a8ff42 31
8e1e744d 32class MediaGoblinApp(object):
31a8ff42 33 """
3f5cf663
CAW
34 WSGI application of MediaGoblin
35
36 ... this is the heart of the program!
31a8ff42 37 """
3f5cf663
CAW
38 def __init__(self, config_path, setup_celery=True):
39 """
40 Initialize the application based on a configuration file.
41
42 Arguments:
43 - config_path: path to the configuration file we're opening.
44 - setup_celery: whether or not to setup celery during init.
45 (Note: setting 'celery_setup_elsewhere' also disables
46 setting up celery.)
47 """
48 ##############
49 # Setup config
50 ##############
51
52 # Open and setup the config
fe289be4 53 global_config, app_config = setup_global_and_app_config(config_path)
3f5cf663
CAW
54
55 ##########################################
56 # Setup other connections / useful objects
57 ##########################################
58
59 # Set up the database
3f4b5e4a 60 self.connection, self.db = setup_database()
ff94114c 61
5afdd7a1 62 # Get the template environment
42ef819c 63 self.template_loader = get_jinja_loader(
3f5cf663 64 app_config.get('user_template_path'))
0c8a30e6 65
5afdd7a1 66 # Set up storage systems
dccef262 67 self.public_store, self.queue_store = setup_storage()
5afdd7a1
CAW
68
69 # set up routing
0f63a944 70 self.routing = routing.get_mapper()
31a8ff42 71
582c4d5f 72 # set up staticdirector tool
c85c9dc7 73 self.staticdirector = get_staticdirector(app_config)
3f5cf663 74
0533f117
CAW
75 # set up caching
76 self.cache = setup_beaker_cache()
77
3f5cf663
CAW
78 # Setup celery, if appropriate
79 if setup_celery and not app_config.get('celery_setup_elsewhere'):
80 if os.environ.get('CELERY_ALWAYS_EAGER'):
81 setup_celery_from_config(
82 app_config, global_config,
83 force_celery_always_eager=True)
84 else:
85 setup_celery_from_config(app_config, global_config)
86
87 #######################################################
88 # Insert appropriate things into mediagoblin.mg_globals
89 #
df9809c2
CAW
90 # certain properties need to be accessed globally eg from
91 # validators, etc, which might not access to the request
92 # object.
3f5cf663
CAW
93 #######################################################
94
dccef262 95 setup_globals(app = self)
1fd97db3
CAW
96
97 # Workbench *currently* only used by celery, so this only
98 # matters in always eager mode :)
7664b4db 99 setup_workbench()
df9809c2 100
0c8a30e6
NY
101 # instantiate application middleware
102 self.middleware = [util.import_component(m)(self)
103 for m in middleware.ENABLED_MIDDLEWARE]
104
105
31a8ff42
CAW
106 def __call__(self, environ, start_response):
107 request = Request(environ)
0c8a30e6
NY
108
109 # pass the request through our middleware classes
110 for m in self.middleware:
111 response = m.process_request(request)
112 if response is not None:
113 return response(environ, start_response)
582c4d5f
CAW
114
115 ## Routing / controller loading stuff
0c8a30e6 116 path_info = request.path_info
0f63a944 117 route_match = self.routing.match(path_info)
31a8ff42 118
3d0557bf
CAW
119 ## Attach utilities to the request object
120 request.matchdict = route_match
121 request.urlgen = routes.URLGenerator(self.routing, environ)
122 # Do we really want to load this via middleware? Maybe?
123 request.session = request.environ['beaker.session']
124 # Attach self as request.app
125 # Also attach a few utilities from request.app for convenience?
126 request.app = self
ae3bc7fa 127 request.locale = translate.get_locale_from_request(request)
0c8a30e6 128
ae3bc7fa 129 request.template_env = template.get_jinja_env(
3d0557bf
CAW
130 self.template_loader, request.locale)
131 request.db = self.db
132 request.staticdirect = self.staticdirector
133
134 util.setup_user_in_request(request)
135
31a8ff42
CAW
136 # No matching page?
137 if route_match is None:
138 # Try to do see if we have a match with a trailing slash
139 # added and if so, redirect
140 if not path_info.endswith('/') \
141 and request.method == 'GET' \
0f63a944 142 and self.routing.match(path_info + '/'):
31a8ff42
CAW
143 new_path_info = path_info + '/'
144 if request.GET:
145 new_path_info = '%s?%s' % (
146 new_path_info, urllib.urlencode(request.GET))
1bb0fdf2 147 redirect = exc.HTTPFound(location=new_path_info)
31a8ff42
CAW
148 return request.get_response(redirect)(environ, start_response)
149
150 # Okay, no matches. 404 time!
3807e8e2 151 request.matchdict = {} # in case our template expects it
bae8f3d8 152 return util.render_404(request)(environ, start_response)
31a8ff42 153
cb8ea0fe 154 controller = util.import_component(route_match['controller'])
31a8ff42
CAW
155 request.start_response = start_response
156
0c8a30e6
NY
157 # get the response from the controller
158 response = controller(request)
159
160 # pass the response through the middleware
161 for m in self.middleware[::-1]:
162 m.process_response(request, response)
163
164 return response(environ, start_response)
31a8ff42
CAW
165
166
5784c4e9 167def paste_app_factory(global_config, **app_config):
3f5cf663 168 mgoblin_app = MediaGoblinApp(app_config['config'])
b61874b2 169
c4d71564 170 return mgoblin_app