10 __docformat__ = "restructuredtext en" |
10 __docformat__ = "restructuredtext en" |
11 |
11 |
12 import sys |
12 import sys |
13 import threading |
13 import threading |
14 from time import time |
14 from time import time |
|
15 from uuid import uuid4 |
15 |
16 |
16 from logilab.common.deprecation import deprecated |
17 from logilab.common.deprecation import deprecated |
17 from rql.nodes import VariableRef, Function, ETYPE_PYOBJ_MAP, etype_from_pyobj |
18 from rql.nodes import VariableRef, Function, ETYPE_PYOBJ_MAP, etype_from_pyobj |
18 from yams import BASE_TYPES |
19 from yams import BASE_TYPES |
19 |
20 |
20 from cubicweb import Binary, UnknownEid |
21 from cubicweb import Binary, UnknownEid, schema |
21 from cubicweb.req import RequestSessionBase |
22 from cubicweb.req import RequestSessionBase |
22 from cubicweb.dbapi import ConnectionProperties |
23 from cubicweb.dbapi import ConnectionProperties |
23 from cubicweb.utils import make_uid |
24 from cubicweb.utils import make_uid |
24 from cubicweb.rqlrewrite import RQLRewriter |
25 from cubicweb.rqlrewrite import RQLRewriter |
25 |
26 |
26 ETYPE_PYOBJ_MAP[Binary] = 'Bytes' |
27 ETYPE_PYOBJ_MAP[Binary] = 'Bytes' |
|
28 |
|
29 NO_UNDO_TYPES = schema.SCHEMA_TYPES.copy() |
|
30 NO_UNDO_TYPES.add('CWCache') |
|
31 # XXX rememberme,forgotpwd,apycot,vcsfile |
27 |
32 |
28 def is_final(rqlst, variable, args): |
33 def is_final(rqlst, variable, args): |
29 # try to find if this is a final var or not |
34 # try to find if this is a final var or not |
30 for select in rqlst.children: |
35 for select in rqlst.children: |
31 for sol in select.solutions: |
36 for sol in select.solutions: |
108 |
113 |
109 class Session(RequestSessionBase): |
114 class Session(RequestSessionBase): |
110 """tie session id, user, connections pool and other session data all |
115 """tie session id, user, connections pool and other session data all |
111 together |
116 together |
112 """ |
117 """ |
|
118 is_internal_session = False |
113 |
119 |
114 def __init__(self, user, repo, cnxprops=None, _id=None): |
120 def __init__(self, user, repo, cnxprops=None, _id=None): |
115 super(Session, self).__init__(repo.vreg) |
121 super(Session, self).__init__(repo.vreg) |
116 self.id = _id or make_uid(user.login.encode('UTF8')) |
122 self.id = _id or make_uid(user.login.encode('UTF8')) |
117 cnxprops = cnxprops or ConnectionProperties('inmemory') |
123 cnxprops = cnxprops or ConnectionProperties('inmemory') |
118 self.user = user |
124 self.user = user |
119 self.repo = repo |
125 self.repo = repo |
120 self.cnxtype = cnxprops.cnxtype |
126 self.cnxtype = cnxprops.cnxtype |
121 self.creation = time() |
127 self.creation = time() |
122 self.timestamp = self.creation |
128 self.timestamp = self.creation |
123 self.is_internal_session = False |
|
124 self.default_mode = 'read' |
129 self.default_mode = 'read' |
|
130 # support undo for Create Update Delete entity / Add Remove relation |
|
131 if repo.config.creating or repo.config.repairing or self.is_internal_session: |
|
132 self.undo_actions = () |
|
133 else: |
|
134 self.undo_actions = set(repo.config['undo-support'].upper()) |
|
135 if self.undo_actions - set('CUDAR'): |
|
136 raise Exception('bad undo-support string in configuration') |
125 # short cut to querier .execute method |
137 # short cut to querier .execute method |
126 self._execute = repo.querier.execute |
138 self._execute = repo.querier.execute |
127 # shared data, used to communicate extra information between the client |
139 # shared data, used to communicate extra information between the client |
128 # and the rql server |
140 # and the rql server |
129 self.data = {} |
141 self.data = {} |
332 # \-> potentially, other calls to querier.execute |
344 # \-> potentially, other calls to querier.execute |
333 # |
345 # |
334 # so we can't rely on simply checking session.read_security, but |
346 # so we can't rely on simply checking session.read_security, but |
335 # recalling the first transition from DEFAULT_SECURITY to something |
347 # recalling the first transition from DEFAULT_SECURITY to something |
336 # else (False actually) is not perfect but should be enough |
348 # else (False actually) is not perfect but should be enough |
337 self._threaddata.dbapi_query = oldmode is self.DEFAULT_SECURITY |
349 # |
|
350 # also reset dbapi_query to true when we go back to DEFAULT_SECURITY |
|
351 self._threaddata.dbapi_query = (oldmode is self.DEFAULT_SECURITY |
|
352 or activated is self.DEFAULT_SECURITY) |
338 return oldmode |
353 return oldmode |
339 |
354 |
340 @property |
355 @property |
341 def write_security(self): |
356 def write_security(self): |
342 """return a boolean telling if write security is activated or not""" |
357 """return a boolean telling if write security is activated or not""" |
687 operation.handle_event('%s_event' % trstate) |
702 operation.handle_event('%s_event' % trstate) |
688 except: |
703 except: |
689 self.critical('error while %sing', trstate, |
704 self.critical('error while %sing', trstate, |
690 exc_info=sys.exc_info()) |
705 exc_info=sys.exc_info()) |
691 self.info('%s session %s done', trstate, self.id) |
706 self.info('%s session %s done', trstate, self.id) |
|
707 return self.transaction_uuid(set=False) |
692 finally: |
708 finally: |
693 self._clear_thread_data() |
709 self._clear_thread_data() |
694 self._touch() |
710 self._touch() |
695 if reset_pool: |
711 if reset_pool: |
696 self.reset_pool(ignoremode=True) |
712 self.reset_pool(ignoremode=True) |
767 if index is None: |
783 if index is None: |
768 self.pending_operations.append(operation) |
784 self.pending_operations.append(operation) |
769 else: |
785 else: |
770 self.pending_operations.insert(index, operation) |
786 self.pending_operations.insert(index, operation) |
771 |
787 |
|
788 # undo support ############################################################ |
|
789 |
|
790 def undoable_action(self, action, ertype): |
|
791 return action in self.undo_actions and not ertype in NO_UNDO_TYPES |
|
792 # XXX elif transaction on mark it partial |
|
793 |
|
794 def transaction_uuid(self, set=True): |
|
795 try: |
|
796 return self.transaction_data['tx_uuid'] |
|
797 except KeyError: |
|
798 if not set: |
|
799 return |
|
800 self.transaction_data['tx_uuid'] = uuid = uuid4().hex |
|
801 self.repo.system_source.start_undoable_transaction(self, uuid) |
|
802 return uuid |
|
803 |
|
804 def transaction_inc_action_counter(self): |
|
805 num = self.transaction_data.setdefault('tx_action_count', 0) + 1 |
|
806 self.transaction_data['tx_action_count'] = num |
|
807 return num |
|
808 |
772 # querier helpers ######################################################### |
809 # querier helpers ######################################################### |
773 |
810 |
774 @property |
811 @property |
775 def rql_rewriter(self): |
812 def rql_rewriter(self): |
776 # in thread local storage since the rewriter isn't thread safe |
813 # in thread local storage since the rewriter isn't thread safe |
888 return self.entity_from_eid(eid) |
925 return self.entity_from_eid(eid) |
889 |
926 |
890 |
927 |
891 class InternalSession(Session): |
928 class InternalSession(Session): |
892 """special session created internaly by the repository""" |
929 """special session created internaly by the repository""" |
|
930 is_internal_session = True |
893 |
931 |
894 def __init__(self, repo, cnxprops=None): |
932 def __init__(self, repo, cnxprops=None): |
895 super(InternalSession, self).__init__(InternalManager(), repo, cnxprops, |
933 super(InternalSession, self).__init__(InternalManager(), repo, cnxprops, |
896 _id='internal') |
934 _id='internal') |
897 self.user.req = self # XXX remove when "vreg = user.req.vreg" hack in entity.py is gone |
935 self.user.req = self # XXX remove when "vreg = user.req.vreg" hack in entity.py is gone |
898 self.cnxtype = 'inmemory' |
936 self.cnxtype = 'inmemory' |
899 self.is_internal_session = True |
|
900 self.disable_hook_categories('integrity') |
937 self.disable_hook_categories('integrity') |
901 |
938 |
902 |
939 |
903 class InternalManager(object): |
940 class InternalManager(object): |
904 """a manager user with all access rights used internally for task such as |
941 """a manager user with all access rights used internally for task such as |