cubicweb/hooks/integrity.py
author Denis Laxalde <denis.laxalde@logilab.fr>
Fri, 05 Apr 2019 17:58:19 +0200
changeset 12567 26744ad37953
parent 11767 432f87a63057
permissions -rw-r--r--
Drop python2 support This mostly consists in removing the dependency on "six" and updating the code to use only Python3 idioms. Notice that we previously used TemporaryDirectory from cubicweb.devtools.testlib for compatibility with Python2. We now directly import it from tempfile.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11767
432f87a63057 flake8 and all
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11765
diff changeset
     1
# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    18
"""Core hooks: check for data integrity according to the instance'schema
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    19
validity
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    20
"""
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    21
10666
7f6b5f023884 [py3k] replace '_ = unicode' in global scope (closes #7589459)
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
    22
from cubicweb import _
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    23
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    24
from threading import Lock
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    25
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
    26
from cubicweb import validation_error, neg_role
6375
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    27
from cubicweb.schema import (META_RTYPES, WORKFLOW_RTYPES,
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    28
                             RQLConstraint, RQLUniqueConstraint)
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
    29
from cubicweb.predicates import is_instance, composite_etype
4023
eae23c40627a drop common subpackage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4003
diff changeset
    30
from cubicweb.uilib import soup2xhtml
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    31
from cubicweb.server import hook
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    32
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    33
# special relations that don't have to be checked for integrity, usually
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    34
# because they are handled internally by hooks (so we trust ourselves)
6375
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    35
DONT_CHECK_RTYPES_ON_ADD = META_RTYPES | WORKFLOW_RTYPES
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    36
DONT_CHECK_RTYPES_ON_DEL = META_RTYPES | WORKFLOW_RTYPES
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    37
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    38
_UNIQUE_CONSTRAINTS_LOCK = Lock()
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    39
_UNIQUE_CONSTRAINTS_HOLDER = None
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    40
4517
0f3c10fc42b2 backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4498
diff changeset
    41
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    42
def _acquire_unique_cstr_lock(cnx):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    43
    """acquire the _UNIQUE_CONSTRAINTS_LOCK for the cnx.
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    44
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    45
    This lock used to avoid potential integrity pb when checking
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    46
    RQLUniqueConstraint in two different transactions, as explained in
10893
351c82df25be [hooks] update internal URL in doc string
Julien Cristau <julien.cristau@logilab.fr>
parents: 10689
diff changeset
    47
    https://extranet.logilab.fr/3577926
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    48
    """
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    49
    if 'uniquecstrholder' in cnx.transaction_data:
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    50
        return
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    51
    _UNIQUE_CONSTRAINTS_LOCK.acquire()
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    52
    cnx.transaction_data['uniquecstrholder'] = True
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    53
    # register operation responsible to release the lock on commit/rollback
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    54
    _ReleaseUniqueConstraintsOperation(cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    55
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    56
def _release_unique_cstr_lock(cnx):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    57
    if 'uniquecstrholder' in cnx.transaction_data:
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    58
        del cnx.transaction_data['uniquecstrholder']
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    59
        _UNIQUE_CONSTRAINTS_LOCK.release()
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    60
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    61
class _ReleaseUniqueConstraintsOperation(hook.Operation):
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    62
    def postcommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    63
        _release_unique_cstr_lock(self.cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    64
    def rollback_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    65
        _release_unique_cstr_lock(self.cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    66
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    67
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    68
class _CheckRequiredRelationOperation(hook.DataOperationMixIn,
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    69
                                      hook.LateOperation):
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    70
    """checking relation cardinality has to be done after commit in case the
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    71
    relation is being replaced
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    72
    """
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    73
    containercls = list
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    74
    role = key = base_rql = None
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    75
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    76
    def precommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    77
        cnx = self.cnx
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    78
        pendingeids = cnx.transaction_data.get('pendingeids', ())
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    79
        pendingrtypes = cnx.transaction_data.get('pendingrtypes', ())
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    80
        for eid, rtype in self.get_data():
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    81
            # recheck pending eids / relation types
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    82
            if eid in pendingeids:
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    83
                continue
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    84
            if rtype in pendingrtypes:
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    85
                continue
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    86
            if not cnx.execute(self.base_rql % rtype, {'x': eid}):
11765
9cb215e833b0 [cnx] Use entity_type instead of entity_metas()['type']
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11366
diff changeset
    87
                etype = cnx.entity_type(eid)
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    88
                msg = _('at least one relation %(rtype)s is required on '
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    89
                        '%(etype)s (%(eid)s)')
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    90
                raise validation_error(eid, {(rtype, self.role): msg},
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    91
                                       {'rtype': rtype, 'etype': etype, 'eid': eid},
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    92
                                       ['rtype', 'etype'])
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    93
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    94
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    95
class _CheckSRelationOp(_CheckRequiredRelationOperation):
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    96
    """check required subject relation"""
5030
5238d9a8dfee [form] put qualified name on validation error, should fix #784299
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5007
diff changeset
    97
    role = 'subject'
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    98
    base_rql = 'Any O WHERE S eid %%(x)s, S %s O'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    99
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   100
class _CheckORelationOp(_CheckRequiredRelationOperation):
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   101
    """check required object relation"""
5030
5238d9a8dfee [form] put qualified name on validation error, should fix #784299
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5007
diff changeset
   102
    role = 'object'
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   103
    base_rql = 'Any S WHERE O eid %%(x)s, S %s O'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   104
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   105
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   106
class IntegrityHook(hook.Hook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   107
    __abstract__ = True
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   108
    category = 'integrity'
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   109
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   110
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   111
class _EnsureSymmetricRelationsAdd(hook.Hook):
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   112
    """ ensure X r Y => Y r X iff r is symmetric """
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   113
    __regid__ = 'cw.add_ensure_symmetry'
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   114
    __abstract__ = True
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   115
    category = 'activeintegrity'
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   116
    events = ('after_add_relation',)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   117
    # __select__ is set in the registration callback
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   118
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   119
    def __call__(self):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   120
        self._cw.repo.system_source.add_relation(self._cw, self.eidto,
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   121
                                                 self.rtype, self.eidfrom)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   122
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   123
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   124
class _EnsureSymmetricRelationsDelete(hook.Hook):
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   125
    """ ensure X r Y => Y r X iff r is symmetric """
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   126
    __regid__ = 'cw.delete_ensure_symmetry'
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   127
    __abstract__ = True
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   128
    category = 'activeintegrity'
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   129
    events = ('after_delete_relation',)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   130
    # __select__ is set in the registration callback
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   131
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   132
    def __call__(self):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   133
        self._cw.repo.system_source.delete_relation(self._cw, self.eidto,
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   134
                                                    self.rtype, self.eidfrom)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   135
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   136
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   137
class CheckCardinalityHookBeforeDeleteRelation(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   138
    """check cardinalities are satisfied"""
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   139
    __regid__ = 'checkcard_before_delete_relation'
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   140
    events = ('before_delete_relation',)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   141
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   142
    def __call__(self):
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   143
        rtype = self.rtype
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   144
        if rtype in DONT_CHECK_RTYPES_ON_DEL:
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   145
            return
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   146
        cnx = self._cw
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   147
        eidfrom, eidto = self.eidfrom, self.eidto
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   148
        rdef = cnx.rtype_eids_rdef(rtype, eidfrom, eidto)
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   149
        if (rdef.subject, rtype, rdef.object) in cnx.transaction_data.get('pendingrdefs', ()):
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   150
            return
7502
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   151
        card = rdef.cardinality
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   152
        if card[0] in '1+' and not cnx.deleted_in_transaction(eidfrom):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   153
            _CheckSRelationOp.get_instance(cnx).add_data((eidfrom, rtype))
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   154
        if card[1] in '1+' and not cnx.deleted_in_transaction(eidto):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   155
            _CheckORelationOp.get_instance(cnx).add_data((eidto, rtype))
7495
09d245a9bf5f [hooks] use local variable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7494
diff changeset
   156
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   157
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   158
class CheckCardinalityHookAfterAddEntity(IntegrityHook):
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   159
    """check cardinalities are satisfied"""
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   160
    __regid__ = 'checkcard_after_add_entity'
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   161
    events = ('after_add_entity',)
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   162
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   163
    def __call__(self):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   164
        eid = self.entity.eid
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   165
        eschema = self.entity.e_schema
3890
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   166
        for rschema, targetschemas, role in eschema.relation_definitions():
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   167
            # skip automatically handled relations
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   168
            if rschema.type in DONT_CHECK_RTYPES_ON_ADD:
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   169
                continue
3890
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   170
            rdef = rschema.role_rdef(eschema, targetschemas[0], role)
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   171
            if rdef.role_cardinality(role) in '1+':
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   172
                if role == 'subject':
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   173
                    op = _CheckSRelationOp.get_instance(self._cw)
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   174
                else:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   175
                    op = _CheckORelationOp.get_instance(self._cw)
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   176
                op.add_data((eid, rschema.type))
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   177
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   178
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   179
class _CheckConstraintsOp(hook.DataOperationMixIn, hook.LateOperation):
5450
269dcd14b92c [hooks/integrity & tests/entities] fix test to check for sibling error (set_operations yields a different order for constraints)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5449
diff changeset
   180
    """ check a new relation satisfy its constraints """
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   181
    containercls = list
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   182
    def precommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   183
        cnx = self.cnx
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   184
        for values in self.get_data():
5450
269dcd14b92c [hooks/integrity & tests/entities] fix test to check for sibling error (set_operations yields a different order for constraints)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5449
diff changeset
   185
            eidfrom, rtype, eidto, constraints = values
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   186
            # first check related entities have not been deleted in the same
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   187
            # transaction
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   188
            if cnx.deleted_in_transaction(eidfrom):
6894
ba3f7e655414 we must check constraint for all concerned entities and not stop at the first deleted one
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6889
diff changeset
   189
                continue
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   190
            if cnx.deleted_in_transaction(eidto):
6894
ba3f7e655414 we must check constraint for all concerned entities and not stop at the first deleted one
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6889
diff changeset
   191
                continue
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   192
            for constraint in constraints:
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   193
                # XXX
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   194
                # * lock RQLConstraint as well?
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   195
                # * use a constraint id to use per constraint lock and avoid
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   196
                #   unnecessary commit serialization ?
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   197
                if isinstance(constraint, RQLUniqueConstraint):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   198
                    _acquire_unique_cstr_lock(cnx)
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   199
                try:
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   200
                    constraint.repo_check(cnx, eidfrom, rtype, eidto)
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   201
                except NotImplementedError:
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   202
                    self.critical('can\'t check constraint %s, not supported',
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   203
                                  constraint)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   204
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   205
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   206
class CheckConstraintHook(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   207
    """check the relation satisfy its constraints
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   208
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   209
    this is delayed to a precommit time operation since other relation which
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   210
    will make constraint satisfied (or unsatisfied) may be added later.
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   211
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   212
    __regid__ = 'checkconstraint'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   213
    events = ('after_add_relation',)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   214
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   215
    def __call__(self):
3998
94cc7cad3d2d backport stable into default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3894
diff changeset
   216
        # XXX get only RQL[Unique]Constraints?
7502
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   217
        rdef = self._cw.rtype_eids_rdef(self.rtype, self.eidfrom, self.eidto)
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   218
        constraints = rdef.constraints
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   219
        if constraints:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   220
            _CheckConstraintsOp.get_instance(self._cw).add_data(
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   221
                (self.eidfrom, self.rtype, self.eidto, constraints))
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   222
4027
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
   223
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   224
class CheckAttributeConstraintHook(IntegrityHook):
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   225
    """check the attribute relation satisfy its constraints
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   226
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   227
    this is delayed to a precommit time operation since other relation which
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   228
    will make constraint satisfied (or unsatisfied) may be added later.
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   229
    """
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   230
    __regid__ = 'checkattrconstraint'
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   231
    events = ('after_add_entity', 'after_update_entity')
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   232
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   233
    def __call__(self):
4190
742e3eb16f81 fix bad merge
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4181
diff changeset
   234
        eschema = self.entity.e_schema
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   235
        for attr in self.entity.cw_edited:
4181
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4075
diff changeset
   236
            if eschema.subjrels[attr].final:
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4075
diff changeset
   237
                constraints = [c for c in eschema.rdef(attr).constraints
3998
94cc7cad3d2d backport stable into default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3894
diff changeset
   238
                               if isinstance(c, (RQLUniqueConstraint, RQLConstraint))]
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   239
                if constraints:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   240
                    _CheckConstraintsOp.get_instance(self._cw).add_data(
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   241
                        (self.entity.eid, attr, None, constraints))
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   242
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   243
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   244
class DontRemoveOwnersGroupHook(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   245
    """delete the composed of a composite relation when this relation is deleted
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   246
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   247
    __regid__ = 'checkownersgroup'
5877
0c7b7b76a84f [selectors] provide a new, optimized, is_instance selector that should at some point replace implements (along with the adaptable selector)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5538
diff changeset
   248
    __select__ = IntegrityHook.__select__ & is_instance('CWGroup')
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   249
    events = ('before_delete_entity', 'before_update_entity')
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   250
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   251
    def __call__(self):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   252
        entity = self.entity
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   253
        if self.event == 'before_delete_entity' and entity.name == 'owners':
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
   254
            raise validation_error(entity, {None: _("can't be deleted")})
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   255
        elif self.event == 'before_update_entity' \
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   256
                 and 'name' in entity.cw_edited:
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   257
            oldname, newname = entity.cw_edited.oldnewvalue('name')
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   258
            if oldname == 'owners' and newname != oldname:
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
   259
                raise validation_error(entity, {('name', 'subject'): _("can't be changed")})
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   260
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   261
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   262
class TidyHtmlFields(IntegrityHook):
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   263
    """tidy HTML in rich text strings"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   264
    __regid__ = 'htmltidy'
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   265
    events = ('before_add_entity', 'before_update_entity')
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   266
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   267
    def __call__(self):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   268
        entity = self.entity
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   269
        metaattrs = entity.e_schema.meta_attributes()
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   270
        edited = entity.cw_edited
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 9680
diff changeset
   271
        for metaattr, (metadata, attr) in metaattrs.items():
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   272
            if metadata == 'format' and attr in edited:
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   273
                try:
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   274
                    value = edited[attr]
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   275
                except KeyError:
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   276
                    continue # no text to tidy
12567
26744ad37953 Drop python2 support
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11767
diff changeset
   277
                if isinstance(value, str): # filter out None and Binary
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   278
                    if getattr(entity, str(metaattr)) == 'text/html':
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   279
                        edited[attr] = soup2xhtml(value, self._cw.encoding)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   280
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   281
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   282
class StripCWUserLoginHook(IntegrityHook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   283
    """ensure user logins are stripped"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   284
    __regid__ = 'stripuserlogin'
5877
0c7b7b76a84f [selectors] provide a new, optimized, is_instance selector that should at some point replace implements (along with the adaptable selector)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5538
diff changeset
   285
    __select__ = IntegrityHook.__select__ & is_instance('CWUser')
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   286
    events = ('before_add_entity', 'before_update_entity',)
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   287
2900
9d65e0350aa1 api update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2896
diff changeset
   288
    def __call__(self):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   289
        login = self.entity.cw_edited.get('login')
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   290
        if login:
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   291
            self.entity.cw_edited['login'] = login.strip()
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   292
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   293
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   294
class DeleteCompositeOrphanHook(hook.Hook):
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   295
    """Delete the composed of a composite relation when the composite is
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   296
    deleted (this is similar to the cascading ON DELETE CASCADE
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   297
    semantics of sql).
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   298
    """
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   299
    __regid__ = 'deletecomposite'
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   300
    __select__ = hook.Hook.__select__ & composite_etype()
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   301
    events = ('before_delete_entity',)
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   302
    category = 'activeintegrity'
9680
8fb8f001f4e2 [hooks] run cascading delete hook later
Julien Cristau <julien.cristau@logilab.fr>
parents: 9613
diff changeset
   303
    # give the application's before_delete_entity hooks a chance to run before we cascade
8fb8f001f4e2 [hooks] run cascading delete hook later
Julien Cristau <julien.cristau@logilab.fr>
parents: 9613
diff changeset
   304
    order = 99
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   305
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   306
    def __call__(self):
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   307
        eid = self.entity.eid
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   308
        for rdef, role in self.entity.e_schema.composite_rdef_roles:
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   309
            rtype = rdef.rtype.type
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   310
            target = getattr(rdef, neg_role(role))
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   311
            expr = ('C %s X' % rtype) if role == 'subject' else ('X %s C' % rtype)
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   312
            self._cw.execute('DELETE %s X WHERE C eid %%(c)s, %s' % (target, expr),
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   313
                             {'c': eid})
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   314
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   315
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   316
def registration_callback(vreg):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   317
    vreg.register_all(globals().values(), __name__)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   318
    symmetric_rtypes = [rschema.type for rschema in vreg.schema.relations()
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   319
                        if rschema.symmetric]
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   320
    class EnsureSymmetricRelationsAdd(_EnsureSymmetricRelationsAdd):
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   321
        __select__ = _EnsureSymmetricRelationsAdd.__select__ & hook.match_rtype(*symmetric_rtypes)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   322
    vreg.register(EnsureSymmetricRelationsAdd)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   323
    class EnsureSymmetricRelationsDelete(_EnsureSymmetricRelationsDelete):
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   324
        __select__ = _EnsureSymmetricRelationsDelete.__select__ & hook.match_rtype(*symmetric_rtypes)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   325
    vreg.register(EnsureSymmetricRelationsDelete)