| 36 | | self.auth_backend = None |
|---|
| 37 | | |
|---|
| 38 | | pass |
|---|
| | 54 | self.auth_backend = None |
|---|
| | 55 | self.serve_static = True |
|---|
| | 56 | |
|---|
| | 57 | def setup_paths(self): |
|---|
| | 58 | root = os.path.dirname(os.path.abspath( |
|---|
| | 59 | self.package.__file__)) |
|---|
| | 60 | self.paths = dict(root=root, |
|---|
| | 61 | controllers=os.path.join(root, 'controllers'), |
|---|
| | 62 | static_files=os.path.join(root, 'public'), |
|---|
| | 63 | templates=[os.path.join(root, 'templates')]) |
|---|
| | 64 | |
|---|
| | 65 | def init_config(self, global_conf, app_conf): |
|---|
| | 66 | # Initialize config with the basic options |
|---|
| | 67 | config.init_app(global_conf, app_conf, |
|---|
| | 68 | package=self.package.__name__, |
|---|
| | 69 | paths=self.paths) |
|---|
| | 70 | |
|---|
| | 71 | def setup_routes(self): |
|---|
| | 72 | # This setups up a set of default route that enables a standard |
|---|
| | 73 | # TG2 style object dispatch. Fell free to overide it with |
|---|
| | 74 | # custom routes. |
|---|
| | 75 | map = Mapper(directory=config['pylons.paths']['controllers'], |
|---|
| | 76 | always_scan=config['debug']) |
|---|
| | 77 | |
|---|
| | 78 | # Setup a default route for the error controller: |
|---|
| | 79 | map.connect('error/:action/:id', controller='error') |
|---|
| | 80 | |
|---|
| | 81 | ## Replace the next line with your overides. Overides should generally come |
|---|
| | 82 | ## bevore the default route defined below |
|---|
| | 83 | # map.connect('overide/url/here', controller='mycontrller', action='send_stuff') |
|---|
| | 84 | |
|---|
| | 85 | # This route connects your root controller, it should be after |
|---|
| | 86 | # more specific routes since the wildcard will pick up everything... |
|---|
| | 87 | map.connect('*url', controller='root', action='routes_placeholder') |
|---|
| | 88 | |
|---|
| | 89 | config['routes.map'] = map |
|---|
| | 90 | |
|---|
| | 91 | def setup_helpers_and_globals(self): |
|---|
| | 92 | config['pylons.app_globals'] = self.package.lib.app_globals.Globals() |
|---|
| | 93 | config['pylons.h'] = self.package.lib.helpers |
|---|
| | 94 | |
|---|
| | 95 | def setup_sa_auth_backend(): |
|---|
| | 96 | defaults = {'user_class':self.model.User, |
|---|
| | 97 | 'group_class':self.model.Group, |
|---|
| | 98 | 'permission_class':self.model.Permission, |
|---|
| | 99 | 'users_table':'tg_user', |
|---|
| | 100 | 'groups_table':'tg_group', |
|---|
| | 101 | 'permissions_table':'tg_permission', |
|---|
| | 102 | 'password_encryption_method':'sha1', |
|---|
| | 103 | 'form_plugin': None |
|---|
| | 104 | } |
|---|
| | 105 | if config['sa_auth']: |
|---|
| | 106 | config['sa_auth'] = defaults.update(config['sa_auth']) |
|---|
| | 107 | if not config['sa_auth']: |
|---|
| | 108 | config['sa_auth'] = defaults |
|---|
| | 109 | |
|---|
| | 110 | def setup_mako_renderer(self): |
|---|
| | 111 | # Create the Mako TemplateLookup, with the default auto-escaping |
|---|
| | 112 | from mako.lookup import TemplateLookup |
|---|
| | 113 | from tg.render import render_mako |
|---|
| | 114 | |
|---|
| | 115 | config['pylons.app_globals'].mako_lookup = TemplateLookup( |
|---|
| | 116 | directories=self.paths['templates'], |
|---|
| | 117 | module_directory=os.path.join(app_conf['cache_dir'], 'templates'), |
|---|
| | 118 | input_encoding='utf-8', output_encoding='utf-8', |
|---|
| | 119 | imports=['from webhelpers.html import escape'], |
|---|
| | 120 | default_filters=['escape']) |
|---|
| | 121 | config['pylons.app_globals'].renderer_functions = render_mako |
|---|
| | 122 | |
|---|
| | 123 | def setup_genshi_renderer(self): |
|---|
| | 124 | # Create the Genshi TemplateLoader |
|---|
| | 125 | from genshi.template import TemplateLoader |
|---|
| | 126 | from tg.render import render_genshi |
|---|
| | 127 | |
|---|
| | 128 | def template_loaded(template): |
|---|
| | 129 | "Plug-in our i18n function to Genshi." |
|---|
| | 130 | genshi.template.filters.insert(0, Translator(ugettext)) |
|---|
| | 131 | |
|---|
| | 132 | config['pylons.app_globals'].genshi_loader = TemplateLoader( |
|---|
| | 133 | self.paths['templates'], auto_reload=True) |
|---|
| | 134 | |
|---|
| | 135 | config['pylons.app_globals'].renderer_functions = render_genshi |
|---|
| | 136 | |
|---|
| | 137 | def setup_jinja_renderer(self): |
|---|
| | 138 | # Create the Jinja Environment |
|---|
| | 139 | from jinja import ChoiceLoader, Environment, FileSystemLoader |
|---|
| | 140 | from tg.render import render_jinja |
|---|
| | 141 | |
|---|
| | 142 | config['pylons.app_globals'].jinja_env = Environment(loader=ChoiceLoader( |
|---|
| | 143 | [FileSystemLoader(path) for path in self.paths['templates']])) |
|---|
| | 144 | # Jinja's unable to request c's attributes without strict_c |
|---|
| | 145 | config['pylons.strict_c'] = True |
|---|
| | 146 | |
|---|
| | 147 | config['pylons.app_globals'].renderer_functionsloa = render_jinja |
|---|
| | 148 | |
|---|
| | 149 | def setup_default_renderer(self): |
|---|
| | 150 | #This is specific to buffet, will not be needed later |
|---|
| | 151 | config['buffet.template_engines'].pop() |
|---|
| | 152 | template_location = '%s.templates' %self.package.__name__ |
|---|
| | 153 | config.add_template_engine(self.default_renderer, |
|---|
| | 154 | template_location, {}) |
|---|
| | 155 | |
|---|
| | 156 | def setup_sqlalchemy(self): |
|---|
| | 157 | # Setup SQLAlchemy database engine |
|---|
| | 158 | from sqlalchemy import engine_from_config |
|---|
| | 159 | engine = engine_from_config(config, 'sqlalchemy.') |
|---|
| | 160 | config['pylons.app_globals'].sa_engine = engine |
|---|
| | 161 | # Pass the engine to initmodel, to be able to introspect tables |
|---|
| | 162 | self.package.model.init_model(engine) |
|---|
| | 163 | self.package.model.DBSession.configure(bind=engine) |
|---|
| | 164 | self.package.model.metadata.bind = engine |
|---|
| | 165 | |
|---|
| | 166 | def make_load_environment(self): |
|---|
| | 167 | """Returns a load_environment function |
|---|
| | 168 | |
|---|
| | 169 | The returned load_environment function can be called to configure the |
|---|
| | 170 | TurboGears runtime environment for this particular application. You |
|---|
| | 171 | can do this dynamically with multiple nested TG applications if |
|---|
| | 172 | nessisary.""" |
|---|
| | 173 | |
|---|
| | 174 | def load_environment(global_conf, app_conf): |
|---|
| | 175 | """Configure the Pylons environment via the ``pylons.config`` |
|---|
| | 176 | object |
|---|
| | 177 | """ |
|---|
| | 178 | |
|---|
| | 179 | self.setup_paths() |
|---|
| | 180 | self.init_config(global_conf, app_conf) |
|---|
| | 181 | self.setup_routes() |
|---|
| | 182 | self.setup_helpers_and_globals() |
|---|
| | 183 | if self.auth_backend == "sqlalchemy": |
|---|
| | 184 | self.setup_sa_auth_backend |
|---|
| | 185 | |
|---|
| | 186 | if 'mako' in self.renderers: |
|---|
| | 187 | self.setup_mako_renderer() |
|---|
| | 188 | |
|---|
| | 189 | if 'genshi' in self.renderers: |
|---|
| | 190 | self.setup_genshi_renderer() |
|---|
| | 191 | |
|---|
| | 192 | if 'jinja' in self.renderers: |
|---|
| | 193 | self.setup_jinja_renderer() |
|---|
| | 194 | |
|---|
| | 195 | self.setup_default_renderer() |
|---|
| | 196 | |
|---|
| | 197 | if self.use_sqlalchemy: |
|---|
| | 198 | self.setup_sqlalchemy() |
|---|
| | 199 | |
|---|
| | 200 | return load_environment |
|---|
| | 201 | |
|---|
| | 202 | |
|---|
| | 203 | def add_error_middleware(self, global_conf, app): |
|---|
| | 204 | # Handle Python exceptions |
|---|
| | 205 | app = ErrorHandler(app, global_conf, **config['pylons.errorware']) |
|---|
| | 206 | |
|---|
| | 207 | # Display error documents for 401, 403, 404 status codes (and |
|---|
| | 208 | # 500 when debug is disabled) |
|---|
| | 209 | if asbool(config['debug']): |
|---|
| | 210 | app = StatusCodeRedirect(app) |
|---|
| | 211 | else: |
|---|
| | 212 | app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) |
|---|
| | 213 | return app |
|---|
| | 214 | |
|---|
| | 215 | def add_auth_middleware(self, app): |
|---|
| | 216 | # configure identity Middleware |
|---|
| | 217 | from tg.ext.repoze.who.middleware import make_who_middleware |
|---|
| | 218 | |
|---|
| | 219 | auth = self.sa_auth |
|---|
| | 220 | |
|---|
| | 221 | app = make_who_middleware(app, config, auth.user, |
|---|
| | 222 | auth.user_criterion, |
|---|
| | 223 | auth.user_id_column, |
|---|
| | 224 | auth.dbsession, |
|---|
| | 225 | ) |
|---|
| | 226 | return app |
|---|
| | 227 | |
|---|
| | 228 | def add_core_middleware(self, app): |
|---|
| | 229 | app = RoutesMiddleware(app, config['routes.map']) |
|---|
| | 230 | app = SessionMiddleware(app, config) |
|---|
| | 231 | app = CacheMiddleware(app, config) |
|---|
| | 232 | return app |
|---|
| | 233 | |
|---|
| | 234 | def add_tosca_middleware(self, app): |
|---|
| | 235 | app = tw_middleware(app, { |
|---|
| | 236 | 'toscawidgets.framework.default_view': |
|---|
| | 237 | self.default_renderer, |
|---|
| | 238 | 'toscawidgets.middleware.inject_resources': True, |
|---|
| | 239 | }) |
|---|
| | 240 | return app |
|---|
| | 241 | |
|---|
| | 242 | def add_static_file_middleware(self, app): |
|---|
| | 243 | javascripts_app = StaticJavascripts() |
|---|
| | 244 | static_app = StaticURLParser(config['pylons.paths']['static_files']) |
|---|
| | 245 | app = Cascade([static_app, javascripts_app, app]) |
|---|
| | 246 | return app |
|---|
| | 247 | |
|---|
| | 248 | def setup_tg_wsgi_app(self, load_environment): |
|---|
| | 249 | """Create a base TG app, with all the standard middleware |
|---|
| | 250 | |
|---|
| | 251 | ``load_environment`` |
|---|
| | 252 | A required callable, which sets up the basic application |
|---|
| | 253 | evironment. |
|---|
| | 254 | ``setup_vars`` |
|---|
| | 255 | A dictionary any special values nessisary for setting up |
|---|
| | 256 | the base wsgi app. |
|---|
| | 257 | """ |
|---|
| | 258 | |
|---|
| | 259 | def make_base_app(global_conf, wrap_app=None, full_stack=True, **app_conf): |
|---|
| | 260 | """Create a tg WSGI application and return it |
|---|
| | 261 | |
|---|
| | 262 | ``global_conf`` |
|---|
| | 263 | The inherited configuration for this application. Normally from |
|---|
| | 264 | the [DEFAULT] section of the Paste ini file. |
|---|
| | 265 | |
|---|
| | 266 | ``full_stack`` |
|---|
| | 267 | Whether or not this application provides a full WSGI stack (by |
|---|
| | 268 | default, meaning it handles its own exceptions and errors). |
|---|
| | 269 | Disable full_stack when this application is "managed" by |
|---|
| | 270 | another WSGI middleware. |
|---|
| | 271 | |
|---|
| | 272 | ``app_conf`` |
|---|
| | 273 | The application's local configuration. Normally specified in the |
|---|
| | 274 | [app:<name>] section of the Paste ini file (where <name> |
|---|
| | 275 | defaults to main). |
|---|
| | 276 | """ |
|---|
| | 277 | # Configure the Pylons environment |
|---|
| | 278 | load_environment(global_conf, app_conf) |
|---|
| | 279 | app = PylonsApp() |
|---|
| | 280 | if wrap_app: |
|---|
| | 281 | wrap_app(app) |
|---|
| | 282 | app = self.add_core_middleware(app) |
|---|
| | 283 | app = self.add_tosca_middleware(app) |
|---|
| | 284 | |
|---|
| | 285 | if self.auth_backend == "sqlalchemy": |
|---|
| | 286 | app = self.add_auth_middleware(app) |
|---|
| | 287 | |
|---|
| | 288 | if asbool(full_stack): |
|---|
| | 289 | # This should nevery be true for internal nested apps |
|---|
| | 290 | app = self.add_error_middleware(global_conf, app) |
|---|
| | 291 | |
|---|
| | 292 | # Establish the Registry for this application |
|---|
| | 293 | app = RegistryManager(app) |
|---|
| | 294 | |
|---|
| | 295 | # Static files (If running in production, and Apache or another |
|---|
| | 296 | # web server is serving static files) |
|---|
| | 297 | if self.serve_static: |
|---|
| | 298 | app = self.add_static_file_middleware(app) |
|---|
| | 299 | return app |
|---|
| | 300 | |
|---|
| | 301 | return make_base_app |
|---|