Merge remote branch 'remotes/aaronw/feature410_markdown_bio'
[mediagoblin.git] / mediagoblin / app.py
index 0157748ce81c13d442bac2d3cb91fc5bf3291e1c..7a6a1f33c7c4610a7dcf32dc98d048a35d97d4fa 100644 (file)
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import os
 import urllib
 
 import routes
-import mongokit
 from webob import Request, exc
 
-from mediagoblin import routing, util, models, storage, staticdirect
-
-
-class Error(Exception): pass
-class ImproperlyConfigured(Error): pass
+from mediagoblin import routing, util, storage
+from mediagoblin.db.open import setup_connection_and_db_from_config
+from mediagoblin.db.util import MigrationManager
+from mediagoblin.mg_globals import setup_globals
+from mediagoblin.init.celery import setup_celery_from_config
+from mediagoblin.init import get_jinja_loader, get_staticdirector, \
+    setup_global_and_app_config, setup_workbench
 
 
 class MediaGoblinApp(object):
     """
-    Really basic wsgi app using routes and WebOb.
+    WSGI application of MediaGoblin
+
+    ... this is the heart of the program!
     """
-    def __init__(self, connection, database_path,
-                 public_store, queue_store,
-                 staticdirector,
-                 user_template_path=None):
+    def __init__(self, config_path, setup_celery=True):
+        """
+        Initialize the application based on a configuration file.
+
+        Arguments:
+         - config_path: path to the configuration file we're opening.
+         - setup_celery: whether or not to setup celery during init.
+           (Note: setting 'celery_setup_elsewhere' also disables
+           setting up celery.)
+        """
+        ##############
+        # Setup config
+        ##############
+
+        # Open and setup the config
+        global_config, app_config = setup_global_and_app_config(config_path)
+
+        ##########################################
+        # Setup other connections / useful objects
+        ##########################################
+
+        # Set up the database
+        self.connection, self.db = setup_connection_and_db_from_config(
+            app_config)
+
+        # Init the migration number if necessary
+        migration_manager = MigrationManager(self.db)
+        migration_manager.install_migration_version_if_missing()
+
+        # Tiny hack to warn user if our migration is out of date
+        if not migration_manager.database_at_latest_migration():
+            print (
+                "*WARNING:* Your migrations are out of date, "
+                "maybe run ./bin/gmg migrate?")
+
         # Get the template environment
-        self.template_env = util.get_jinja_env(user_template_path)
+        self.template_loader = get_jinja_loader(
+            app_config.get('user_template_path'))
         
         # Set up storage systems
-        self.public_store = public_store
-        self.queue_store = queue_store
-
-        # Set up database
-        self.connection = connection
-        self.db = connection[database_path]
-        models.register_models(connection)
+        self.public_store = storage.storage_system_from_config(
+            app_config, 'publicstore')
+        self.queue_store = storage.storage_system_from_config(
+            app_config, 'queuestore')
 
         # set up routing
         self.routing = routing.get_mapper()
 
         # set up staticdirector tool
-        self.staticdirector = staticdirector
+        self.staticdirector = get_staticdirector(app_config)
+
+        # Setup celery, if appropriate
+        if setup_celery and not app_config.get('celery_setup_elsewhere'):
+            if os.environ.get('CELERY_ALWAYS_EAGER'):
+                setup_celery_from_config(
+                    app_config, global_config,
+                    force_celery_always_eager=True)
+            else:
+                setup_celery_from_config(app_config, global_config)
+
+        #######################################################
+        # Insert appropriate things into mediagoblin.mg_globals
+        #
+        # certain properties need to be accessed globally eg from
+        # validators, etc, which might not access to the request
+        # object.
+        #######################################################
+
+        setup_globals(
+            app=self,
+            db_connection=self.connection,
+            database=self.db,
+            public_store=self.public_store,
+            queue_store=self.queue_store)
+
+        # Workbench *currently* only used by celery, so this only
+        # matters in always eager mode :)
+        setup_workbench()
 
     def __call__(self, environ, start_response):
         request = Request(environ)
@@ -71,7 +132,7 @@ class MediaGoblinApp(object):
                 if request.GET:
                     new_path_info = '%s?%s' % (
                         new_path_info, urllib.urlencode(request.GET))
-                redirect = exc.HTTPTemporaryRedirect(location=new_path_info)
+                redirect = exc.HTTPFound(location=new_path_info)
                 return request.get_response(redirect)(environ, start_response)
 
             # Okay, no matches.  404 time!
@@ -85,44 +146,22 @@ class MediaGoblinApp(object):
         request.urlgen = routes.URLGenerator(self.routing, environ)
         # Do we really want to load this via middleware?  Maybe?
         request.session = request.environ['beaker.session']
-        util.setup_user_in_request(request)
         # Attach self as request.app
         # Also attach a few utilities from request.app for convenience?
         request.app = self
-        request.template_env = self.template_env
+        request.locale = util.get_locale_from_request(request)
+            
+        request.template_env = util.get_jinja_env(
+            self.template_loader, request.locale)
         request.db = self.db
         request.staticdirect = self.staticdirector
 
+        util.setup_user_in_request(request)
+
         return controller(request)(environ, start_response)
 
 
-def paste_app_factory(global_config, **kw):
-    # Get the database connection
-    connection = mongokit.Connection(
-        kw.get('db_host'), kw.get('db_port'))
-
-    # Set up the storage systems.
-    public_store = storage.storage_system_from_paste_config(
-        kw, 'publicstore')
-    queue_store = storage.storage_system_from_paste_config(
-        kw, 'queuestore')
-
-    # Set up the staticdirect system
-    if kw.has_key('direct_remote_path'):
-        staticdirector = staticdirect.RemoteStaticDirect(
-            kw['direct_remote_path'].strip())
-    elif kw.has_key('direct_remote_paths'):
-        staticdirector = staticdirect.MultiRemoteStaticDirect(
-            dict([line.strip().split(' ', 1)
-                  for line in kw['direct_remote_paths'].strip().splitlines()]))
-    else:
-        raise ImproperlyConfigured(
-            "One of direct_remote_path or direct_remote_paths must be provided")
-
-    mgoblin_app = MediaGoblinApp(
-        connection, kw.get('db_name', 'mediagoblin'),
-        public_store=public_store, queue_store=queue_store,
-        staticdirector=staticdirector,
-        user_template_path=kw.get('local_templates'))
+def paste_app_factory(global_config, **app_config):
+    mgoblin_app = MediaGoblinApp(app_config['config'])
 
     return mgoblin_app