server/repository.py
changeset 4835 13b0b96d7982
parent 4834 b718626a0e60
child 4843 5f7363416765
equal deleted inserted replaced
4834:b718626a0e60 4835:13b0b96d7982
    13 :organization: Logilab
    13 :organization: Logilab
    14 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
    14 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
    15 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
    15 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
    16 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
    16 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
    17 """
    17 """
       
    18 from __future__ import with_statement
       
    19 
    18 __docformat__ = "restructuredtext en"
    20 __docformat__ = "restructuredtext en"
    19 
    21 
    20 import sys
    22 import sys
    21 import Queue
    23 import Queue
    22 from os.path import join
    24 from os.path import join
    34                       ETypeNotSupportedBySources, MultiSourcesError,
    36                       ETypeNotSupportedBySources, MultiSourcesError,
    35                       BadConnectionId, Unauthorized, ValidationError,
    37                       BadConnectionId, Unauthorized, ValidationError,
    36                       typed_eid)
    38                       typed_eid)
    37 from cubicweb import cwvreg, schema, server
    39 from cubicweb import cwvreg, schema, server
    38 from cubicweb.server import utils, hook, pool, querier, sources
    40 from cubicweb.server import utils, hook, pool, querier, sources
    39 from cubicweb.server.session import Session, InternalSession
    41 from cubicweb.server.session import Session, InternalSession, security_enabled
    40 
    42 
    41 
    43 
    42 class CleanupEidTypeCacheOp(hook.SingleLastOperation):
    44 class CleanupEidTypeCacheOp(hook.SingleLastOperation):
    43     """on rollback of a insert query or commit of delete query, we have to
    45     """on rollback of a insert query or commit of delete query, we have to
    44     clear repository's cache from no more valid entries
    46     clear repository's cache from no more valid entries
    78     an entity without a relation for some time
    80     an entity without a relation for some time
    79 
    81 
    80     this kind of behaviour has to be done in the repository so we don't have
    82     this kind of behaviour has to be done in the repository so we don't have
    81     hooks order hazardness
    83     hooks order hazardness
    82     """
    84     """
    83     # XXX now that rql in migraction default to unsafe_execute we don't want to
    85     # skip that for internal session or if integrity explicitly disabled
    84     #     skip that for super session (though we can still skip it for internal
    86     #
    85     #     sessions). Also we should imo rely on the orm to first fetch existing
    87     # XXX we should imo rely on the orm to first fetch existing entity if any
    86     #     entity if any then delete it.
    88     # then delete it.
    87     if session.is_internal_session \
    89     if session.is_internal_session \
    88            or not session.is_hooks_category_activated('integrity'):
    90            or not session.is_hooks_category_activated('integrity'):
    89         return
    91         return
    90     card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
    92     card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
    91     # one may be tented to check for neweids but this may cause more than one
    93     # one may be tented to check for neweids but this may cause more than one
    98     # XXX we don't want read permissions to be applied but we want delete
   100     # XXX we don't want read permissions to be applied but we want delete
    99     # permission to be checked
   101     # permission to be checked
   100     rschema = session.repo.schema.rschema(rtype)
   102     rschema = session.repo.schema.rschema(rtype)
   101     if card[0] in '1?':
   103     if card[0] in '1?':
   102         if not rschema.inlined: # inlined relations will be implicitly deleted
   104         if not rschema.inlined: # inlined relations will be implicitly deleted
   103             rset = session.unsafe_execute('Any X,Y WHERE X %s Y, X eid %%(x)s, '
   105             with security_enabled(session, read=False):
   104                                           'NOT Y eid %%(y)s' % rtype,
   106                 session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
   105                                           {'x': eidfrom, 'y': eidto}, 'x')
   107                                 'NOT Y eid %%(y)s' % rtype,
   106             if rset:
   108                                 {'x': eidfrom, 'y': eidto}, 'x')
   107                 safe_delete_relation(session, rschema, *rset[0])
       
   108     if card[1] in '1?':
   109     if card[1] in '1?':
   109         rset = session.unsafe_execute('Any X,Y WHERE X %s Y, Y eid %%(y)s, '
   110         with security_enabled(session, read=False):
   110                                       'NOT X eid %%(x)s' % rtype,
   111             session.execute('DELETE X %sY WHERE Y eid %%(y)s, '
   111                                       {'x': eidfrom, 'y': eidto}, 'y')
   112                             'NOT X eid %%(x)s' % rtype,
   112         if rset:
   113                             {'x': eidfrom, 'y': eidto}, 'y')
   113             safe_delete_relation(session, rschema, *rset[0])
       
   114 
       
   115 
       
   116 def safe_delete_relation(session, rschema, subject, object):
       
   117     if not rschema.has_perm(session, 'delete', fromeid=subject, toeid=object):
       
   118         raise Unauthorized()
       
   119     session.repo.glob_delete_relation(session, subject, rschema.type, object)
       
   120 
   114 
   121 
   115 
   122 class Repository(object):
   116 class Repository(object):
   123     """a repository provides access to a set of persistent storages for
   117     """a repository provides access to a set of persistent storages for
   124     entities and relations
   118     entities and relations
   916         its relations
   910         its relations
   917         """
   911         """
   918         rql = []
   912         rql = []
   919         eschema = self.schema.eschema(etype)
   913         eschema = self.schema.eschema(etype)
   920         pendingrtypes = session.transaction_data.get('pendingrtypes', ())
   914         pendingrtypes = session.transaction_data.get('pendingrtypes', ())
   921         for rschema, targetschemas, x in eschema.relation_definitions():
   915         with security_enabled(session, read=False, write=False):
   922             rtype = rschema.type
   916             for rschema, targetschemas, x in eschema.relation_definitions():
   923             if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes:
   917                 rtype = rschema.type
   924                 continue
   918                 if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes:
   925             var = '%s%s' % (rtype.upper(), x.upper())
   919                     continue
   926             if x == 'subject':
   920                 var = '%s%s' % (rtype.upper(), x.upper())
   927                 # don't skip inlined relation so they are regularly
   921                 if x == 'subject':
   928                 # deleted and so hooks are correctly called
   922                     # don't skip inlined relation so they are regularly
   929                 selection = 'X %s %s' % (rtype, var)
   923                     # deleted and so hooks are correctly called
   930             else:
   924                     selection = 'X %s %s' % (rtype, var)
   931                 selection = '%s %s X' % (var, rtype)
   925                 else:
   932             rql = 'DELETE %s WHERE X eid %%(x)s' % selection
   926                     selection = '%s %s X' % (var, rtype)
   933             # unsafe_execute since we suppose that if user can delete the entity,
   927                 rql = 'DELETE %s WHERE X eid %%(x)s' % selection
   934             # he can delete all its relations without security checking
   928                 # if user can delete the entity, he can delete all its relations
   935             session.unsafe_execute(rql, {'x': eid}, 'x', build_descr=False)
   929                 # without security checking
       
   930                 session.execute(rql, {'x': eid}, 'x', build_descr=False)
   936 
   931 
   937     def locate_relation_source(self, session, subject, rtype, object):
   932     def locate_relation_source(self, session, subject, rtype, object):
   938         subjsource = self.source_from_eid(subject, session)
   933         subjsource = self.source_from_eid(subject, session)
   939         objsource = self.source_from_eid(object, session)
   934         objsource = self.source_from_eid(object, session)
   940         if not subjsource is objsource:
   935         if not subjsource is objsource: