Commit dummy_settings_module, of course.
[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
31a8ff42
CAW
17import urllib
18
31a8ff42 19import routes
2b4e236a 20import mongokit
b61874b2 21from webob import Request, exc
31a8ff42 22
582c4d5f 23from mediagoblin import routing, util, models, storage, staticdirect
df9809c2 24from mediagoblin.globals import setup_globals
31a8ff42
CAW
25
26
27class Error(Exception): pass
28class ImproperlyConfigured(Error): pass
29
30
8e1e744d 31class MediaGoblinApp(object):
31a8ff42
CAW
32 """
33 Really basic wsgi app using routes and WebOb.
34 """
5afdd7a1
CAW
35 def __init__(self, connection, database_path,
36 public_store, queue_store,
582c4d5f 37 staticdirector,
5afdd7a1
CAW
38 user_template_path=None):
39 # Get the template environment
31a8ff42 40 self.template_env = util.get_jinja_env(user_template_path)
5afdd7a1
CAW
41
42 # Set up storage systems
43 self.public_store = public_store
44 self.queue_store = queue_store
45
46 # Set up database
2b4e236a 47 self.connection = connection
65d7374c 48 self.db = connection[database_path]
5afdd7a1
CAW
49 models.register_models(connection)
50
51 # set up routing
0f63a944 52 self.routing = routing.get_mapper()
31a8ff42 53
582c4d5f
CAW
54 # set up staticdirector tool
55 self.staticdirector = staticdirector
2b4e236a 56
df9809c2
CAW
57 # certain properties need to be accessed globally eg from
58 # validators, etc, which might not access to the request
59 # object.
60 setup_globals(
61 db_connection=connection,
62 database=self.db,
63 public_store=self.public_store,
64 queue_store=self.queue_store)
65
31a8ff42
CAW
66 def __call__(self, environ, start_response):
67 request = Request(environ)
68 path_info = request.path_info
582c4d5f
CAW
69
70 ## Routing / controller loading stuff
0f63a944 71 route_match = self.routing.match(path_info)
31a8ff42
CAW
72
73 # No matching page?
74 if route_match is None:
75 # Try to do see if we have a match with a trailing slash
76 # added and if so, redirect
77 if not path_info.endswith('/') \
78 and request.method == 'GET' \
0f63a944 79 and self.routing.match(path_info + '/'):
31a8ff42
CAW
80 new_path_info = path_info + '/'
81 if request.GET:
82 new_path_info = '%s?%s' % (
83 new_path_info, urllib.urlencode(request.GET))
84 redirect = exc.HTTPTemporaryRedirect(location=new_path_info)
85 return request.get_response(redirect)(environ, start_response)
86
87 # Okay, no matches. 404 time!
88 return exc.HTTPNotFound()(environ, start_response)
89
cb8ea0fe 90 controller = util.import_component(route_match['controller'])
31a8ff42
CAW
91 request.start_response = start_response
92
582c4d5f 93 ## Attach utilities to the request object
31a8ff42 94 request.matchdict = route_match
0f63a944 95 request.urlgen = routes.URLGenerator(self.routing, environ)
7846e406 96 # Do we really want to load this via middleware? Maybe?
14ba9383 97 request.session = request.environ['beaker.session']
0dd65945
CAW
98 # Attach self as request.app
99 # Also attach a few utilities from request.app for convenience?
100 request.app = self
101 request.template_env = self.template_env
102 request.db = self.db
103 request.staticdirect = self.staticdirector
31a8ff42 104
ddff7cce
CAW
105 util.setup_user_in_request(request)
106
31a8ff42
CAW
107 return controller(request)(environ, start_response)
108
109
110def paste_app_factory(global_config, **kw):
cb8ea0fe 111 # Get the database connection
2b4e236a
CAW
112 connection = mongokit.Connection(
113 kw.get('db_host'), kw.get('db_port'))
73e0dbcc 114
cb8ea0fe 115 # Set up the storage systems.
5afdd7a1
CAW
116 public_store = storage.storage_system_from_paste_config(
117 kw, 'publicstore')
118 queue_store = storage.storage_system_from_paste_config(
119 kw, 'queuestore')
120
582c4d5f
CAW
121 # Set up the staticdirect system
122 if kw.has_key('direct_remote_path'):
123 staticdirector = staticdirect.RemoteStaticDirect(
124 kw['direct_remote_path'].strip())
125 elif kw.has_key('direct_remote_paths'):
126 staticdirector = staticdirect.MultiRemoteStaticDirect(
127 dict([line.strip().split(' ', 1)
128 for line in kw['direct_remote_paths'].strip().splitlines()]))
129 else:
130 raise ImproperlyConfigured(
131 "One of direct_remote_path or direct_remote_paths must be provided")
132
8e1e744d 133 mgoblin_app = MediaGoblinApp(
2b4e236a 134 connection, kw.get('db_name', 'mediagoblin'),
5afdd7a1 135 public_store=public_store, queue_store=queue_store,
582c4d5f 136 staticdirector=staticdirector,
2b4e236a 137 user_template_path=kw.get('local_templates'))
b61874b2 138
c4d71564 139 return mgoblin_app