--- a/devtools/__init__.py Fri Feb 26 17:39:33 2010 +0100
+++ b/devtools/__init__.py Wed Mar 03 17:51:49 2010 +0100
@@ -30,8 +30,8 @@
SYSTEM_RELATIONS = schema.META_RTYPES | set((
# workflow related
- 'workflow_of', 'state_of', 'transition_of', 'initial_state', 'allowed_transition',
- 'destination_state', 'from_state', 'to_state',
+ 'workflow_of', 'state_of', 'transition_of', 'initial_state', 'default_workflow',
+ 'allowed_transition', 'destination_state', 'from_state', 'to_state',
'condition', 'subworkflow', 'subworkflow_state', 'subworkflow_exit',
'custom_workflow', 'in_state', 'wf_info_for',
# cwproperty
--- a/doc/book/en/admin/ldap.rst Fri Feb 26 17:39:33 2010 +0100
+++ b/doc/book/en/admin/ldap.rst Wed Mar 03 17:51:49 2010 +0100
@@ -1,4 +1,64 @@
LDAP integration
================
-XXX feed me
\ No newline at end of file
+Overview
+--------
+
+Using LDAP as a source for user credentials and information is quite
+easy. The most difficult part lies in building an LDAP schema or
+using an existing one.
+
+At cube creation time, one is asked if more sources are wanted. LDAP
+is one possible option at this time. Of course, it is always possible
+to set it up later in the `source` configuration file, which we
+discuss there.
+
+It is possible to add as many LDAP sources as wanted, which translates
+in as many [ldapxxx] sections in the `source` configuration file.
+
+The general principle of the LDAP source is, given a proper
+configuration, to create local users matching the users available in
+the directory, deriving local user attributes from directory users
+attributes. Then a periodic task ensures local user information
+synchronization with the directory.
+
+Credential checks are _always_ done against the LDAP server.
+
+The base functionality for this is in
+cubicweb/server/sources/ldapuser.py.
+
+Configurations options
+----------------------
+
+Let us enumerate the options (but please keep in mind that the
+authoritative source for these is in the aforementioned python
+module), by categories (LDAP server connection, LDAP schema mapping
+information, LDAP source internal configuration).
+
+LDAP server connection options:
+
+* host: may contain port information using <host>:<port> notation.
+* protocol (choices are ldap, ldaps, ldapi)
+* auth-mode (choices are simple, cram_md5, digest_md5, gssapi, support
+ for the later being partial as of now)
+* auth-realm, realm to use when using gssapi/kerberos authentication
+* data-cnx-dn, user dn to use to open data connection to the ldap (eg
+ used to respond to rql queries)
+* data-cnx-password, password to use to open data connection to the
+ ldap (eg used to respond to rql queries)
+
+LDAP schema mapping:
+
+* user-base-dn, base DN to lookup for users
+* user-scope, user search scope
+* user-classes, classes of user
+* user-attrs-map, map from ldap user attributes to cubicweb attributes
+* user-login-attr, attribute used as login on authentication
+
+LDAP source internal configuration:
+
+* user-default-group, name of a group in which ldap users will be by
+ default. You can set multiple groups by separating them by a comma
+* synchronization-interval, interval between synchronization with the
+ ldap directory in seconds (default to once a day)
+* life time of query cache in minutes (default to two hours).
--- a/doc/book/en/development/devweb/controllers.rst Fri Feb 26 17:39:33 2010 +0100
+++ b/doc/book/en/development/devweb/controllers.rst Wed Mar 03 17:51:49 2010 +0100
@@ -1,4 +1,79 @@
Controllers
-----------
-XXX the view controller, other controllers
\ No newline at end of file
+Overview
+++++++++
+
+Controllers are responsible for taking action upon user requests
+(loosely following the terminology of the MVC meta pattern).
+
+The following controllers are provided out-of-the box in CubicWeb. We
+list them by category.
+
+Browsing:
+
+* the View controller (web/views/basecontrollers.py) is associated
+ with most browsing actions within a CubicWeb application: it always
+ instantiates a `main template` and lets the ResultSet/Views dispatch
+ system build up the whole content; it handles ObjectNotFound and
+ NoSelectableObject errors that may bubble up to its entry point, in
+ an end-user-friendly way (but other programming errors will slip
+ through)
+
+* the JSon controller (web/views/basecontrollers.py) provides services
+ for Ajax calls, typically using JSON as a serialization format for
+ input, and sometimes using either JSON or XML for output;
+
+* the Login/Logout controllers (web/views/basecontrollers.py) make
+ effective user login or logout requests
+
+Edition:
+
+* the Edit controller (web/views/editcontroller.py) handles CRUD
+ operations in response to a form being submitted; it works in close
+ association with the Forms, to which it delegates some of the work
+
+* the Form validator controller (web/views/basecontrollers.py)
+ provides form validation from Ajax context, using the Edit
+ controller, to implement the classic form handling loop (user edits,
+ hits 'submit/apply', validation occurs server-side by way of the
+ Form validator controller, and the UI is decorated with failure
+ information, either global or per-field , until it is valid)
+
+Other:
+
+* the SendMail controller (web/views/basecontrollers.py) is reponsible
+ for outgoing email notifications
+
+* the MailBugReport controller (web/views/basecontrollers.py) allows
+ to quickly have a `repotbug` feature in one's application
+
+Registration
+++++++++++++
+
+All controllers (should) live in the 'controllers' namespace within
+the global registry.
+
+API
++++
+
+Most API details should be resolved by source code inspection, as the
+various controllers have differing goals.
+
+`web/controller.py` contains the top-level abstract Controller class and
+its (NotImplemented) entry point `publish(rset=None)` method.
+
+A handful of helpers are also provided there:
+
+* process_rql builds a result set from an rql query typically issued
+ from the browser (and available through _cw.form['rql'])
+
+* validate_cache will force cache validation handling with respect to
+ the HTTP Cache directives (that were typically originally issued
+ from a previous server -> client response); concrete Controller
+ implementations dealing with HTTP (thus, for instance, not the
+ SendMail controller) may very well call this in their publication
+ process.
+
+
+
--- a/entity.py Fri Feb 26 17:39:33 2010 +0100
+++ b/entity.py Wed Mar 03 17:51:49 2010 +0100
@@ -797,7 +797,7 @@
del self.__unique
except AttributeError:
pass
-
+
# raw edition utilities ###################################################
def set_attributes(self, _cw_unsafe=False, **kwargs):
--- a/schema.py Fri Feb 26 17:39:33 2010 +0100
+++ b/schema.py Wed Mar 03 17:51:49 2010 +0100
@@ -50,8 +50,9 @@
))
WORKFLOW_TYPES = set(('Transition', 'State', 'TrInfo', 'Workflow',
- 'WorkflowTransition', 'BaseTransition',
- 'SubWorkflowExitPoint'))
+ 'WorkflowTransition', 'BaseTransition',
+ 'SubWorkflowExitPoint'))
+
INTERNAL_TYPES = set(('CWProperty', 'CWPermission', 'CWCache', 'ExternalUri'))
@@ -63,6 +64,31 @@
ybo.RDEF_PROPERTIES += ('eid',)
+PUB_SYSTEM_ENTITY_PERMS = {
+ 'read': ('managers', 'users', 'guests',),
+ 'add': ('managers',),
+ 'delete': ('managers',),
+ 'update': ('managers',),
+ }
+PUB_SYSTEM_REL_PERMS = {
+ 'read': ('managers', 'users', 'guests',),
+ 'add': ('managers',),
+ 'delete': ('managers',),
+ }
+PUB_SYSTEM_ATTR_PERMS = {
+ 'read': ('managers', 'users', 'guests',),
+ 'update': ('managers',),
+ }
+RO_REL_PERMS = {
+ 'read': ('managers', 'users', 'guests',),
+ 'add': (),
+ 'delete': (),
+ }
+RO_ATTR_PERMS = {
+ 'read': ('managers', 'users', 'guests',),
+ 'update': (),
+ }
+
# XXX same algorithm as in reorder_cubes and probably other place,
# may probably extract a generic function
def order_eschemas(eschemas):
@@ -369,7 +395,8 @@
if need_has_text is None:
need_has_text = may_need_has_text
if need_has_text and not has_has_text and not deletion:
- rdef = ybo.RelationDefinition(self.type, 'has_text', 'String')
+ rdef = ybo.RelationDefinition(self.type, 'has_text', 'String',
+ __permissions__=RO_ATTR_PERMS)
self.schema.add_relation_def(rdef)
elif not need_has_text and has_has_text:
self.schema.del_relation_def(self.type, 'has_text', 'String')
@@ -491,9 +518,11 @@
if not eschema.final:
# automatically add the eid relation to non final entity types
rdef = ybo.RelationDefinition(eschema.type, 'eid', 'Int',
- cardinality='11', uid=True)
+ cardinality='11', uid=True,
+ __permissions__=RO_ATTR_PERMS)
self.add_relation_def(rdef)
- rdef = ybo.RelationDefinition(eschema.type, 'identity', eschema.type)
+ rdef = ybo.RelationDefinition(eschema.type, 'identity', eschema.type,
+ __permissions__=RO_REL_PERMS)
self.add_relation_def(rdef)
self._eid_index[eschema.eid] = eschema
return eschema
@@ -1054,8 +1083,16 @@
cw = entity._cw
elif form is not None:
cw = form._cw
- if cw is not None and cw.user.has_permission(PERM_USE_TEMPLATE_FORMAT):
- return self.regular_formats + tuple(NEED_PERM_FORMATS)
+ if cw is not None:
+ if hasattr(cw, 'is_super_session'):
+ # cw is a server session
+ hasperm = cw.is_super_session or \
+ not cw.vreg.config.is_hook_category_activated('integrity') or \
+ cw.user.has_permission(PERM_USE_TEMPLATE_FORMAT)
+ else:
+ hasperm = cw.user.has_permission(PERM_USE_TEMPLATE_FORMAT)
+ if hasperm:
+ return self.regular_formats + tuple(NEED_PERM_FORMATS)
return self.regular_formats
# XXX monkey patch PyFileReader.import_erschema until bw_normalize_etype is
--- a/schemas/__init__.py Fri Feb 26 17:39:33 2010 +0100
+++ b/schemas/__init__.py Wed Mar 03 17:51:49 2010 +0100
@@ -1,38 +1,25 @@
"""some utilities to define schema permissions
:organization: Logilab
-:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2008-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
from rql.utils import quote
-from cubicweb.schema import ERQLExpression, RRQLExpression
+from cubicweb.schema import RO_REL_PERMS, RO_ATTR_PERMS, \
+ PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, \
+ ERQLExpression, RRQLExpression
# permissions for "meta" entity type (readable by anyone, can only be
# added/deleted by managers)
-META_ETYPE_PERMS = {
- 'read': ('managers', 'users', 'guests',),
- 'add': ('managers',),
- 'delete': ('managers',),
- 'update': ('managers', 'owners',),
- }
-
+META_ETYPE_PERMS = PUB_SYSTEM_ENTITY_PERMS # XXX deprecates
# permissions for "meta" relation type (readable by anyone, can only be
# added/deleted by managers)
-META_RTYPE_PERMS = {
- 'read': ('managers', 'users', 'guests',),
- 'add': ('managers',),
- 'delete': ('managers',),
- }
-
+META_RTYPE_PERMS = PUB_SYSTEM_REL_PERMS # XXX deprecates
# permissions for relation type that should only set by hooks using unsafe
# execute, readable by anyone
-HOOKS_RTYPE_PERMS = {
- 'read': ('managers', 'users', 'guests',),
- 'add': (),
- 'delete': (),
- }
+HOOKS_RTYPE_PERMS = RO_REL_PERMS # XXX deprecates
def _perm(names):
if isinstance(names, (list, tuple)):
--- a/schemas/base.py Fri Feb 26 17:39:33 2010 +0100
+++ b/schemas/base.py Wed Mar 03 17:51:49 2010 +0100
@@ -10,9 +10,9 @@
from yams.buildobjs import (EntityType, RelationType, SubjectRelation,
String, Datetime, Password)
-from cubicweb.schema import (RQLConstraint, WorkflowableEntityType,
- ERQLExpression, RRQLExpression)
-from cubicweb.schemas import META_ETYPE_PERMS, META_RTYPE_PERMS
+from cubicweb.schema import (
+ RQLConstraint, WorkflowableEntityType, ERQLExpression, RRQLExpression,
+ PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, PUB_SYSTEM_ATTR_PERMS)
class CWUser(WorkflowableEntityType):
"""define a CubicWeb user"""
@@ -85,7 +85,7 @@
class in_group(RelationType):
"""core relation indicating a user's groups"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
class owned_by(RelationType):
"""core relation indicating owners of an entity. This relation
@@ -118,18 +118,21 @@
class creation_date(RelationType):
"""creation time of an entity"""
+ __permissions__ = PUB_SYSTEM_ATTR_PERMS
cardinality = '11'
subject = '*'
object = 'Datetime'
class modification_date(RelationType):
"""latest modification time of an entity"""
+ __permissions__ = PUB_SYSTEM_ATTR_PERMS
cardinality = '11'
subject = '*'
object = 'Datetime'
class cwuri(RelationType):
"""internal entity uri"""
+ __permissions__ = PUB_SYSTEM_ATTR_PERMS
cardinality = '11'
subject = '*'
object = 'String'
@@ -155,7 +158,7 @@
class CWPermission(EntityType):
"""entity type that may be used to construct some advanced security configuration
"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
name = String(required=True, indexed=True, internationalizable=True, maxsize=100,
description=_('name or identifier of the permission'))
@@ -170,11 +173,11 @@
"""link a permission to the entity. This permission should be used in the
security definition of the entity's type to be useful.
"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
class require_group(RelationType):
"""used to grant a permission to a group"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
class ExternalUri(EntityType):
@@ -209,6 +212,8 @@
Also, checkout the AppObject.get_cache() method.
"""
+ # XXX only handle by hooks, shouldn't be readable/editable at all through
+ # the ui and so no permissions should be granted, no?
__permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
--- a/schemas/bootstrap.py Fri Feb 26 17:39:33 2010 +0100
+++ b/schemas/bootstrap.py Wed Mar 03 17:51:49 2010 +0100
@@ -10,14 +10,16 @@
from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
SubjectRelation, RichString, String, Boolean, Int)
-from cubicweb.schema import RQLConstraint
-from cubicweb.schemas import META_ETYPE_PERMS, META_RTYPE_PERMS
+from cubicweb.schema import (
+ RQLConstraint,
+ PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, PUB_SYSTEM_ATTR_PERMS
+ )
# not restricted since as "is" is handled as other relations, guests need
# access to this
class CWEType(EntityType):
"""define an entity type, used to build the instance schema"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
description = RichString(internationalizable=True,
@@ -28,7 +30,7 @@
class CWRType(EntityType):
"""define a relation type, used to build the instance schema"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
description = RichString(internationalizable=True,
@@ -48,7 +50,7 @@
used to build the instance schema
"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
relation_type = SubjectRelation('CWRType', cardinality='1*',
constraints=[RQLConstraint('O final TRUE')],
composite='object')
@@ -85,7 +87,7 @@
used to build the instance schema
"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
relation_type = SubjectRelation('CWRType', cardinality='1*',
constraints=[RQLConstraint('O final FALSE')],
composite='object')
@@ -116,7 +118,7 @@
# not restricted since it has to be read when checking allowed transitions
class RQLExpression(EntityType):
"""define a rql expression used to define permissions"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
exprtype = String(required=True, vocabulary=['ERQLExpression', 'RRQLExpression'])
mainvars = String(maxsize=8,
description=_('name of the main variables which should be '
@@ -134,14 +136,14 @@
class CWConstraint(EntityType):
"""define a schema constraint"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
cstrtype = SubjectRelation('CWConstraintType', cardinality='1*')
value = String(description=_('depends on the constraint type'))
class CWConstraintType(EntityType):
"""define a schema constraint type"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
@@ -149,7 +151,7 @@
# not restricted since it has to be read when checking allowed transitions
class CWGroup(EntityType):
"""define a CubicWeb users group"""
- __permissions__ = META_ETYPE_PERMS
+ __permissions__ = PUB_SYSTEM_ENTITY_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
@@ -173,32 +175,32 @@
class relation_type(RelationType):
"""link a relation definition to its relation type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
inlined = True
class from_entity(RelationType):
"""link a relation definition to its subject entity type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
inlined = True
class to_entity(RelationType):
"""link a relation definition to its object entity type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
inlined = True
class constrained_by(RelationType):
"""constraints applying on this relation"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
class cstrtype(RelationType):
"""constraint factory"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
inlined = True
class read_permission_cwgroup(RelationDefinition):
"""groups allowed to read entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'read_permission'
subject = ('CWEType', 'CWAttribute', 'CWRelation')
object = 'CWGroup'
@@ -206,7 +208,7 @@
class add_permission_cwgroup(RelationDefinition):
"""groups allowed to add entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'add_permission'
subject = ('CWEType', 'CWRelation')
object = 'CWGroup'
@@ -214,7 +216,7 @@
class delete_permission_cwgroup(RelationDefinition):
"""groups allowed to delete entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'delete_permission'
subject = ('CWEType', 'CWRelation')
object = 'CWGroup'
@@ -222,7 +224,7 @@
class update_permission_cwgroup(RelationDefinition):
"""groups allowed to update entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'update_permission'
subject = ('CWEType', 'CWAttribute')
object = 'CWGroup'
@@ -230,7 +232,7 @@
class read_permission_rqlexpr(RelationDefinition):
"""rql expression allowing to read entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'read_permission'
subject = ('CWEType', 'CWAttribute', 'CWRelation')
object = 'RQLExpression'
@@ -239,7 +241,7 @@
class add_permission_rqlexpr(RelationDefinition):
"""rql expression allowing to add entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'add_permission'
subject = ('CWEType', 'CWRelation')
object = 'RQLExpression'
@@ -248,7 +250,7 @@
class delete_permission_rqlexpr(RelationDefinition):
"""rql expression allowing to delete entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'delete_permission'
subject = ('CWEType', 'CWRelation')
object = 'RQLExpression'
@@ -257,7 +259,7 @@
class update_permission_rqlexpr(RelationDefinition):
"""rql expression allowing to update entities/relations of this type"""
- __permissions__ = META_RTYPE_PERMS
+ __permissions__ = PUB_SYSTEM_REL_PERMS
name = 'update_permission'
subject = ('CWEType', 'CWAttribute')
object = 'RQLExpression'
@@ -305,3 +307,13 @@
cardinality = '?*'
subject = 'CWEType'
object = 'CWEType'
+
+def post_build_callback(schema):
+ """set attributes permissions for schema/workflow entities"""
+ from cubicweb.schema import SCHEMA_TYPES, WORKFLOW_TYPES, META_RTYPES
+ for eschema in schema.entities():
+ if eschema in SCHEMA_TYPES or eschema in WORKFLOW_TYPES:
+ for rschema in eschema.subject_relations():
+ if rschema.final and not rschema in META_RTYPES:
+ rdef = eschema.rdef(rschema)
+ rdef.permissions = PUB_SYSTEM_ATTR_PERMS
--- a/server/__init__.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/__init__.py Wed Mar 03 17:51:49 2010 +0100
@@ -186,6 +186,7 @@
handler.install_custom_sql_scripts(join(CW_SOFTWARE_ROOT, 'schemas'), driver)
for directory in reversed(config.cubes_path()):
handler.install_custom_sql_scripts(join(directory, 'schema'), driver)
+ # serialize the schema
initialize_schema(config, schema, handler)
# yoo !
cnx.commit()
--- a/server/querier.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/querier.py Wed Mar 03 17:51:49 2010 +0100
@@ -358,6 +358,7 @@
self.preprocess(rqlst, security=False)
return rqlst
+
class InsertPlan(ExecutionPlan):
"""an execution model specific to the INSERT rql query
"""
--- a/server/repository.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/repository.py Wed Mar 03 17:51:49 2010 +0100
@@ -105,7 +105,8 @@
# skip that for super session (though we can still skip it for internal
# sessions). Also we should imo rely on the orm to first fetch existing
# entity if any then delete it.
- if session.is_internal_session:
+ if session.is_internal_session \
+ or not session.vreg.config.is_hook_category_activated('integrity'):
return
card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
# one may be tented to check for neweids but this may cause more than one
--- a/server/schemaserial.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/schemaserial.py Wed Mar 03 17:51:49 2010 +0100
@@ -51,10 +51,6 @@
return res
# schema / perms deserialization ##############################################
-OLD_SCHEMA_TYPES = frozenset(('EFRDef', 'ENFRDef', 'ERType', 'EEType',
- 'EConstraintType', 'EConstraint', 'EGroup',
- 'EUser', 'ECache', 'EPermission', 'EProperty'))
-
def deserialize_schema(schema, session):
"""return a schema according to information stored in an rql database
as CWRType and CWEType entities
@@ -90,12 +86,6 @@
{'x': eid, 'n': netype})
session.system_sql('UPDATE entities SET type=%(n)s WHERE type=%(x)s',
{'x': etype, 'n': netype})
- # XXX should be donne as well on sqlite based sources
- if not etype in OLD_SCHEMA_TYPES and \
- (getattr(dbhelper, 'case_sensitive', False)
- or etype.lower() != netype.lower()):
- session.system_sql('ALTER TABLE %s%s RENAME TO %s%s' % (
- sqlutils.SQL_PREFIX, etype, sqlutils.SQL_PREFIX, netype))
session.commit(False)
try:
session.system_sql('UPDATE deleted_entities SET type=%(n)s WHERE type=%(x)s',
@@ -182,6 +172,17 @@
res.setdefault(eid, {}).setdefault(action, []).append( (expr, mainvars, expreid) )
return res
+def deserialize_rdef_constraints(session):
+ """return the list of relation definition's constraints as instances"""
+ res = {}
+ for rdefeid, ceid, ct, val in session.execute(
+ 'Any E, X,TN,V WHERE E constrained_by X, X is CWConstraint, '
+ 'X cstrtype T, T name TN, X value V', build_descr=False):
+ cstr = CONSTRAINTS[ct].deserialize(val)
+ cstr.eid = ceid
+ res.setdefault(rdefeid, []).append(cstr)
+ return res
+
def set_perms(erschema, permsdict):
"""set permissions on the given erschema according to the permission
definition dictionary as built by deserialize_ertype_permissions for a
@@ -202,21 +203,9 @@
for p in somethings)
-def deserialize_rdef_constraints(session):
- """return the list of relation definition's constraints as instances"""
- res = {}
- for rdefeid, ceid, ct, val in session.execute(
- 'Any E, X,TN,V WHERE E constrained_by X, X is CWConstraint, '
- 'X cstrtype T, T name TN, X value V', build_descr=False):
- cstr = CONSTRAINTS[ct].deserialize(val)
- cstr.eid = ceid
- res.setdefault(rdefeid, []).append(cstr)
- return res
-
-
# schema / perms serialization ################################################
-def serialize_schema(cursor, schema, verbose=False):
+def serialize_schema(cursor, schema):
"""synchronize schema and permissions in the database according to
current schema
"""
@@ -224,38 +213,40 @@
if not quiet:
_title = '-> storing the schema in the database '
print _title,
- execute = cursor.execute
+ execute = cursor.unsafe_execute
eschemas = schema.entities()
aller = eschemas + schema.relations()
- if not verbose and not quiet:
+ if not quiet:
pb_size = len(aller) + len(CONSTRAINTS) + len([x for x in eschemas if x.specializes()])
pb = ProgressBar(pb_size, title=_title)
else:
pb = None
+ # serialize all entity types, assuring CWEType is serialized first
+ eschemas.remove(schema.eschema('CWEType'))
+ eschemas.insert(0, schema.eschema('CWEType'))
+ for eschema in eschemas:
+ execschemarql(execute, eschema, eschema2rql(eschema, groupmap))
+ if pb is not None:
+ pb.update()
+ # serialize constraint types
rql = 'INSERT CWConstraintType X: X name %(ct)s'
for cstrtype in CONSTRAINTS:
- if verbose:
- print rql
execute(rql, {'ct': unicode(cstrtype)}, build_descr=False)
if pb is not None:
pb.update()
- groupmap = group_mapping(cursor, interactive=False)
- for ertype in aller:
- # skip eid and has_text relations
- if ertype in VIRTUAL_RTYPES:
+ # serialize relations
+ for rschema in schema.relations():
+ # skip virtual relations such as eid, has_text and identity
+ if rschema in VIRTUAL_RTYPES:
if pb is not None:
pb.update()
continue
for rql, kwargs in erschema2rql(schema[ertype], groupmap):
- if verbose:
- print rql % kwargs
execute(rql, kwargs, build_descr=False)
if pb is not None:
pb.update()
for rql, kwargs in specialize2rql(schema):
- if verbose:
- print rql % kwargs
- execute(rql, kwargs, build_descr=False)
+ assert execute(rql, kwargs, build_descr=False)
if pb is not None:
pb.update()
if not quiet:
--- a/server/serverconfig.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/serverconfig.py Wed Mar 03 17:51:49 2010 +0100
@@ -185,6 +185,8 @@
# check user's state at login time
consider_user_state = True
+ # XXX hooks control stuff should probably be on the session, not on the config
+
# hooks activation configuration
# all hooks should be activated during normal execution
disabled_hooks_categories = set()
@@ -232,9 +234,13 @@
@classmethod
def is_hook_activated(cls, hook):
+ return cls.is_hook_category_activated(hook.category)
+
+ @classmethod
+ def is_hook_category_activated(cls, category):
if cls.hooks_mode is cls.DENY_ALL:
- return hook.category in cls.enabled_hooks_categories
- return hook.category not in cls.disabled_hooks_categories
+ return category in cls.enabled_hooks_categories
+ return category not in cls.disabled_hooks_categories
# should some hooks be deactivated during [pre|post]create script execution
free_wheel = False
--- a/server/session.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/session.py Wed Mar 03 17:51:49 2010 +0100
@@ -499,7 +499,7 @@
operation.handle_event('revert%s_event' % trstate)
# XXX use slice notation since self.pending_operations is a
# read-only property.
- self.pending_operations[:] = processed + self.pending_operations
+ self.pending_operations[:] = processed + self.pending_operations
self.rollback(reset_pool)
raise
self.pool.commit()
--- a/server/test/unittest_querier.py Fri Feb 26 17:39:33 2010 +0100
+++ b/server/test/unittest_querier.py Wed Mar 03 17:51:49 2010 +0100
@@ -257,7 +257,7 @@
result, descr = rset.rows, rset.description
self.assertEquals(descr[0][0], 'String')
self.assertEquals(descr[0][1], 'Int')
- self.assertEquals(result[0][0], 'RQLExpression') # XXX may change as schema evolve
+ self.assertEquals(result[0][0], 'CWRelation') # XXX may change as schema evolve
def test_select_groupby_orderby(self):
rset = self.execute('Any N GROUPBY N ORDERBY N WHERE X is CWGroup, X name N')
--- a/web/controller.py Fri Feb 26 17:39:33 2010 +0100
+++ b/web/controller.py Wed Mar 03 17:51:49 2010 +0100
@@ -61,12 +61,10 @@
self._edited_entity = None
def publish(self, rset=None):
- """publish the current request, with an option input rql string
- (already processed if necessary)
- """
+ """publish the current request, with an optional input rset"""
raise NotImplementedError
- # generic methods useful for concret implementations ######################
+ # generic methods useful for concrete implementations ######################
def process_rql(self, rql):
"""execute rql if specified"""
@@ -102,6 +100,7 @@
if not self._edited_entity:
self._edited_entity = entity
+ # XXX move to EditController (only customer)
def delete_entities(self, eidtypes):
"""delete entities from the repository"""
redirect_info = set()
@@ -125,6 +124,7 @@
view.set_http_cache_headers()
self._cw.validate_cache()
+ # XXX is that used AT ALL ?
def reset(self):
"""reset form parameters and redirect to a view determinated by given
parameters
@@ -141,6 +141,7 @@
self._return_to_original_view(newparams)
+ # XXX is that used AT ALL ?
def _return_to_original_view(self, newparams):
"""validate-button case"""
# transforms __redirect[*] parameters into regular form parameters
@@ -173,7 +174,7 @@
url = append_url_params(url, self._cw.form.get('__redirectparams'))
raise Redirect(url)
-
+ # XXX is that used AT ALL ?
def _return_to_edition_view(self, newparams):
"""apply-button case"""
form = self._cw.form
@@ -197,6 +198,7 @@
raise Redirect(self._cw.build_url(path, **newparams))
+ # XXX is that used AT ALL ?
def _return_to_lastpage(self, newparams):
"""cancel-button case: in this case we are always expecting to go back
where we came from, and this is not easy. Currently we suppose that
--- a/web/data/cubicweb.widgets.js Fri Feb 26 17:39:33 2010 +0100
+++ b/web/data/cubicweb.widgets.js Wed Mar 03 17:51:49 2010 +0100
@@ -170,8 +170,8 @@
function toggleTree(event) {
var linode = jQuery(this);
var url = linode.attr('cubicweb:loadurl');
- linode.find('ul.placeholder').remove();
if (url) {
+ linode.find('ul.placeholder').remove();
linode.loadxhtml(url, {callback: function(domnode) {
linode.removeAttr('cubicweb:loadurl');
jQuery(domnode).treeview({toggle: toggleTree,
--- a/web/test/unittest_views_editforms.py Fri Feb 26 17:39:33 2010 +0100
+++ b/web/test/unittest_views_editforms.py Wed Mar 03 17:51:49 2010 +0100
@@ -43,13 +43,11 @@
('firstname', 'subject'),
('surname', 'subject'),
('in_group', 'subject'),
- ('eid', 'subject'),
])
self.assertListEquals(rbc(e, 'muledit', 'attributes'),
[('login', 'subject'),
('upassword', 'subject'),
('in_group', 'subject'),
- ('eid', 'subject'),
])
self.assertListEquals(rbc(e, 'main', 'metadata'),
[('last_login_time', 'subject'),
@@ -76,13 +74,10 @@
# owned_by is defined both as subject and object relations on CWUser
self.assertListEquals(sorted(x for x in rbc(e, 'main', 'hidden')
if x != ('tags', 'object')),
- sorted([('has_text', 'subject'),
- ('identity', 'subject'),
- ('for_user', 'object'),
+ sorted([('for_user', 'object'),
('created_by', 'object'),
('wf_info_for', 'object'),
('owned_by', 'object'),
- ('identity', 'object'),
]))
def test_inlined_view(self):
@@ -106,11 +101,9 @@
('test', 'subject'),
('description', 'subject'),
('salary', 'subject'),
- ('eid', 'subject')
])
self.assertListEquals(rbc(e, 'muledit', 'attributes'),
[('nom', 'subject'),
- ('eid', 'subject')
])
self.assertListEquals(rbc(e, 'main', 'metadata'),
[('creation_date', 'subject'),
@@ -124,10 +117,7 @@
('connait', 'object')
])
self.assertListEquals(rbc(e, 'main', 'hidden'),
- [('has_text', 'subject'),
- ('identity', 'subject'),
- ('identity', 'object'),
- ])
+ [])
def test_edition_form(self):
rset = self.execute('CWUser X LIMIT 1')
--- a/web/views/autoform.py Fri Feb 26 17:39:33 2010 +0100
+++ b/web/views/autoform.py Wed Mar 03 17:51:49 2010 +0100
@@ -661,7 +661,7 @@
return []
# XXX we should simply put eid in the generated section, no?
return [(rtype, role) for rtype, _, role in self._relations_by_section(
- 'attributes', 'update', strict) if rtype != 'eid']
+ 'attributes', 'update', strict)]
def editable_relations(self):
"""return a sorted list of (relation's label, relation'schema, role) for
--- a/web/views/basecontrollers.py Fri Feb 26 17:39:33 2010 +0100
+++ b/web/views/basecontrollers.py Wed Mar 03 17:51:49 2010 +0100
@@ -375,12 +375,12 @@
rset = self._exec(rql)
else:
rset = None
- comp = self._cw.vreg[registry].select(compid, self._cw, rset=rset)
if extraargs is None:
extraargs = {}
else: # we receive unicode keys which is not supported by the **syntax
extraargs = dict((str(key), value)
for key, value in extraargs.items())
+ comp = self._cw.vreg[registry].select(compid, self._cw, rset=rset, **extraargs)
extraargs = extraargs or {}
return comp.render(**extraargs)
@@ -402,13 +402,23 @@
@xhtmlize
def js_reledit_form(self):
+ req = self._cw
args = dict((x, self._cw.form[x])
for x in frozenset(('rtype', 'role', 'reload', 'landing_zone')))
entity = self._cw.entity_from_eid(int(self._cw.form['eid']))
# note: default is reserved in js land
args['default'] = self._cw.form['default_value']
args['reload'] = simplejson.loads(args['reload'])
- return entity.view('doreledit', **args)
+ rset = req.eid_rset(int(self._cw.form['eid']))
+ view = req.vreg['views'].select('doreledit', req, rset=rset, rtype=args['rtype'])
+ stream = view.set_stream()
+ view.render(**args)
+ extresources = req.html_headers.getvalue(skiphead=True)
+ if extresources:
+ stream.write(u'<div class="ajaxHtmlHead">\n')
+ stream.write(extresources)
+ stream.write(u'</div>\n')
+ return stream.getvalue()
@jsonize
def js_i18n(self, msgids):
--- a/web/views/primary.py Fri Feb 26 17:39:33 2010 +0100
+++ b/web/views/primary.py Wed Mar 03 17:51:49 2010 +0100
@@ -62,6 +62,7 @@
self.render_entity_attributes(entity)
if self.main_related_section:
self.render_entity_relations(entity)
+ self.content_navigation_components('navcontentbottom')
self.w(u'</div>')
# side boxes
if boxes or hasattr(self, 'render_side_related'):
@@ -73,7 +74,6 @@
self.render_side_boxes(boxes)
self.w(u'</div>')
self.w(u'</td></tr></table>')
- self.content_navigation_components('navcontentbottom')
def content_navigation_components(self, context):
self.w(u'<div class="%s">' % context)