25 point to a cubicweb instance. |
25 point to a cubicweb instance. |
26 * handles session management |
26 * handles session management |
27 """ |
27 """ |
28 __docformat__ = "restructuredtext en" |
28 __docformat__ = "restructuredtext en" |
29 |
29 |
30 import sys |
|
31 import threading |
30 import threading |
32 import Queue |
31 import Queue |
33 from warnings import warn |
32 from warnings import warn |
34 from itertools import chain |
33 from itertools import chain |
35 from time import time, localtime, strftime |
34 from time import time, localtime, strftime |
36 from contextlib import contextmanager |
35 from contextlib import contextmanager |
37 from warnings import warn |
|
38 |
36 |
39 from logilab.common.decorators import cached, clear_cache |
37 from logilab.common.decorators import cached, clear_cache |
40 from logilab.common.deprecation import deprecated |
38 from logilab.common.deprecation import deprecated |
41 |
39 |
42 from yams import BadSchemaDefinition |
40 from yams import BadSchemaDefinition |
43 from rql import RQLSyntaxError |
|
44 from rql.utils import rqlvar_maker |
41 from rql.utils import rqlvar_maker |
45 |
42 |
46 from cubicweb import (CW_MIGRATION_MAP, QueryError, |
43 from cubicweb import (CW_MIGRATION_MAP, QueryError, |
47 UnknownEid, AuthenticationError, ExecutionError, |
44 UnknownEid, AuthenticationError, ExecutionError, |
48 BadConnectionId, Unauthorized, ValidationError, |
45 BadConnectionId, ValidationError, |
49 UniqueTogetherError, onevent) |
46 UniqueTogetherError, onevent) |
50 from cubicweb import cwvreg, schema, server |
47 from cubicweb import cwvreg, schema, server |
51 from cubicweb.server import ShuttingDown, utils, hook, querier, sources |
48 from cubicweb.server import ShuttingDown, utils, hook, querier, sources |
52 from cubicweb.server.session import Session, InternalManager |
49 from cubicweb.server.session import Session, InternalManager |
53 from cubicweb.server.ssplanner import EditedEntity |
|
54 |
50 |
55 NO_CACHE_RELATIONS = set( [('owned_by', 'object'), |
51 NO_CACHE_RELATIONS = set( [('owned_by', 'object'), |
56 ('created_by', 'object'), |
52 ('created_by', 'object'), |
57 ('cw_source', 'object'), |
53 ('cw_source', 'object'), |
58 ]) |
54 ]) |
59 |
55 |
60 def prefill_entity_caches(entity): |
56 def prefill_entity_caches(entity): |
61 session = entity._cw |
57 cnx = entity._cw |
62 # prefill entity relation caches |
58 # prefill entity relation caches |
63 for rschema in entity.e_schema.subject_relations(): |
59 for rschema in entity.e_schema.subject_relations(): |
64 rtype = str(rschema) |
60 rtype = str(rschema) |
65 if rtype in schema.VIRTUAL_RTYPES or (rtype, 'subject') in NO_CACHE_RELATIONS: |
61 if rtype in schema.VIRTUAL_RTYPES or (rtype, 'subject') in NO_CACHE_RELATIONS: |
66 continue |
62 continue |
67 if rschema.final: |
63 if rschema.final: |
68 entity.cw_attr_cache.setdefault(rtype, None) |
64 entity.cw_attr_cache.setdefault(rtype, None) |
69 else: |
65 else: |
70 entity.cw_set_relation_cache(rtype, 'subject', |
66 entity.cw_set_relation_cache(rtype, 'subject', |
71 session.empty_rset()) |
67 cnx.empty_rset()) |
72 for rschema in entity.e_schema.object_relations(): |
68 for rschema in entity.e_schema.object_relations(): |
73 rtype = str(rschema) |
69 rtype = str(rschema) |
74 if rtype in schema.VIRTUAL_RTYPES or (rtype, 'object') in NO_CACHE_RELATIONS: |
70 if rtype in schema.VIRTUAL_RTYPES or (rtype, 'object') in NO_CACHE_RELATIONS: |
75 continue |
71 continue |
76 entity.cw_set_relation_cache(rtype, 'object', session.empty_rset()) |
72 entity.cw_set_relation_cache(rtype, 'object', cnx.empty_rset()) |
77 |
73 |
78 def del_existing_rel_if_needed(session, eidfrom, rtype, eidto): |
74 def del_existing_rel_if_needed(cnx, eidfrom, rtype, eidto): |
79 """delete existing relation when adding a new one if card is 1 or ? |
75 """delete existing relation when adding a new one if card is 1 or ? |
80 |
76 |
81 have to be done once the new relation has been inserted to avoid having |
77 have to be done once the new relation has been inserted to avoid having |
82 an entity without a relation for some time |
78 an entity without a relation for some time |
83 |
79 |
84 this kind of behaviour has to be done in the repository so we don't have |
80 this kind of behaviour has to be done in the repository so we don't have |
85 hooks order hazardness |
81 hooks order hazardness |
86 """ |
82 """ |
87 # skip that if integrity explicitly disabled |
83 # skip that if integrity explicitly disabled |
88 if not session.is_hook_category_activated('activeintegrity'): |
84 if not cnx.is_hook_category_activated('activeintegrity'): |
89 return |
85 return |
90 rdef = session.rtype_eids_rdef(rtype, eidfrom, eidto) |
86 rdef = cnx.rtype_eids_rdef(rtype, eidfrom, eidto) |
91 card = rdef.cardinality |
87 card = rdef.cardinality |
92 # one may be tented to check for neweids but this may cause more than one |
88 # one may be tented to check for neweids but this may cause more than one |
93 # relation even with '1?' cardinality if thoses relations are added in the |
89 # relation even with '1?' cardinality if thoses relations are added in the |
94 # same transaction where the entity is being created. This never occurs from |
90 # same transaction where the entity is being created. This never occurs from |
95 # the web interface but may occurs during test or dbapi connection (though |
91 # the web interface but may occurs during test or dbapi connection (though |
99 # notes: |
95 # notes: |
100 # * inlined relations will be implicitly deleted for the subject entity |
96 # * inlined relations will be implicitly deleted for the subject entity |
101 # * we don't want read permissions to be applied but we want delete |
97 # * we don't want read permissions to be applied but we want delete |
102 # permission to be checked |
98 # permission to be checked |
103 if card[0] in '1?': |
99 if card[0] in '1?': |
104 with session.security_enabled(read=False): |
100 with cnx.security_enabled(read=False): |
105 session.execute('DELETE X %s Y WHERE X eid %%(x)s, ' |
101 cnx.execute('DELETE X %s Y WHERE X eid %%(x)s, ' |
106 'NOT Y eid %%(y)s' % rtype, |
102 'NOT Y eid %%(y)s' % rtype, |
107 {'x': eidfrom, 'y': eidto}) |
103 {'x': eidfrom, 'y': eidto}) |
108 if card[1] in '1?': |
104 if card[1] in '1?': |
109 with session.security_enabled(read=False): |
105 with cnx.security_enabled(read=False): |
110 session.execute('DELETE X %s Y WHERE Y eid %%(y)s, ' |
106 cnx.execute('DELETE X %s Y WHERE Y eid %%(y)s, ' |
111 'NOT X eid %%(x)s' % rtype, |
107 'NOT X eid %%(x)s' % rtype, |
112 {'x': eidfrom, 'y': eidto}) |
108 {'x': eidfrom, 'y': eidto}) |
113 |
109 |
114 |
110 |
115 def preprocess_inlined_relations(session, entity): |
111 def preprocess_inlined_relations(cnx, entity): |
116 """when an entity is added, check if it has some inlined relation which |
112 """when an entity is added, check if it has some inlined relation which |
117 requires to be extrated for proper call hooks |
113 requires to be extrated for proper call hooks |
118 """ |
114 """ |
119 relations = [] |
115 relations = [] |
120 activeintegrity = session.is_hook_category_activated('activeintegrity') |
116 activeintegrity = cnx.is_hook_category_activated('activeintegrity') |
121 eschema = entity.e_schema |
117 eschema = entity.e_schema |
122 for attr in entity.cw_edited: |
118 for attr in entity.cw_edited: |
123 rschema = eschema.subjrels[attr] |
119 rschema = eschema.subjrels[attr] |
124 if not rschema.final: # inlined relation |
120 if not rschema.final: # inlined relation |
125 value = entity.cw_edited[attr] |
121 value = entity.cw_edited[attr] |
126 relations.append((attr, value)) |
122 relations.append((attr, value)) |
127 session.update_rel_cache_add(entity.eid, attr, value) |
123 cnx.update_rel_cache_add(entity.eid, attr, value) |
128 rdef = session.rtype_eids_rdef(attr, entity.eid, value) |
124 rdef = cnx.rtype_eids_rdef(attr, entity.eid, value) |
129 if rdef.cardinality[1] in '1?' and activeintegrity: |
125 if rdef.cardinality[1] in '1?' and activeintegrity: |
130 with session.security_enabled(read=False): |
126 with cnx.security_enabled(read=False): |
131 session.execute('DELETE X %s Y WHERE Y eid %%(y)s' % attr, |
127 cnx.execute('DELETE X %s Y WHERE Y eid %%(y)s' % attr, |
132 {'x': entity.eid, 'y': value}) |
128 {'x': entity.eid, 'y': value}) |
133 return relations |
129 return relations |
134 |
130 |
135 |
131 |
136 class NullEventBus(object): |
132 class NullEventBus(object): |