--- a/dataimport.py Mon Mar 28 19:31:26 2011 +0200
+++ b/dataimport.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -81,7 +81,7 @@
from logilab.common.deprecation import deprecated
from cubicweb.server.utils import eschema_eid
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def count_lines(stream_or_filename):
if isinstance(stream_or_filename, basestring):
--- a/entities/authobjs.py Mon Mar 28 19:31:26 2011 +0200
+++ b/entities/authobjs.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -87,8 +87,10 @@
'CWProperty X WHERE X pkey %(k)s, X for_user U, U eid %(u)s',
{'k': pkey, 'u': self.eid}).get_entity(0, 0)
except:
- self._cw.create_entity('CWProperty', pkey=unicode(pkey),
- value=value, for_user=self)
+ kwargs = dict(pkey=unicode(pkey), value=value)
+ if self.is_in_group('managers'):
+ kwargs['for_user'] = self
+ self._cw.create_entity('CWProperty', **kwargs)
else:
prop.set_attributes(value=value)
--- a/hooks/syncsession.py Mon Mar 28 19:31:26 2011 +0200
+++ b/hooks/syncsession.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
--- a/req.py Mon Mar 28 19:31:26 2011 +0200
+++ b/req.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -154,7 +154,7 @@
def find_one_entity(self, etype, **kwargs):
"""find one entity of the given type and attribute values.
- raise FindEntityError if can not return one and only one entity.
+ raise :exc:`FindEntityError` if can not return one and only one entity.
>>> users = find_one_entity('CWGroup', name=u'users')
>>> groups = find_one_entity('CWGroup')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/edition.py Mon Mar 28 19:31:45 2011 +0200
@@ -0,0 +1,128 @@
+from copy import copy
+
+_MARKER = object()
+
+class dict_protocol_catcher(object):
+ def __init__(self, entity):
+ self.__entity = entity
+ def __getitem__(self, attr):
+ return self.__entity.cw_edited[attr]
+ def __setitem__(self, attr, value):
+ self.__entity.cw_edited[attr] = value
+ def __getattr__(self, attr):
+ return getattr(self.__entity, attr)
+
+
+class EditedEntity(dict):
+ """encapsulate entities attributes being written by an RQL query"""
+ def __init__(self, entity, **kwargs):
+ dict.__init__(self, **kwargs)
+ self.entity = entity
+ self.skip_security = set()
+ self.querier_pending_relations = {}
+ self.saved = False
+
+ def __hash__(self):
+ # dict|set keyable
+ return hash(id(self))
+
+ def __cmp__(self, other):
+ # we don't want comparison by value inherited from dict
+ return cmp(id(self), id(other))
+
+ def __setitem__(self, attr, value):
+ assert attr != 'eid'
+ # don't add attribute into skip_security if already in edited
+ # attributes, else we may accidentaly skip a desired security check
+ if attr not in self:
+ self.skip_security.add(attr)
+ self.edited_attribute(attr, value)
+
+ def __delitem__(self, attr):
+ assert not self.saved, 'too late to modify edited attributes'
+ super(EditedEntity, self).__delitem__(attr)
+ self.entity.cw_attr_cache.pop(attr, None)
+
+ def pop(self, attr, *args):
+ # don't update skip_security by design (think to storage api)
+ assert not self.saved, 'too late to modify edited attributes'
+ value = super(EditedEntity, self).pop(attr, *args)
+ self.entity.cw_attr_cache.pop(attr, *args)
+ return value
+
+ def setdefault(self, attr, default):
+ assert attr != 'eid'
+ # don't add attribute into skip_security if already in edited
+ # attributes, else we may accidentaly skip a desired security check
+ if attr not in self:
+ self[attr] = default
+ return self[attr]
+
+ def update(self, values, skipsec=True):
+ if skipsec:
+ setitem = self.__setitem__
+ else:
+ setitem = self.edited_attribute
+ for attr, value in values.iteritems():
+ setitem(attr, value)
+
+ def edited_attribute(self, attr, value):
+ """attribute being edited by a rql query: should'nt be added to
+ skip_security
+ """
+ assert not self.saved, 'too late to modify edited attributes'
+ super(EditedEntity, self).__setitem__(attr, value)
+ self.entity.cw_attr_cache[attr] = value
+
+ def oldnewvalue(self, attr):
+ """returns the couple (old attr value, new attr value)
+
+ NOTE: will only work in a before_update_entity hook
+ """
+ assert not self.saved, 'too late to get the old value'
+ # get new value and remove from local dict to force a db query to
+ # fetch old value
+ newvalue = self.entity.cw_attr_cache.pop(attr, _MARKER)
+ oldvalue = getattr(self.entity, attr)
+ if newvalue is not _MARKER:
+ self.entity.cw_attr_cache[attr] = newvalue
+ else:
+ newvalue = oldvalue
+ return oldvalue, newvalue
+
+ def set_defaults(self):
+ """set default values according to the schema"""
+ for attr, value in self.entity.e_schema.defaults():
+ if not attr in self:
+ self[str(attr)] = value
+
+ def check(self, creation=False):
+ """check the entity edition against its schema. Only final relation
+ are checked here, constraint on actual relations are checked in hooks
+ """
+ entity = self.entity
+ if creation:
+ # on creations, we want to check all relations, especially
+ # required attributes
+ relations = [rschema for rschema in entity.e_schema.subject_relations()
+ if rschema.final and rschema.type != 'eid']
+ else:
+ relations = [entity._cw.vreg.schema.rschema(rtype)
+ for rtype in self]
+ from yams import ValidationError
+ try:
+ entity.e_schema.check(dict_protocol_catcher(entity),
+ creation=creation, _=entity._cw._,
+ relations=relations)
+ except ValidationError, ex:
+ ex.entity = self.entity
+ raise
+
+ def clone(self):
+ thecopy = EditedEntity(copy(self.entity))
+ thecopy.entity.cw_attr_cache = copy(self.entity.cw_attr_cache)
+ thecopy.entity._cw_related_cache = {}
+ thecopy.update(self, skipsec=False)
+ return thecopy
+
+
--- a/server/querier.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/querier.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -38,7 +38,8 @@
from cubicweb.server.utils import cleanup_solutions
from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata
-from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction, EditedEntity
+from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction
+from cubicweb.server.edition import EditedEntity
from cubicweb.server.session import security_enabled
def empty_rset(rql, args, rqlst=None):
--- a/server/serverctl.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/serverctl.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
--- a/server/session.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/session.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -37,6 +37,7 @@
from cubicweb.dbapi import ConnectionProperties
from cubicweb.utils import make_uid, RepeatList
from cubicweb.rqlrewrite import RQLRewriter
+from cubicweb.server.edition import EditedEntity
ETYPE_PYOBJ_MAP[Binary] = 'Bytes'
@@ -215,8 +216,9 @@
with security_enabled(self, False, False):
if self.vreg.schema[rtype].inlined:
entity = self.entity_from_eid(fromeid)
- entity[rtype] = toeid
- self.repo.glob_update_entity(self, entity, set((rtype,)))
+ edited = EditedEntity(entity)
+ edited.edited_attribute(rtype, toeid)
+ self.repo.glob_update_entity(self, edited)
else:
self.repo.glob_add_relation(self, fromeid, rtype, toeid)
@@ -234,7 +236,7 @@
with security_enabled(self, False, False):
if self.vreg.schema[rtype].inlined:
entity = self.entity_from_eid(fromeid)
- entity[rtype] = None
+ entity.cw_attr_cache[rtype] = None
self.repo.glob_update_entity(self, entity, set((rtype,)))
else:
self.repo.glob_delete_relation(self, fromeid, rtype, toeid)
--- a/server/sources/__init__.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/sources/__init__.py Mon Mar 28 19:31:45 2011 +0200
@@ -31,7 +31,7 @@
from cubicweb import ValidationError, set_log_methods, server
from cubicweb.schema import VIRTUAL_RTYPES
from cubicweb.server.sqlutils import SQL_PREFIX
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def dbg_st_search(uri, union, varmap, args, cachekey=None, prefix='rql for'):
--- a/server/sources/ldapuser.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/sources/ldapuser.py Mon Mar 28 19:31:45 2011 +0200
@@ -522,7 +522,8 @@
def _search(self, session, base, scope,
searchstr='(objectClass=*)', attrs=()):
"""make an ldap query"""
- self.debug('ldap search %s %s %s %s %s', self.uri, base, scope, searchstr, list(attrs))
+ self.debug('ldap search %s %s %s %s %s', self.uri, base, scope,
+ searchstr, list(attrs))
# XXX for now, we do not have connection pool support for LDAP, so
# this is always self._conn
cnx = session.pool.connection(self.uri).cnx
--- a/server/sources/native.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/sources/native.py Mon Mar 28 19:31:45 2011 +0200
@@ -58,7 +58,7 @@
from cubicweb.server.rqlannotation import set_qdata
from cubicweb.server.hook import CleanupDeletedEidsCacheOp
from cubicweb.server.session import hooks_control, security_enabled
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
from cubicweb.server.sources import AbstractSource, dbg_st_search, dbg_results
from cubicweb.server.sources.rql2sql import SQLGenerator
--- a/server/sources/storages.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/sources/storages.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,7 +24,7 @@
from cubicweb import Binary, ValidationError
from cubicweb.server import hook
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def set_attribute_storage(repo, etype, attr, storage):
--- a/server/ssplanner.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/ssplanner.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -21,8 +21,6 @@
__docformat__ = "restructuredtext en"
-from copy import copy
-
from rql.stmts import Union, Select
from rql.nodes import Constant, Relation
@@ -31,6 +29,7 @@
from cubicweb.rqlrewrite import add_types_restriction
from cubicweb.server.session import security_enabled
from cubicweb.server.hook import CleanupDeletedEidsCacheOp
+from cubicweb.server.edition import EditedEntity
READ_ONLY_RTYPES = set(('eid', 'has_text', 'is', 'is_instance_of', 'identity'))
@@ -128,132 +127,6 @@
return select
-_MARKER = object()
-
-class dict_protocol_catcher(object):
- def __init__(self, entity):
- self.__entity = entity
- def __getitem__(self, attr):
- return self.__entity.cw_edited[attr]
- def __setitem__(self, attr, value):
- self.__entity.cw_edited[attr] = value
- def __getattr__(self, attr):
- return getattr(self.__entity, attr)
-
-
-class EditedEntity(dict):
- """encapsulate entities attributes being written by an RQL query"""
- def __init__(self, entity, **kwargs):
- dict.__init__(self, **kwargs)
- self.entity = entity
- self.skip_security = set()
- self.querier_pending_relations = {}
- self.saved = False
-
- def __hash__(self):
- # dict|set keyable
- return hash(id(self))
-
- def __cmp__(self, other):
- # we don't want comparison by value inherited from dict
- return cmp(id(self), id(other))
-
- def __setitem__(self, attr, value):
- assert attr != 'eid'
- # don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
- if attr not in self:
- self.skip_security.add(attr)
- self.edited_attribute(attr, value)
-
- def __delitem__(self, attr):
- assert not self.saved, 'too late to modify edited attributes'
- super(EditedEntity, self).__delitem__(attr)
- self.entity.cw_attr_cache.pop(attr, None)
-
- def pop(self, attr, *args):
- # don't update skip_security by design (think to storage api)
- assert not self.saved, 'too late to modify edited attributes'
- value = super(EditedEntity, self).pop(attr, *args)
- self.entity.cw_attr_cache.pop(attr, *args)
- return value
-
- def setdefault(self, attr, default):
- assert attr != 'eid'
- # don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
- if attr not in self:
- self[attr] = default
- return self[attr]
-
- def update(self, values, skipsec=True):
- if skipsec:
- setitem = self.__setitem__
- else:
- setitem = self.edited_attribute
- for attr, value in values.iteritems():
- setitem(attr, value)
-
- def edited_attribute(self, attr, value):
- """attribute being edited by a rql query: should'nt be added to
- skip_security
- """
- assert not self.saved, 'too late to modify edited attributes'
- super(EditedEntity, self).__setitem__(attr, value)
- self.entity.cw_attr_cache[attr] = value
-
- def oldnewvalue(self, attr):
- """returns the couple (old attr value, new attr value)
-
- NOTE: will only work in a before_update_entity hook
- """
- assert not self.saved, 'too late to get the old value'
- # get new value and remove from local dict to force a db query to
- # fetch old value
- newvalue = self.entity.cw_attr_cache.pop(attr, _MARKER)
- oldvalue = getattr(self.entity, attr)
- if newvalue is not _MARKER:
- self.entity.cw_attr_cache[attr] = newvalue
- else:
- newvalue = oldvalue
- return oldvalue, newvalue
-
- def set_defaults(self):
- """set default values according to the schema"""
- for attr, value in self.entity.e_schema.defaults():
- if not attr in self:
- self[str(attr)] = value
-
- def check(self, creation=False):
- """check the entity edition against its schema. Only final relation
- are checked here, constraint on actual relations are checked in hooks
- """
- entity = self.entity
- if creation:
- # on creations, we want to check all relations, especially
- # required attributes
- relations = [rschema for rschema in entity.e_schema.subject_relations()
- if rschema.final and rschema.type != 'eid']
- else:
- relations = [entity._cw.vreg.schema.rschema(rtype)
- for rtype in self]
- from yams import ValidationError
- try:
- entity.e_schema.check(dict_protocol_catcher(entity),
- creation=creation, _=entity._cw._,
- relations=relations)
- except ValidationError, ex:
- ex.entity = self.entity
- raise
-
- def clone(self):
- thecopy = EditedEntity(copy(self.entity))
- thecopy.entity.cw_attr_cache = copy(self.entity.cw_attr_cache)
- thecopy.entity._cw_related_cache = {}
- thecopy.update(self, skipsec=False)
- return thecopy
-
-
class SSPlanner(object):
"""SingleSourcePlanner: build execution plan for rql queries
--- a/server/test/unittest_ldapuser.py Mon Mar 28 19:31:26 2011 +0200
+++ b/server/test/unittest_ldapuser.py Mon Mar 28 19:31:45 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
--- a/web/data/cubicweb.ajax.js Mon Mar 28 19:31:26 2011 +0200
+++ b/web/data/cubicweb.ajax.js Mon Mar 28 19:31:45 2011 +0200
@@ -283,7 +283,7 @@
* dictionary, `reqtype` the HTTP request type (get 'GET' or 'POST').
*/
function loadRemote(url, form, reqtype, sync) {
- if (!url.toLowerCase().startswith(baseuri())) {
+ if (!url.toLowerCase().startswith(baseuri().toLowerCase())) {
url = baseuri() + url;
}
if (!sync) {