def __before__(self, action, **params): # Let templates get at the total render time c.timer = ResponseTimer() c.links = config["spline.plugins.links"] c.javascripts = [ ("spline", "lib/jquery-1.7.1.min"), ("spline", "lib/jquery.cookies-2.2.0.min"), ("spline", "lib/jquery.ui-1.8.4.min"), ("spline", "core"), ] run_hooks("before_controller", action, **params)
def __before__(self, action, **params): # Let templates get at the total render time c.timer = ResponseTimer() c.links = config['spline.plugins.links'] c.javascripts = [ ('spline', 'lib/jquery-1.3.2.min'), ('spline', 'lib/jquery.cookies-2.2.0.min'), ('spline', 'lib/jquery.ui-1.8.4.min'), ('spline', 'core'), ] run_hooks('before_controller', action, **params)
def cron(self): """Runs interested cron-jobs.""" cron_cache = cache.get_cache('spline:cron') # XXX Tiny race condition here; checking for a value and then setting # it is not atomic if 'LOCK' in cron_cache: return 'already running' cron_cache['LOCK'] = 1 try: now = datetime.datetime.now().time() tic = now.hour * 60 + now.minute run_hooks('cron', tic=tic) finally: # Always unlock when done del cron_cache['LOCK'] return 'ok'
def make_map(config, content_dirs=[]): """Create, configure and return the routes Mapper""" map = I18nMapper( controller_scan=lambda directory: controller_scan(config, directory), directory=config['pylons.paths']['controllers'], always_scan=config['debug']) map.minimization = False # Content files get explicitly mapped so we don't have to pull any cheap # tricks like looking for them in a 404 handler. We do them first so # controllers can't be clobbered by bad choices of filenames for content_dir in content_dirs: for root, dirs, files in os.walk(content_dir): for name in files: localpath = os.path.join(root, name) webpath, ext = os.path.splitext(localpath) # Skip over hidden files. # For now, also require a .html extension. if webpath[0] == '.' or ext != '.html': continue # Use the full path as a route name so url() can easily route # to a static page map.connect('/' + os.path.relpath(webpath, content_dir), '/' + os.path.relpath(webpath, content_dir), controller='main', action='content', path=localpath) # The ErrorController route (handles 404/500 error pages); it should # likely stay at the top, ensuring it can always be resolved map.connect('/error/{action}', controller='error') map.connect('/error/{action}/{id}', controller='error') map.connect('/css', controller='main', action='css') map.connect('/cron', controller='main', action='cron') # Allow plugins to map routes without the below defaults clobbering them run_hooks('routes_mapping', config=config, map=map) map.connect('/', controller='main', action='index') return map
def load_sources_hook(config, *args, **kwargs): """Hook to load all the known sources and stuff them in config. Run once, on server startup. Frontpage hooks are also passed the `config` hash, as it's not available during setup. """ # Extract source definitions from config and store as source_name => config update_config = defaultdict(dict) key_rx = re.compile( '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $') for key, val in config.iteritems(): # Match against spline-frontpage.source.(source).(key) match = key_rx.match(key) if not match: continue source_name, subkey = match.groups() if not subkey: # This is the type declaration; use a special key subkey = '__type__' update_config[source_name][subkey] = val # Figure out the global limit and expiration time, with reasonable # defaults. Make sure they're integers. global_limit = int(config.get('spline-frontpage.limit', 10)) # max_age is optional and can be None try: global_max_age = int(config['spline-frontpage.max_age']) except KeyError: global_max_age = None config['spline-frontpage.limit'] = global_limit config['spline-frontpage.max_age'] = global_max_age # Ask plugins to turn configuration into source objects sources = [] for source, source_config in update_config.iteritems(): hook_name = 'frontpage_updates_' + source_config['__type__'] del source_config['__type__'] # don't feed this to constructor! # Default to global limit and max age. Source takes care of making # integers and whatnot source_config.setdefault('limit', global_limit) source_config.setdefault('max_age', global_max_age) # Hooks return a list of sources; combine with running list sources += run_hooks(hook_name, config=config, **source_config) # Save the list of sources, and done config['spline-frontpage.sources'] = sources
def make_app(global_conf, full_stack=True, **app_conf): """Create a Pylons WSGI application and return it ``global_conf`` The inherited configuration for this application. Normally from the [DEFAULT] section of the Paste ini file. ``full_stack`` Whether or not this application provides a full WSGI stack (by default, meaning it handles its own exceptions and errors). Disable full_stack when this application is "managed" by another WSGI middleware. ``app_conf`` The application's local configuration. Normally specified in the [app:<name>] section of the Paste ini file (where <name> defaults to main). """ # Configure the Pylons environment config = load_environment(global_conf, app_conf) # The Pylons WSGI app app = SplineApp(config=config) # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) # XXX This is dumb. Hack around a Beaker bug which ignores enabled=False # in config -- but not, thankfully, in kwargs cache_kwargs = {} if 'beaker.cache.enabled' in config: cache_kwargs['enabled'] = asbool(config['beaker.cache.enabled']) # Routing/Session/Cache Middleware app = RoutesMiddleware(app, config['routes.map']) app = SessionMiddleware(app, config) # Super ultra debug mode #from paste.translogger import TransLogger #app = TransLogger(app) if asbool(full_stack): # Handle Python exceptions app = ErrorHandler(app, global_conf, **config['pylons.errorware']) # Display error documents for 401, 403, 404 status codes (and # 500 when debug is disabled) if asbool(config['debug']): app = StatusCodeRedirect(app) else: app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) # Establish the Registry for this application app = RegistryManager(app) # Static files (If running in production, and Apache or another web # server is handling this static content, remove the following 2 lines) static_app = SplineStaticURLParser(config['pylons.paths']['static_files']) app = Cascade([static_app, app]) app.config = config # Let plugins do any final setup run_hooks('after_setup', config=config) return app
def __after__(self, **params): run_hooks('after_controller', **params)
def index(self): """Magicaltastic front page. Plugins can register a hook called 'frontpage_updates_<type>' to add updates to the front page. `<type>` is an arbitrary string indicating the sort of update the plugin knows how to handle; for example, spline-forum has a `frontpage_updates_forum` hook for posting news from a specific forum. Hook handlers should return a list of FrontPageUpdate objects. Standard hook parameters are: `limit`, the maximum number of items that should ever be returned. `max_age`, the number of seconds after which items expire. `title`, a name for the source. `icon`, an icon to show next to its name. `limit` and `max_age` are also global options. Updates are configured in the .ini like so: spline-frontpage.sources.foo = updatetype spline-frontpage.sources.foo.opt1 = val1 spline-frontpage.sources.foo.opt2 = val2 Note that the 'foo' name is completely arbitrary and is only used for grouping options together. This will result in a call to: run_hooks('frontpage_updates_updatetype', opt1=val1, opt2=val2) Plugins may also respond to the `frontpage_extras` hook with other interesting things to put on the front page. There's no way to customize the order of these extras or which appear and which don't, at the moment. Such hooks should return an object with at least a `template` attribute; the template will be called with the object passed in as its `obj` argument. Local plugins can override the fairly simple index.mako template to customize the front page layout. """ updates = [] global_limit = config['spline-frontpage.limit'] global_max_age = max_age_to_datetime( config['spline-frontpage.max_age']) c.sources = config['spline-frontpage.sources'] for source in c.sources: new_updates = source.poll(global_limit, global_max_age) updates.extend(new_updates) # Little optimization: once there are global_limit items, anything # older than the oldest cannot possibly make it onto the list. So, # bump global_max_age to that oldest time if this is ever the case. updates.sort(key=lambda obj: obj.time, reverse=True) del updates[global_limit:] if updates and len(updates) == global_limit: global_max_age = updates[-1].time # Find the oldest unseen item, to draw a divider after it. # If this stays as None, the divider goes at the top c.last_seen_item = None # Could have a timestamp in the stash if this is a user, or in a cookie # if this session has ever been logged out... times = [] for source in (c.user.stash, request.cookies): try: times.append( int(source['frontpage-last-seen-time']) ) except (KeyError, ValueError): pass if times: last_seen_time = datetime.datetime.fromtimestamp(max(times)) for update in updates: if update.time > last_seen_time: c.last_seen_item = update else: break # Save ~now~ as the last-seen time now = datetime.datetime.now().strftime('%s') if c.user: c.user.stash['frontpage-last-seen-time'] = now meta.Session.add(c.user) else: response.set_cookie('frontpage-last-seen-time', now) # Done! Feed to template c.updates = updates # Hook for non-update interesting things to put on the front page. # This hook should return objects with a 'template' attribute, and # whatever else they need c.extras = run_hooks('frontpage_extras') ret = render('/index.mako') # Commit AFTER rendering the template! Committing invalidates # everything in the session, undoing any eagerloading that may have # been done by sources meta.Session.commit() return ret
def index(self): """Magicaltastic front page. Plugins can register a hook called 'frontpage_updates_<type>' to add updates to the front page. `<type>` is an arbitrary string indicating the sort of update the plugin knows how to handle; for example, spline-forum has a `frontpage_updates_forum` hook for posting news from a specific forum. Hook handlers should return a list of FrontPageUpdate objects. Standard hook parameters are: `limit`, the maximum number of items that should ever be returned. `max_age`, the number of seconds after which items expire. `title`, a name for the source. `icon`, an icon to show next to its name. `limit` and `max_age` are also global options. Updates are configured in the .ini like so: spline-frontpage.sources.foo = updatetype spline-frontpage.sources.foo.opt1 = val1 spline-frontpage.sources.foo.opt2 = val2 Note that the 'foo' name is completely arbitrary and is only used for grouping options together. This will result in a call to: run_hooks('frontpage_updates_updatetype', opt1=val1, opt2=val2) Plugins may also respond to the `frontpage_extras` hook with other interesting things to put on the front page. There's no way to customize the order of these extras or which appear and which don't, at the moment. Such hooks should return an object with at least a `template` attribute; the template will be called with the object passed in as its `obj` argument. Local plugins can override the fairly simple index.mako template to customize the front page layout. """ updates = [] global_limit = config['spline-frontpage.limit'] global_max_age = max_age_to_datetime( config['spline-frontpage.max_age']) c.sources = config['spline-frontpage.sources'] for source in c.sources: new_updates = source.poll(global_limit, global_max_age) updates.extend(new_updates) # Little optimization: once there are global_limit items, anything # older than the oldest cannot possibly make it onto the list. So, # bump global_max_age to that oldest time if this is ever the case. updates.sort(key=lambda obj: obj.time, reverse=True) del updates[global_limit:] if updates and len(updates) == global_limit: global_max_age = updates[-1].time # Find the oldest unseen item, to draw a divider after it. # If this stays as None, the divider goes at the top c.last_seen_item = None # Could have a timestamp in the stash if this is a user, or in a cookie # if this session has ever been logged out... times = [] for source in (c.user.stash, request.cookies): try: times.append(int(source['frontpage-last-seen-time'])) except (KeyError, ValueError): pass if times: last_seen_time = datetime.datetime.fromtimestamp(max(times)) for update in updates: if update.time > last_seen_time: c.last_seen_item = update else: break # Save ~now~ as the last-seen time now = datetime.datetime.now().strftime('%s') if c.user: c.user.stash['frontpage-last-seen-time'] = now meta.Session.add(c.user) else: response.set_cookie('frontpage-last-seen-time', now) # Done! Feed to template c.updates = updates # Hook for non-update interesting things to put on the front page. # This hook should return objects with a 'template' attribute, and # whatever else they need c.extras = run_hooks('frontpage_extras') ret = render('/index.mako') # Commit AFTER rendering the template! Committing invalidates # everything in the session, undoing any eagerloading that may have # been done by sources meta.Session.commit() return ret
def __after__(self, **params): run_hooks("after_controller", **params)