[MERGE]: survey: fixed a bug in warning message when users exceed maximal number...
[odoo/odoo.git] / addons / web / common / session.py
1 #!/usr/bin/python
2 import datetime
3 import dateutil.relativedelta
4 import logging
5 import time
6 import openerplib
7
8 import nonliterals
9
10 _logger = logging.getLogger(__name__)
11 #----------------------------------------------------------
12 # OpenERPSession RPC openerp backend access
13 #----------------------------------------------------------
14 class OpenERPSession(object):
15     """
16     An OpenERP RPC session, a given user can own multiple such sessions
17     in a web session.
18
19     .. attribute:: context
20     
21         The session context, a ``dict``. Can be reloaded by calling
22         :meth:`openerpweb.openerpweb.OpenERPSession.get_context`
23
24     .. attribute:: domains_store
25
26         A ``dict`` matching domain keys to evaluable (but non-literal) domains.
27
28         Used to store references to non-literal domains which need to be
29         round-tripped to the client browser.
30     """
31     def __init__(self):
32         self._creation_time = time.time()
33         self.config = None
34         self._db = False
35         self._uid = False
36         self._login = False
37         self._password = False
38         self.context = {}
39         self.contexts_store = {}
40         self.domains_store = {}
41         self.jsonp_requests = {}     # FIXME use a LRU
42         
43     def __getstate__(self):
44         state = dict(self.__dict__)
45         if "config" in state:
46             del state['config']
47         return state
48
49     def openerp_entreprise(self):
50         if not self._uid:
51             return False
52         else:
53             return self.model('publisher_warranty.contract').status()['status'] == 'full'
54
55     def build_connection(self):
56         conn = openerplib.Connection(self.config.connector, database=self._db, login=self._login,
57                    user_id=self._uid, password=self._password)
58         return conn
59
60     def proxy(self, service):
61         return self.build_connection().get_service(service)
62
63     def bind(self, db, uid, login, password):
64         self._db = db
65         self._uid = uid
66         self._login = login
67         self._password = password
68
69     def authenticate(self, db, login, password, env):
70         # TODO use the openerplib API once it exposes authenticate()
71         uid = self.proxy('common').authenticate(db, login, password, env)
72         self.bind(db, uid, login, password)
73         
74         if uid: self.get_context()
75         return uid
76
77     def assert_valid(self, force=False):
78         """
79         Ensures this session is valid (logged into the openerp server)
80         """
81         self.build_connection().check_login(force)
82
83     def execute(self, model, func, *l, **d):
84         self.assert_valid()
85         model = self.build_connection().get_model(model)
86         r = getattr(model, func)(*l, **d)
87         return r
88
89     def exec_workflow(self, model, id, signal):
90         self.assert_valid()
91         r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
92         return r
93
94     def model(self, model):
95         """ Get an RPC proxy for the object ``model``, bound to this session.
96
97         :param model: an OpenERP model name
98         :type model: str
99         :rtype: a model object
100         """
101         return self.build_connection().get_model(model)
102
103     def get_context(self):
104         """ Re-initializes the current user's session context (based on
105         his preferences) by calling res.users.get_context() with the old
106         context
107
108         :returns: the new context
109         """
110         assert self._uid, "The user needs to be logged-in to initialize his context"
111         self.context = self.build_connection().get_user_context() or {}
112
113         return self.context
114
115     @property
116     def base_eval_context(self):
117         """ Default evaluation context for the session.
118
119         Used to evaluate contexts and domains.
120         """
121         base = dict(
122             uid=self._uid,
123             current_date=datetime.date.today().strftime('%Y-%m-%d'),
124             time=time,
125             datetime=datetime,
126             relativedelta=dateutil.relativedelta.relativedelta
127         )
128         base.update(self.context)
129         return base
130
131     def evaluation_context(self, context=None):
132         """ Returns the session's evaluation context, augmented with the
133         provided context if any.
134
135         :param dict context: to add merge in the session's base eval context
136         :returns: the augmented context
137         :rtype: dict
138         """
139         d = dict(self.base_eval_context)
140         if context:
141             d.update(context)
142         d['context'] = d
143         return d
144
145     def eval_context(self, context_to_eval, context=None):
146         """ Evaluates the provided context_to_eval in the context (haha) of
147         the context. Also merges the evaluated context with the session's context.
148
149         :param context_to_eval: a context to evaluate. Must be a dict or a
150                                 non-literal context. If it's a dict, will be
151                                 returned as-is
152         :type context_to_eval: openerpweb.nonliterals.Context
153         :returns: the evaluated context
154         :rtype: dict
155
156         :raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
157                  a Context
158         """
159         ctx = dict(
160             self.base_eval_context,
161             **(context or {}))
162         
163         # adding the context of the session to send to the openerp server
164         ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
165         ccontext.session = self
166         return ccontext.evaluate(ctx)
167
168     def eval_domain(self, domain, context=None):
169         """ Evaluates the provided domain using the provided context
170         (merged with the session's evaluation context)
171
172         :param domain: an OpenERP domain as a list or as a
173                        :class:`openerpweb.nonliterals.Domain` instance
174
175                        In the second case, it will be evaluated and returned.
176         :type domain: openerpweb.nonliterals.Domain
177         :param dict context: the context to use in the evaluation, if any.
178         :returns: the evaluated domain
179         :rtype: list
180
181         :raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
182         """
183         if isinstance(domain, list):
184             return domain
185
186         cdomain = nonliterals.CompoundDomain(domain)
187         cdomain.session = self
188         return cdomain.evaluate(context or {})