# HG changeset patch # User Sylvain Thénault # Date 1267635109 -3600 # Node ID 8dce25da9d955df53db1e8ba3c947abd52040300 # Parent 64143d458495dfaec977db5cd9e1be35a33ed021# Parent e37932b89a6a9a2ace50cfcde3a9845bcfbcdd1b backport stable diff -r 64143d458495 -r 8dce25da9d95 devtools/__init__.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 doc/book/en/admin/ldap.rst --- 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 : 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). diff -r 64143d458495 -r 8dce25da9d95 doc/book/en/development/devweb/controllers.rst --- 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. + + + diff -r 64143d458495 -r 8dce25da9d95 entity.py --- 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): diff -r 64143d458495 -r 8dce25da9d95 schema.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 schemas/__init__.py --- 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)): diff -r 64143d458495 -r 8dce25da9d95 schemas/base.py --- 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',), diff -r 64143d458495 -r 8dce25da9d95 schemas/bootstrap.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 server/__init__.py --- 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() diff -r 64143d458495 -r 8dce25da9d95 server/querier.py --- 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 """ diff -r 64143d458495 -r 8dce25da9d95 server/repository.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 server/schemaserial.py --- 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: diff -r 64143d458495 -r 8dce25da9d95 server/serverconfig.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 server/session.py --- 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() diff -r 64143d458495 -r 8dce25da9d95 server/test/unittest_querier.py --- 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') diff -r 64143d458495 -r 8dce25da9d95 web/controller.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 web/data/cubicweb.widgets.js --- 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, diff -r 64143d458495 -r 8dce25da9d95 web/test/unittest_views_editforms.py --- 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') diff -r 64143d458495 -r 8dce25da9d95 web/views/autoform.py --- 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 diff -r 64143d458495 -r 8dce25da9d95 web/views/basecontrollers.py --- 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'
\n') + stream.write(extresources) + stream.write(u'
\n') + return stream.getvalue() @jsonize def js_i18n(self, msgids): diff -r 64143d458495 -r 8dce25da9d95 web/views/primary.py --- 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'') # side boxes if boxes or hasattr(self, 'render_side_related'): @@ -73,7 +74,6 @@ self.render_side_boxes(boxes) self.w(u'') self.w(u'') - self.content_navigation_components('navcontentbottom') def content_navigation_components(self, context): self.w(u'
' % context)