server/session.py
changeset 8760 17994bf95d6a
parent 8694 d901c36bcfce
child 8761 9c6fb10d246a
equal deleted inserted replaced
8759:cd68cd879def 8760:17994bf95d6a
    46 NO_UNDO_TYPES.add('cw_source')
    46 NO_UNDO_TYPES.add('cw_source')
    47 # XXX rememberme,forgotpwd,apycot,vcsfile
    47 # XXX rememberme,forgotpwd,apycot,vcsfile
    48 
    48 
    49 @objectify_predicate
    49 @objectify_predicate
    50 def is_user_session(cls, req, **kwargs):
    50 def is_user_session(cls, req, **kwargs):
    51     """repository side only predicate returning 1 if the session is a regular
    51     """return 1 when session is not internal.
    52     user session and not an internal session
    52 
    53     """
    53     This predicate can only be used repository side only. """
    54     return not req.is_internal_session
    54     return not req.is_internal_session
    55 
    55 
    56 @objectify_predicate
    56 @objectify_predicate
    57 def is_internal_session(cls, req, **kwargs):
    57 def is_internal_session(cls, req, **kwargs):
    58     """repository side only predicate returning 1 if the session is not a regular
    58     """return 1 when session is not internal.
    59     user session but an internal session
    59 
    60     """
    60     This predicate can only be used repository side only. """
    61     return req.is_internal_session
    61     return req.is_internal_session
    62 
    62 
    63 @objectify_predicate
    63 @objectify_predicate
    64 def repairing(cls, req, **kwargs):
    64 def repairing(cls, req, **kwargs):
    65     """repository side only predicate returning 1 if the session is not a regular
    65     """return 1 when repository is running in repair mode"""
    66     user session but an internal session
       
    67     """
       
    68     return req.vreg.config.repairing
    66     return req.vreg.config.repairing
    69 
    67 
    70 
    68 
    71 class transaction(object):
    69 class transaction(object):
    72     """context manager to enter a transaction for a session: when exiting the
    70     """Ensure that the transaction is either commited or rollbacked at exit
       
    71 
       
    72     Context manager to enter a transaction for a session: when exiting the
    73     `with` block on exception, call `session.rollback()`, else call
    73     `with` block on exception, call `session.rollback()`, else call
    74     `session.commit()` on normal exit
    74     `session.commit()` on normal exit
    75     """
    75     """
    76     def __init__(self, session, free_cnxset=True):
    76     def __init__(self, session, free_cnxset=True):
    77         self.session = session
    77         self.session = session
   122     def __exit__(self, exctype, exc, traceback):
   122     def __exit__(self, exctype, exc, traceback):
   123         self.session.reset_hooks_mode_categories(self.oldmode, self.mode, self.changes)
   123         self.session.reset_hooks_mode_categories(self.oldmode, self.mode, self.changes)
   124 
   124 
   125 
   125 
   126 class security_enabled(object):
   126 class security_enabled(object):
   127     """context manager to control security w/ session.execute, since by
   127     """context manager to control security w/ session.execute,
   128     default security is disabled on queries executed on the repository
   128 
       
   129     By default security is disabled on queries executed on the repository
   129     side.
   130     side.
   130     """
   131     """
   131     def __init__(self, session, read=None, write=None):
   132     def __init__(self, session, read=None, write=None):
   132         self.session = session
   133         self.session = session
   133         self.read = read
   134         self.read = read
   140     def __exit__(self, exctype, exc, traceback):
   141     def __exit__(self, exctype, exc, traceback):
   141         self.session.reset_security(self.oldread, self.oldwrite)
   142         self.session.reset_security(self.oldread, self.oldwrite)
   142 
   143 
   143 
   144 
   144 class TransactionData(object):
   145 class TransactionData(object):
       
   146     """Small object hold core Transaction data"""
   145     def __init__(self, txid):
   147     def __init__(self, txid):
       
   148         #: transaction unique id
   146         self.transactionid = txid
   149         self.transactionid = txid
       
   150         #: reentrance handling
   147         self.ctx_count = 0
   151         self.ctx_count = 0
   148 
   152 
   149 
   153 
   150 class Session(RequestSessionBase):
   154 class Session(RequestSessionBase):
   151     """Repository usersession, tie a session id, user, connections set and
   155     """Repository user session
   152     other session data all together.
   156 
       
   157     This tie all together:
       
   158      * session id,
       
   159      * user,
       
   160      * connections set,
       
   161      * other session data.
   153 
   162 
   154     About session storage / transactions
   163     About session storage / transactions
   155     ------------------------------------
   164     ------------------------------------
   156 
   165 
   157     Here is a description of internal session attributes. Besides :attr:`data`
   166     Here is a description of internal session attributes. Besides :attr:`data`
   170       refers to the proper instance of :class:`TransactionData` according to the
   179       refers to the proper instance of :class:`TransactionData` according to the
   171       transaction.
   180       transaction.
   172 
   181 
   173       :attr:`_threads_in_transaction` is a set of (thread, connections set)
   182       :attr:`_threads_in_transaction` is a set of (thread, connections set)
   174       referencing threads that currently hold a connections set for the session.
   183       referencing threads that currently hold a connections set for the session.
       
   184     .. automethod:: cubicweb.server.session.transaction
   175 
   185 
   176     You should not have to use neither :attr:`_txdata` nor :attr:`__threaddata`,
   186     You should not have to use neither :attr:`_txdata` nor :attr:`__threaddata`,
   177     simply access transaction data transparently through the :attr:`_threaddata`
   187     simply access transaction data transparently through the :attr:`_threaddata`
   178     property. Also, you usually don't have to access it directly since current
   188     property. Also, you usually don't have to access it directly since current
   179     transaction's data may be accessed/modified through properties / methods:
   189     transaction's data may be accessed/modified through properties / methods:
   182       containing some shared data that should be cleared at the end of the
   192       containing some shared data that should be cleared at the end of the
   183       transaction. Hooks and operations may put arbitrary data in there, and
   193       transaction. Hooks and operations may put arbitrary data in there, and
   184       this may also be used as a communication channel between the client and
   194       this may also be used as a communication channel between the client and
   185       the repository.
   195       the repository.
   186 
   196 
       
   197     .. automethod:: cubicweb.server.session.Session.get_shared_data
       
   198     .. automethod:: cubicweb.server.session.Session.set_shared_data
       
   199     .. automethod:: cubicweb.server.session.Session.added_in_transaction
       
   200     .. automethod:: cubicweb.server.session.Session.deleted_in_transaction
       
   201 
       
   202     Transaction state information:
       
   203 
       
   204       :attr:`running_dbapi_query`, boolean flag telling if the executing query
       
   205       is coming from a dbapi connection or is a query from within the repository
       
   206 
   187       :attr:`cnxset`, the connections set to use to execute queries on sources.
   207       :attr:`cnxset`, the connections set to use to execute queries on sources.
   188       During a transaction, the connection set may be freed so that is may be
   208       During a transaction, the connection set may be freed so that is may be
   189       used by another session as long as no writing is done. This means we can
   209       used by another session as long as no writing is done. This means we can
   190       have multiple sessions with a reasonably low connections set pool size.
   210       have multiple sessions with a reasonably low connections set pool size.
       
   211 
       
   212     .. automethod:: cubicweb.server.session.set_cnxset
       
   213     .. automethod:: cubicweb.server.session.free_cnxset
   191 
   214 
   192       :attr:`mode`, string telling the connections set handling mode, may be one
   215       :attr:`mode`, string telling the connections set handling mode, may be one
   193       of 'read' (connections set may be freed), 'write' (some write was done in
   216       of 'read' (connections set may be freed), 'write' (some write was done in
   194       the connections set, it can't be freed before end of the transaction),
   217       the connections set, it can't be freed before end of the transaction),
   195       'transaction' (we want to keep the connections set during all the
   218       'transaction' (we want to keep the connections set during all the
   202       of None (not yet committing), 'precommit' (calling precommit event on
   225       of None (not yet committing), 'precommit' (calling precommit event on
   203       operations), 'postcommit' (calling postcommit event on operations),
   226       operations), 'postcommit' (calling postcommit event on operations),
   204       'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error
   227       'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error
   205       has been raised during the transaction and so it must be rollbacked).
   228       has been raised during the transaction and so it must be rollbacked).
   206 
   229 
       
   230     .. automethod:: cubicweb.server.session.Session.commit
       
   231     .. automethod:: cubicweb.server.session.Session.rollback
       
   232     .. automethod:: cubicweb.server.session.Session.close
       
   233     .. automethod:: cubicweb.server.session.Session.closed
       
   234 
       
   235     Security level Management:
       
   236 
   207       :attr:`read_security` and :attr:`write_security`, boolean flags telling if
   237       :attr:`read_security` and :attr:`write_security`, boolean flags telling if
   208       read/write security is currently activated.
   238       read/write security is currently activated.
   209 
   239 
       
   240     .. automethod:: cubicweb.server.session.Session.set_write_security
       
   241     .. automethod:: cubicweb.server.session.Session.set_read_security
       
   242     .. automethod:: cubicweb.server.session.Session.init_security
       
   243     .. automethod:: cubicweb.server.session.Session.reset_security
       
   244     .. automethod:: cubicweb.server.session.Session.security_enabled
       
   245 
       
   246     Hooks Management:
       
   247 
   210       :attr:`hooks_mode`, may be either `HOOKS_ALLOW_ALL` or `HOOKS_DENY_ALL`.
   248       :attr:`hooks_mode`, may be either `HOOKS_ALLOW_ALL` or `HOOKS_DENY_ALL`.
   211 
   249 
   212       :attr:`enabled_hook_categories`, when :attr:`hooks_mode` is
   250       :attr:`enabled_hook_categories`, when :attr:`hooks_mode` is
   213       `HOOKS_DENY_ALL`, this set contains hooks categories that are enabled.
   251       `HOOKS_DENY_ALL`, this set contains hooks categories that are enabled.
   214 
   252 
   215       :attr:`disabled_hook_categories`, when :attr:`hooks_mode` is
   253       :attr:`disabled_hook_categories`, when :attr:`hooks_mode` is
   216       `HOOKS_ALLOW_ALL`, this set contains hooks categories that are disabled.
   254       `HOOKS_ALLOW_ALL`, this set contains hooks categories that are disabled.
   217 
   255 
   218 
   256     .. automethod:: cubicweb.server.session.Session.deny_all_hooks_but
   219       :attr:`running_dbapi_query`, boolean flag telling if the executing query
   257     .. automethod:: cubicweb.server.session.Session.allow_all_hooks_but
   220       is coming from a dbapi connection or is a query from within the repository
   258     .. automethod:: cubicweb.server.session.Session.is_hook_category_activated
   221 
   259     .. automethod:: cubicweb.server.session.Session.is_hook_activated
   222     .. automethod:: cubicweb.server.session.deny_all_hooks_but
   260 
   223     .. automethod:: cubicweb.server.session.all_all_hooks_but
   261     Data manipulation:
       
   262 
       
   263     .. automethod:: cubicweb.server.session.Session.add_relation
       
   264     .. automethod:: cubicweb.server.session.Session.add_relations
       
   265     .. automethod:: cubicweb.server.session.Session.delete_relation
       
   266 
       
   267     Other:
       
   268 
       
   269     .. automethod:: cubicweb.server.session.Session.call_service
       
   270 
       
   271 
       
   272 
   224     """
   273     """
   225     is_request = False
   274     is_request = False
   226     is_internal_session = False
   275     is_internal_session = False
   227 
   276 
   228     def __init__(self, user, repo, cnxprops=None, _id=None):
   277     def __init__(self, user, repo, cnxprops=None, _id=None):
   244         self.data = {}
   293         self.data = {}
   245         # i18n initialization
   294         # i18n initialization
   246         self.set_language(user.prefered_language())
   295         self.set_language(user.prefered_language())
   247         # internals
   296         # internals
   248         self._tx_data = {}
   297         self._tx_data = {}
       
   298         # Data local to the thread
   249         self.__threaddata = threading.local()
   299         self.__threaddata = threading.local()
   250         self._threads_in_transaction = set()
   300         self._threads_in_transaction = set()
   251         self._closed = False
   301         self._closed = False
   252         self._closed_lock = threading.Lock()
   302         self._closed_lock = threading.Lock()
   253 
   303