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