[MERGE]merge with main branch.
[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.config = None
33         self._db = False
34         self._uid = False
35         self._login = False
36         self._password = False
37         self.context = {}
38         self.contexts_store = {}
39         self.domains_store = {}
40         self.jsonp_requests = {}     # FIXME use a LRU
41         
42     def __getstate__(self):
43         state = dict(self.__dict__)
44         if "config" in state:
45             del state['config']
46         return state
47
48     def openerp_entreprise(self):
49         if not self._uid:
50             return False
51         else:
52             return self.model('publisher_warranty.contract').status()['status'] == 'full'
53
54     def build_connection(self):
55         conn = openerplib.Connection(self.config.connector, database=self._db, login=self._login,
56                    user_id=self._uid, password=self._password)
57         return conn
58
59     def proxy(self, service):
60         return self.build_connection().get_service(service)
61
62     def bind(self, db, uid, login, password):
63         self._db = db
64         self._uid = uid
65         self._login = login
66         self._password = password
67
68     def authenticate(self, db, login, password, env):
69         # TODO use the openerplib API once it exposes authenticate()
70         uid = self.proxy('common').authenticate(db, login, password, env)
71         self.bind(db, uid, login, password)
72         
73         if uid: self.get_context()
74         return uid
75
76     def assert_valid(self, force=False):
77         """
78         Ensures this session is valid (logged into the openerp server)
79         """
80         self.build_connection().check_login(force)
81
82     def execute(self, model, func, *l, **d):
83         self.assert_valid()
84         model = self.build_connection().get_model(model)
85         r = getattr(model, func)(*l, **d)
86         return r
87
88     def exec_workflow(self, model, id, signal):
89         self.assert_valid()
90         r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
91         return r
92
93     def model(self, model):
94         """ Get an RPC proxy for the object ``model``, bound to this session.
95
96         :param model: an OpenERP model name
97         :type model: str
98         :rtype: a model object
99         """
100         return self.build_connection().get_model(model)
101
102     def get_context(self):
103         """ Re-initializes the current user's session context (based on
104         his preferences) by calling res.users.get_context() with the old
105         context
106
107         :returns: the new context
108         """
109         assert self._uid, "The user needs to be logged-in to initialize his context"
110         self.context = self.build_connection().get_user_context() or {}
111
112         return self.context
113
114     @property
115     def base_eval_context(self):
116         """ Default evaluation context for the session.
117
118         Used to evaluate contexts and domains.
119         """
120         base = dict(
121             uid=self._uid,
122             current_date=datetime.date.today().strftime('%Y-%m-%d'),
123             time=time,
124             datetime=datetime,
125             relativedelta=dateutil.relativedelta.relativedelta
126         )
127         base.update(self.context)
128         return base
129
130     def evaluation_context(self, context=None):
131         """ Returns the session's evaluation context, augmented with the
132         provided context if any.
133
134         :param dict context: to add merge in the session's base eval context
135         :returns: the augmented context
136         :rtype: dict
137         """
138         d = dict(self.base_eval_context)
139         if context:
140             d.update(context)
141         d['context'] = d
142         return d
143
144     def eval_context(self, context_to_eval, context=None):
145         """ Evaluates the provided context_to_eval in the context (haha) of
146         the context. Also merges the evaluated context with the session's context.
147
148         :param context_to_eval: a context to evaluate. Must be a dict or a
149                                 non-literal context. If it's a dict, will be
150                                 returned as-is
151         :type context_to_eval: openerpweb.nonliterals.Context
152         :returns: the evaluated context
153         :rtype: dict
154
155         :raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
156                  a Context
157         """
158         ctx = dict(
159             self.base_eval_context,
160             **(context or {}))
161         
162         # adding the context of the session to send to the openerp server
163         ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
164         ccontext.session = self
165         return ccontext.evaluate(ctx)
166
167     def eval_domain(self, domain, context=None):
168         """ Evaluates the provided domain using the provided context
169         (merged with the session's evaluation context)
170
171         :param domain: an OpenERP domain as a list or as a
172                        :class:`openerpweb.nonliterals.Domain` instance
173
174                        In the second case, it will be evaluated and returned.
175         :type domain: openerpweb.nonliterals.Domain
176         :param dict context: the context to use in the evaluation, if any.
177         :returns: the evaluated domain
178         :rtype: list
179
180         :raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
181         """
182         if isinstance(domain, list):
183             return domain
184
185         cdomain = nonliterals.CompoundDomain(domain)
186         cdomain.session = self
187         return cdomain.evaluate(context or {})