0ef670d7f54c87cc6c4e5dbf855a9f141508226d
[mediagoblin.git] / mediagoblin / app.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011 Free Software Foundation, Inc
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
17 import os
18 import urllib
19
20 import routes
21 from webob import Request, exc
22
23 from mediagoblin import routing, util, storage
24 from mediagoblin.db.open import setup_connection_and_db_from_config
25 from mediagoblin.mg_globals import setup_globals
26 from mediagoblin.init.celery import setup_celery_from_config
27 from mediagoblin.init import get_jinja_loader, get_staticdirector, \
28 setup_global_and_app_config
29 from mediagoblin.workbench import WorkbenchManager
30
31
32 class MediaGoblinApp(object):
33 """
34 WSGI application of MediaGoblin
35
36 ... this is the heart of the program!
37 """
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
53 global_config, app_config = setup_global_and_app_config(config_path)
54
55 ##########################################
56 # Setup other connections / useful objects
57 ##########################################
58
59 # Set up the database
60 self.connection, self.db = setup_connection_and_db_from_config(
61 app_config)
62
63 # Get the template environment
64 self.template_loader = get_jinja_loader(
65 app_config.get('user_template_path'))
66
67 # Set up storage systems
68 self.public_store = storage.storage_system_from_config(
69 app_config, 'publicstore')
70 self.queue_store = storage.storage_system_from_config(
71 app_config, 'queuestore')
72
73 # set up routing
74 self.routing = routing.get_mapper()
75
76 # set up staticdirector tool
77 self.staticdirector = get_staticdirector(app_config)
78
79 # Setup celery, if appropriate
80 if setup_celery and not app_config.get('celery_setup_elsewhere'):
81 if os.environ.get('CELERY_ALWAYS_EAGER'):
82 setup_celery_from_config(
83 app_config, global_config,
84 force_celery_always_eager=True)
85 else:
86 setup_celery_from_config(app_config, global_config)
87
88 #######################################################
89 # Insert appropriate things into mediagoblin.mg_globals
90 #
91 # certain properties need to be accessed globally eg from
92 # validators, etc, which might not access to the request
93 # object.
94 #######################################################
95
96 setup_globals(
97 app_config=app_config,
98 global_config=global_config,
99
100 # TODO: No need to set these two up as globals, we could
101 # just read them out of mg_globals.app_config
102 email_sender_address=app_config['email_sender_address'],
103 email_debug_mode=app_config['email_debug_mode'],
104
105 # Actual, useful to everyone objects
106 app=self,
107 db_connection=self.connection,
108 database=self.db,
109 public_store=self.public_store,
110 queue_store=self.queue_store,
111 workbench_manager=WorkbenchManager(app_config['workbench_path']))
112
113 def __call__(self, environ, start_response):
114 request = Request(environ)
115 path_info = request.path_info
116
117 ## Routing / controller loading stuff
118 route_match = self.routing.match(path_info)
119
120 # No matching page?
121 if route_match is None:
122 # Try to do see if we have a match with a trailing slash
123 # added and if so, redirect
124 if not path_info.endswith('/') \
125 and request.method == 'GET' \
126 and self.routing.match(path_info + '/'):
127 new_path_info = path_info + '/'
128 if request.GET:
129 new_path_info = '%s?%s' % (
130 new_path_info, urllib.urlencode(request.GET))
131 redirect = exc.HTTPFound(location=new_path_info)
132 return request.get_response(redirect)(environ, start_response)
133
134 # Okay, no matches. 404 time!
135 return exc.HTTPNotFound()(environ, start_response)
136
137 controller = util.import_component(route_match['controller'])
138 request.start_response = start_response
139
140 ## Attach utilities to the request object
141 request.matchdict = route_match
142 request.urlgen = routes.URLGenerator(self.routing, environ)
143 # Do we really want to load this via middleware? Maybe?
144 request.session = request.environ['beaker.session']
145 # Attach self as request.app
146 # Also attach a few utilities from request.app for convenience?
147 request.app = self
148 request.locale = util.get_locale_from_request(request)
149
150 request.template_env = util.get_jinja_env(
151 self.template_loader, request.locale)
152 request.db = self.db
153 request.staticdirect = self.staticdirector
154
155 util.setup_user_in_request(request)
156
157 return controller(request)(environ, start_response)
158
159
160 def paste_app_factory(global_config, **app_config):
161 mgoblin_app = MediaGoblinApp(app_config['config'])
162
163 return mgoblin_app