Issue #362 - Updated `mediagoblin.user_pages.views` to handle new "Simple comments...
[mediagoblin.git] / mediagoblin / app.py
CommitLineData
8e1e744d 1# GNU MediaGoblin -- federated, autonomous media hosting
e5572c60
ML
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
571198c9 17import os
31a8ff42
CAW
18import urllib
19
31a8ff42 20import routes
b61874b2 21from webob import Request, exc
31a8ff42 22
0f18ed8f 23from mediagoblin import routing, util, storage, staticdirect
3f5cf663
CAW
24from mediagoblin.config import (
25 read_mediagoblin_config, generate_validation_report)
a67fec81 26from mediagoblin.db.open import setup_connection_and_db_from_config
6e7ce8d1 27from mediagoblin.mg_globals import setup_globals
5784c4e9 28from mediagoblin.celery_setup import setup_celery_from_config
3f5cf663 29from mediagoblin.workbench import WorkbenchManager
31a8ff42
CAW
30
31
32class Error(Exception): pass
33class ImproperlyConfigured(Error): pass
34
35
8e1e744d 36class MediaGoblinApp(object):
31a8ff42 37 """
3f5cf663
CAW
38 WSGI application of MediaGoblin
39
40 ... this is the heart of the program!
31a8ff42 41 """
3f5cf663
CAW
42 def __init__(self, config_path, setup_celery=True):
43 """
44 Initialize the application based on a configuration file.
45
46 Arguments:
47 - config_path: path to the configuration file we're opening.
48 - setup_celery: whether or not to setup celery during init.
49 (Note: setting 'celery_setup_elsewhere' also disables
50 setting up celery.)
51 """
52 ##############
53 # Setup config
54 ##############
55
56 # Open and setup the config
57 global_config, validation_result = read_mediagoblin_config(config_path)
58 app_config = global_config['mediagoblin']
59 # report errors if necessary
60 validation_report = generate_validation_report(
61 global_config, validation_result)
62 if validation_report:
63 raise ImproperlyConfigured(validation_report)
64
65 ##########################################
66 # Setup other connections / useful objects
67 ##########################################
68
69 # Set up the database
70 self.connection, self.db = setup_connection_and_db_from_config(
71 app_config)
72
5afdd7a1 73 # Get the template environment
3f5cf663
CAW
74 self.template_loader = util.get_jinja_loader(
75 app_config.get('user_template_path'))
5afdd7a1
CAW
76
77 # Set up storage systems
3c7d11ff 78 self.public_store = storage.storage_system_from_config(
3f5cf663 79 app_config, 'publicstore')
3c7d11ff 80 self.queue_store = storage.storage_system_from_config(
3f5cf663 81 app_config, 'queuestore')
5afdd7a1
CAW
82
83 # set up routing
0f63a944 84 self.routing = routing.get_mapper()
31a8ff42 85
582c4d5f 86 # set up staticdirector tool
3f5cf663
CAW
87 if app_config.has_key('direct_remote_path'):
88 self.staticdirector = staticdirect.RemoteStaticDirect(
89 app_config['direct_remote_path'].strip())
90 elif app_config.has_key('direct_remote_paths'):
91 direct_remote_path_lines = app_config[
92 'direct_remote_paths'].strip().splitlines()
93 self.staticdirector = staticdirect.MultiRemoteStaticDirect(
94 dict([line.strip().split(' ', 1)
95 for line in direct_remote_path_lines]))
96 else:
97 raise ImproperlyConfigured(
98 "One of direct_remote_path or "
99 "direct_remote_paths must be provided")
100
101 # Setup celery, if appropriate
102 if setup_celery and not app_config.get('celery_setup_elsewhere'):
103 if os.environ.get('CELERY_ALWAYS_EAGER'):
104 setup_celery_from_config(
105 app_config, global_config,
106 force_celery_always_eager=True)
107 else:
108 setup_celery_from_config(app_config, global_config)
109
110 #######################################################
111 # Insert appropriate things into mediagoblin.mg_globals
112 #
df9809c2
CAW
113 # certain properties need to be accessed globally eg from
114 # validators, etc, which might not access to the request
115 # object.
3f5cf663
CAW
116 #######################################################
117
df9809c2 118 setup_globals(
3f5cf663
CAW
119 app_config=app_config,
120 global_config=global_config,
121
122 # TODO: No need to set these two up as globals, we could
123 # just read them out of mg_globals.app_config
124 email_sender_address=app_config['email_sender_address'],
125 email_debug_mode=app_config['email_debug_mode'],
126
127 # Actual, useful to everyone objects
becb77ee 128 app=self,
3f5cf663 129 db_connection=self.connection,
df9809c2
CAW
130 database=self.db,
131 public_store=self.public_store,
7ecc58cc 132 queue_store=self.queue_store,
3f5cf663 133 workbench_manager=WorkbenchManager(app_config['workbench_path']))
df9809c2 134
31a8ff42
CAW
135 def __call__(self, environ, start_response):
136 request = Request(environ)
137 path_info = request.path_info
582c4d5f
CAW
138
139 ## Routing / controller loading stuff
0f63a944 140 route_match = self.routing.match(path_info)
31a8ff42
CAW
141
142 # No matching page?
143 if route_match is None:
144 # Try to do see if we have a match with a trailing slash
145 # added and if so, redirect
146 if not path_info.endswith('/') \
147 and request.method == 'GET' \
0f63a944 148 and self.routing.match(path_info + '/'):
31a8ff42
CAW
149 new_path_info = path_info + '/'
150 if request.GET:
151 new_path_info = '%s?%s' % (
152 new_path_info, urllib.urlencode(request.GET))
1bb0fdf2 153 redirect = exc.HTTPFound(location=new_path_info)
31a8ff42
CAW
154 return request.get_response(redirect)(environ, start_response)
155
156 # Okay, no matches. 404 time!
157 return exc.HTTPNotFound()(environ, start_response)
158
cb8ea0fe 159 controller = util.import_component(route_match['controller'])
31a8ff42
CAW
160 request.start_response = start_response
161
582c4d5f 162 ## Attach utilities to the request object
31a8ff42 163 request.matchdict = route_match
0f63a944 164 request.urlgen = routes.URLGenerator(self.routing, environ)
7846e406 165 # Do we really want to load this via middleware? Maybe?
14ba9383 166 request.session = request.environ['beaker.session']
0dd65945
CAW
167 # Attach self as request.app
168 # Also attach a few utilities from request.app for convenience?
169 request.app = self
0e0e3d9a
CAW
170 request.locale = util.get_locale_from_request(request)
171
172 request.template_env = util.get_jinja_env(
173 self.template_loader, request.locale)
0dd65945
CAW
174 request.db = self.db
175 request.staticdirect = self.staticdirector
31a8ff42 176
ddff7cce
CAW
177 util.setup_user_in_request(request)
178
31a8ff42
CAW
179 return controller(request)(environ, start_response)
180
181
5784c4e9 182def paste_app_factory(global_config, **app_config):
3f5cf663 183 mgoblin_app = MediaGoblinApp(app_config['config'])
b61874b2 184
c4d71564 185 return mgoblin_app