source: tailbone/tailbone/subscribers.py @ 2bdcc4f

Last change on this file since 2bdcc4f was 2bdcc4f, checked in by Lance Edgar <ledgar@…>, 11 months ago

Can finally assume "simple" menus by default

all apps in the wild already using them

  • Property mode set to 100644
File size: 7.9 KB
Line 
1# -*- coding: utf-8; -*-
2################################################################################
3#
4#  Rattail -- Retail Software Framework
5#  Copyright © 2010-2018 Lance Edgar
6#
7#  This file is part of Rattail.
8#
9#  Rattail is free software: you can redistribute it and/or modify it under the
10#  terms of the GNU General Public License as published by the Free Software
11#  Foundation, either version 3 of the License, or (at your option) any later
12#  version.
13#
14#  Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
15#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16#  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17#  details.
18#
19#  You should have received a copy of the GNU General Public License along with
20#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
21#
22################################################################################
23"""
24Event Subscribers
25"""
26
27from __future__ import unicode_literals, absolute_import
28
29import six
30import json
31import datetime
32
33import rattail
34from rattail.db import model
35from rattail.db.auth import cache_permissions
36
37from pyramid import threadlocal
38from webhelpers2.html import tags
39
40import tailbone
41from tailbone import helpers
42from tailbone.db import Session
43from tailbone.menus import make_simple_menus
44
45
46def new_request(event):
47    """
48    Identify the current user, and cache their current permissions.  Also adds
49    the ``rattail_config`` attribute to the request.
50
51    A global Rattail ``config`` should already be present within the Pyramid
52    application registry's settings, which would normally be accessed via::
53   
54       request.registry.settings['rattail_config']
55
56    This function merely "promotes" that config object so that it is more
57    directly accessible, a la::
58
59       request.rattail_config
60
61    .. note::
62       This of course assumes that a Rattail ``config`` object *has* in fact
63       already been placed in the application registry settings.  If this is
64       not the case, this function will do nothing.
65    """
66    request = event.request
67    rattail_config = request.registry.settings.get('rattail_config')
68    if rattail_config:
69        request.rattail_config = rattail_config
70
71    request.user = None
72    uuid = request.authenticated_userid
73    if uuid:
74        request.user = Session.query(model.User).get(uuid)
75        if request.user:
76            Session().set_continuum_user(request.user)
77
78    request.is_admin = bool(request.user) and request.user.is_admin()
79    request.is_root = request.is_admin and request.session.get('is_root', False)
80
81    request.tailbone_cached_permissions = cache_permissions(Session(), request.user)
82
83
84def before_render(event):
85    """
86    Adds goodies to the global template renderer context.
87    """
88
89    request = event.get('request') or threadlocal.get_current_request()
90
91    renderer_globals = event
92    renderer_globals['h'] = helpers
93    renderer_globals['url'] = request.route_url
94    renderer_globals['rattail'] = rattail
95    renderer_globals['tailbone'] = tailbone
96    renderer_globals['enum'] = request.rattail_config.get_enum()
97    renderer_globals['six'] = six
98    renderer_globals['json'] = json
99    renderer_globals['datetime'] = datetime
100
101    # theme  - we only want do this for classic web app, *not* API
102    # TODO: so, clearly we need a better way to distinguish the two
103    if 'tailbone.theme' in request.registry.settings:
104        renderer_globals['theme'] = request.registry.settings['tailbone.theme']
105        # note, this is just a global flag; user still needs permission to see picker
106        expose_picker = request.rattail_config.getbool('tailbone', 'themes.expose_picker',
107                                                       default=False)
108        renderer_globals['expose_theme_picker'] = expose_picker
109        if expose_picker:
110            available = request.rattail_config.getlist('tailbone', 'themes',
111                                                       default=['bobcat'])
112            if 'default' not in available:
113                available.insert(0, 'default')
114            options = [tags.Option(theme) for theme in available]
115            renderer_globals['theme_picker_options'] = options
116
117        # heck while we're assuming the classic web app here...
118        # (we don't want this to happen for the API either!)
119        # TODO: just..awful *shrug*
120        # note that we assume "simple" menus nowadays
121        if request.rattail_config.getbool('tailbone', 'menus.simple', default=True):
122            renderer_globals['menus'] = make_simple_menus(request)
123
124        # TODO: ugh, same deal here
125        renderer_globals['messaging_enabled'] = request.rattail_config.getbool(
126            'tailbone', 'messaging.enabled', default=False)
127
128        # background color may be set per-request, by some apps
129        if hasattr(request, 'background_color') and request.background_color:
130            renderer_globals['background_color'] = request.background_color
131        else: # otherwise we use the one from config
132            renderer_globals['background_color'] = request.rattail_config.get(
133                'tailbone', 'background_color')
134
135
136def add_inbox_count(event):
137    """
138    Adds the current user's inbox message count to the global renderer context.
139
140    Note that this is not enabled by default; to turn it on you must do this:
141
142       config.add_subscriber('tailbone.subscribers.add_inbox_count', 'pyramid.events.BeforeRender')
143    """
144    request = event.get('request') or threadlocal.get_current_request()
145    if request.user:
146        renderer_globals = event
147        enum = request.rattail_config.get_enum()
148        renderer_globals['inbox_count'] = Session.query(model.Message)\
149                                                 .outerjoin(model.MessageRecipient)\
150                                                 .filter(model.MessageRecipient.recipient == Session.merge(request.user))\
151                                                 .filter(model.MessageRecipient.status == enum.MESSAGE_STATUS_INBOX)\
152                                                 .count()
153
154
155def context_found(event):
156    """
157    Attach some goodies to the request object.
158
159    The following is attached to the request:
160
161    * The currently logged-in user instance (if any), as ``user``.
162
163    * ``is_admin`` flag indicating whether user has the Administrator role.
164
165    * ``is_root`` flag indicating whether user is currently elevated to root.
166
167    * A shortcut method for permission checking, as ``has_perm()``.
168
169    * A shortcut method for fetching the referrer, as ``get_referrer()``.
170    """
171
172    request = event.request
173
174    def has_perm(name):
175        if name in request.tailbone_cached_permissions:
176            return True
177        return request.is_root
178    request.has_perm = has_perm
179
180    def has_any_perm(*names):
181        for name in names:
182            if has_perm(name):
183                return True
184        return False
185    request.has_any_perm = has_any_perm
186
187    def get_referrer(default=None, mobile=False):
188        if request.params.get('referrer'):
189            return request.params['referrer']
190        if request.session.get('referrer'):
191            return request.session.pop('referrer')
192        referrer = request.referrer
193        if (not referrer or referrer == request.current_route_url()
194            or not referrer.startswith(request.host_url)):
195            if default:
196                referrer = default
197            elif mobile:
198                referrer = request.route_url('mobile.home')
199            else:
200                referrer = request.route_url('home')
201        return referrer
202    request.get_referrer = get_referrer
203
204    def get_session_timeout():
205        """
206        Returns the timeout in effect for the current session
207        """
208        return request.session.get('_timeout')
209    request.get_session_timeout = get_session_timeout
210
211
212def includeme(config):
213    config.add_subscriber(new_request, 'pyramid.events.NewRequest')
214    config.add_subscriber(before_render, 'pyramid.events.BeforeRender')
215    config.add_subscriber(context_found, 'pyramid.events.ContextFound')
Note: See TracBrowser for help on using the repository browser.