--- a/appobject.py Thu Feb 11 12:19:08 2010 +0100
+++ b/appobject.py Mon Feb 15 18:44:47 2010 +0100
@@ -404,7 +404,7 @@
def format_date(self, date, date_format=None, time=False):
return self._cw.format_date(date, date_format, time)
- @deprecated('[3.6] use self._cw.format_timoe')
+ @deprecated('[3.6] use self._cw.format_time')
def format_time(self, time):
return self._cw.format_time(time)
--- a/hooks/metadata.py Thu Feb 11 12:19:08 2010 +0100
+++ b/hooks/metadata.py Mon Feb 15 18:44:47 2010 +0100
@@ -55,7 +55,13 @@
events = ('before_update_entity',)
def __call__(self):
- self.entity.setdefault('modification_date', datetime.now())
+ # repairing is true during c-c upgrade/shell and similar commands. We
+ # usually don't want to update modification date in such cases.
+ #
+ # XXX to be really clean, we should turn off modification_date update
+ # explicitly on each command where we do not want that behaviour.
+ if not self._cw.vreg.config.repairing:
+ self.entity.setdefault('modification_date', datetime.now())
class _SetCreatorOp(hook.Operation):
--- a/hooks/notification.py Thu Feb 11 12:19:08 2010 +0100
+++ b/hooks/notification.py Mon Feb 15 18:44:47 2010 +0100
@@ -126,7 +126,7 @@
rqlsel.append(var)
rqlrestr.append('X %s %s' % (attr, var))
rql = 'Any %s WHERE %s' % (','.join(rqlsel), ','.join(rqlrestr))
- rset = session.execute(rql, {'x': self.entity.eid}, 'x')
+ rset = session.unsafe_execute(rql, {'x': self.entity.eid}, 'x')
for i, attr in enumerate(attrs):
oldvalue = rset[0][i]
newvalue = self.entity[attr]
--- a/hooks/security.py Thu Feb 11 12:19:08 2010 +0100
+++ b/hooks/security.py Mon Feb 15 18:44:47 2010 +0100
@@ -12,30 +12,31 @@
from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
-def check_entity_attributes(session, entity):
+def check_entity_attributes(session, entity, editedattrs=None):
eid = entity.eid
eschema = entity.e_schema
# ._default_set is only there on entity creation to indicate unspecified
# attributes which has been set to a default value defined in the schema
defaults = getattr(entity, '_default_set', ())
- try:
- editedattrs = entity.edited_attributes
- except AttributeError:
- editedattrs = entity
+ if editedattrs is None:
+ try:
+ editedattrs = entity.edited_attributes
+ except AttributeError:
+ editedattrs = entity
for attr in editedattrs:
if attr in defaults:
continue
rdef = eschema.rdef(attr)
if rdef.final: # non final relation are checked by other hooks
# add/delete should be equivalent (XXX: unify them into 'update' ?)
- rdef.check_perm(session, 'add', eid=eid)
+ rdef.check_perm(session, 'update', eid=eid)
class _CheckEntityPermissionOp(hook.LateOperation):
def precommit_event(self):
#print 'CheckEntityPermissionOp', self.session.user, self.entity, self.action
self.entity.check_perm(self.action)
- check_entity_attributes(self.session, self.entity)
+ check_entity_attributes(self.session, self.entity, self.editedattrs)
def commit_event(self):
pass
@@ -63,7 +64,9 @@
events = ('after_add_entity',)
def __call__(self):
- _CheckEntityPermissionOp(self._cw, entity=self.entity, action='add')
+ _CheckEntityPermissionOp(self._cw, entity=self.entity,
+ editedattrs=tuple(self.entity.edited_attributes),
+ action='add')
class AfterUpdateEntitySecurityHook(SecurityHook):
@@ -77,7 +80,12 @@
check_entity_attributes(self._cw, self.entity)
except Unauthorized:
self.entity.clear_local_perm_cache('update')
- _CheckEntityPermissionOp(self._cw, entity=self.entity, action='update')
+ # save back editedattrs in case the entity is reedited later in the
+ # same transaction, which will lead to edited_attributes being
+ # overwritten
+ _CheckEntityPermissionOp(self._cw, entity=self.entity,
+ editedattrs=tuple(self.entity.edited_attributes),
+ action='update')
class BeforeDelEntitySecurityHook(SecurityHook):
--- a/hooks/syncschema.py Thu Feb 11 12:19:08 2010 +0100
+++ b/hooks/syncschema.py Mon Feb 15 18:44:47 2010 +0100
@@ -716,6 +716,9 @@
return
if isinstance(erschema, RelationSchema): # XXX 3.6 migration
return
+ if isinstance(erschema, RelationDefinitionSchema) and \
+ self.action in ('delete', 'add'): # XXX 3.6.1 migration
+ return
perms = list(erschema.action_permissions(self.action))
if hasattr(self, 'group_eid'):
perm = self.session.entity_from_eid(self.group_eid).name
--- a/hooks/syncsession.py Thu Feb 11 12:19:08 2010 +0100
+++ b/hooks/syncsession.py Mon Feb 15 18:44:47 2010 +0100
@@ -153,7 +153,7 @@
raise ValidationError(self.entity.eid,
{'value': session._(str(ex))})
if not session.user.matching_groups('managers'):
- session.add_relation(entity.eid, 'for_user', session.user.eid)
+ session.add_relation(self.entity.eid, 'for_user', session.user.eid)
else:
_AddCWPropertyOp(session, cwprop=self.entity)
@@ -178,7 +178,7 @@
if entity.for_user:
for session_ in get_user_sessions(session.repo, entity.for_user[0].eid):
_ChangeCWPropertyOp(session, cwpropdict=session_.user.properties,
- key=key, value=value)
+ key=key, value=value)
else:
# site wide properties
_ChangeCWPropertyOp(session, cwpropdict=session.vreg['propertyvalues'],
--- a/mail.py Thu Feb 11 12:19:08 2010 +0100
+++ b/mail.py Mon Feb 15 18:44:47 2010 +0100
@@ -200,7 +200,8 @@
continue
except Exception, ex:
# shouldn't make the whole transaction fail because of rendering
- # error (unauthorized or such)
+ # error (unauthorized or such) XXX check it doesn't actually
+ # occurs due to rollback on such error
self.exception(str(ex))
continue
msg = format_mail(self.user_data, [emailaddr], content, subject,
--- a/migration.py Thu Feb 11 12:19:08 2010 +0100
+++ b/migration.py Mon Feb 15 18:44:47 2010 +0100
@@ -70,8 +70,11 @@
ability to show the script's content
"""
while True:
- answer = ASK.ask('Execute %r ?' % scriptpath, ('Y','n','show'), 'Y')
- if answer == 'n':
+ answer = ASK.ask('Execute %r ?' % scriptpath,
+ ('Y','n','show','abort'), 'Y')
+ if answer == 'abort':
+ raise SystemExit(1)
+ elif answer == 'n':
return False
elif answer == 'show':
stream = open(scriptpath)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.6.1_Any.py Mon Feb 15 18:44:47 2010 +0100
@@ -0,0 +1,1 @@
+sync_schema_props_perms(syncprops=False)
--- a/misc/migration/bootstrapmigration_repository.py Thu Feb 11 12:19:08 2010 +0100
+++ b/misc/migration/bootstrapmigration_repository.py Mon Feb 15 18:44:47 2010 +0100
@@ -10,24 +10,35 @@
applcubicwebversion, cubicwebversion = versions_map['cubicweb']
-if applcubicwebversion < (3, 6, 0) and cubicwebversion >= (3, 6, 0):
- from cubicweb.server import schemaserial as ss
+from cubicweb.server import schemaserial as ss
+def _add_relation_definition_no_perms(subjtype, rtype, objtype):
+ rschema = fsschema.rschema(rtype)
+ for query, args in ss.rdef2rql(rschema, subjtype, objtype, groupmap=None):
+ rql(query, args, ask_confirm=False)
+ commit(ask_confirm=False)
+
+if applcubicwebversion == (3, 6, 0) and cubicwebversion >= (3, 6, 0):
+ _add_relation_definition_no_perms('CWAttribute', 'update_permission', 'CWGroup')
+ _add_relation_definition_no_perms('CWAttribute', 'update_permission', 'RQLExpression')
+ session.set_pool()
+ session.unsafe_execute('SET X update_permission Y WHERE X is CWAttribute, X add_permission Y')
+ drop_relation_definition('CWAttribute', 'add_permission', 'CWGroup')
+ drop_relation_definition('CWAttribute', 'add_permission', 'RQLExpression')
+ drop_relation_definition('CWAttribute', 'delete_permission', 'CWGroup')
+ drop_relation_definition('CWAttribute', 'delete_permission', 'RQLExpression')
+
+elif applcubicwebversion < (3, 6, 0) and cubicwebversion >= (3, 6, 0):
session.set_pool()
session.execute = session.unsafe_execute
permsdict = ss.deserialize_ertype_permissions(session)
- def _add_relation_definition_no_perms(subjtype, rtype, objtype):
- rschema = fsschema.rschema(rtype)
- for query, args in ss.rdef2rql(rschema, subjtype, objtype, groupmap=None):
- rql(query, args, ask_confirm=False)
- commit(ask_confirm=False)
config.disabled_hooks_categories.add('integrity')
for rschema in repo.schema.relations():
rpermsdict = permsdict.get(rschema.eid, {})
for rdef in rschema.rdefs.values():
- for action in ('read', 'add', 'delete'):
+ for action in rdef.ACTIONS:
actperms = []
- for something in rpermsdict.get(action, ()):
+ for something in rpermsdict.get(action == 'update' and 'add' or action, ()):
if isinstance(something, tuple):
actperms.append(rdef.rql_expression(*something))
else: # group name
@@ -36,18 +47,32 @@
for action in ('read', 'add', 'delete'):
_add_relation_definition_no_perms('CWRelation', '%s_permission' % action, 'CWGroup')
_add_relation_definition_no_perms('CWRelation', '%s_permission' % action, 'RQLExpression')
+ for action in ('read', 'update'):
_add_relation_definition_no_perms('CWAttribute', '%s_permission' % action, 'CWGroup')
_add_relation_definition_no_perms('CWAttribute', '%s_permission' % action, 'RQLExpression')
for action in ('read', 'add', 'delete'):
- rql('SET X %s_permission Y WHERE X is IN (CWAttribute, CWRelation), '
+ rql('SET X %s_permission Y WHERE X is CWRelation, '
'RT %s_permission Y, X relation_type RT, Y is CWGroup' % (action, action))
rql('INSERT RQLExpression Y: Y exprtype YET, Y mainvars YMV, Y expression YEX, '
- 'X %s_permission Y WHERE X is IN (CWAttribute, CWRelation), '
+ 'X %s_permission Y WHERE X is CWRelation, '
'X relation_type RT, RT %s_permission Y2, Y2 exprtype YET, '
'Y2 mainvars YMV, Y2 expression YEX' % (action, action))
+ rql('SET X read_permission Y WHERE X is CWAttribute, '
+ 'RT read_permission Y, X relation_type RT, Y is CWGroup')
+ rql('INSERT RQLExpression Y: Y exprtype YET, Y mainvars YMV, Y expression YEX, '
+ 'X read_permission Y WHERE X is CWAttribute, '
+ 'X relation_type RT, RT read_permission Y2, Y2 exprtype YET, '
+ 'Y2 mainvars YMV, Y2 expression YEX')
+ rql('SET X update_permission Y WHERE X is CWAttribute, '
+ 'RT add_permission Y, X relation_type RT, Y is CWGroup')
+ rql('INSERT RQLExpression Y: Y exprtype YET, Y mainvars YMV, Y expression YEX, '
+ 'X update_permission Y WHERE X is CWAttribute, '
+ 'X relation_type RT, RT add_permission Y2, Y2 exprtype YET, '
+ 'Y2 mainvars YMV, Y2 expression YEX')
+ for action in ('read', 'add', 'delete'):
drop_relation_definition('CWRType', '%s_permission' % action, 'CWGroup', commit=False)
drop_relation_definition('CWRType', '%s_permission' % action, 'RQLExpression')
- config.disabled_hooks_categories.add('integrity')
+ config.disabled_hooks_categories.remove('integrity')
if applcubicwebversion < (3, 4, 0) and cubicwebversion >= (3, 4, 0):
--- a/schema.py Thu Feb 11 12:19:08 2010 +0100
+++ b/schema.py Mon Feb 15 18:44:47 2010 +0100
@@ -283,22 +283,10 @@
isinstance(group_or_rqlexpr, RQLExpression):
msg = "can't use rql expression for read permission of %s"
raise BadSchemaDefinition(msg % self)
- elif self.final and isinstance(group_or_rqlexpr, RRQLExpression):
- if schema.reading_from_database:
- # we didn't have final relation earlier, so turn
- # RRQLExpression into ERQLExpression now
- rqlexpr = group_or_rqlexpr
- newrqlexprs = [x for x in self.get_rqlexprs(action)
- if not x is rqlexpr]
- newrqlexprs.append(ERQLExpression(rqlexpr.expression,
- rqlexpr.mainvars,
- rqlexpr.eid))
- self.set_rqlexprs(action, newrqlexprs)
- else:
- msg = "can't use RRQLExpression on %s, use an ERQLExpression"
- raise BadSchemaDefinition(msg % self)
- elif not self.final and \
- isinstance(group_or_rqlexpr, ERQLExpression):
+ if self.final and isinstance(group_or_rqlexpr, RRQLExpression):
+ msg = "can't use RRQLExpression on %s, use an ERQLExpression"
+ raise BadSchemaDefinition(msg % self)
+ if not self.final and isinstance(group_or_rqlexpr, ERQLExpression):
msg = "can't use ERQLExpression on %s, use a RRQLExpression"
raise BadSchemaDefinition(msg % self)
RelationDefinitionSchema.check_permission_definitions = check_permission_definitions
@@ -314,13 +302,14 @@
if eid is None and edef is not None:
eid = getattr(edef, 'eid', None)
self.eid = eid
- # take care: no _groups attribute when deep-copying
- if getattr(self, 'permissions', None):
- for groups in self.permissions.itervalues():
- for group_or_rqlexpr in groups:
- if isinstance(group_or_rqlexpr, RRQLExpression):
- msg = "can't use RRQLExpression on an entity type, use an ERQLExpression (%s)"
- raise BadSchemaDefinition(msg % self.type)
+
+ def check_permission_definitions(self):
+ super(CubicWebEntitySchema, self).check_permission_definitions()
+ for groups in self.permissions.itervalues():
+ for group_or_rqlexpr in groups:
+ if isinstance(group_or_rqlexpr, RRQLExpression):
+ msg = "can't use RRQLExpression on %s, use an ERQLExpression"
+ raise BadSchemaDefinition(msg % self.type)
def attribute_definitions(self):
"""return an iterator on attribute definitions
@@ -426,14 +415,24 @@
def has_perm(self, session, action, **kwargs):
"""return true if the action is granted globaly or localy"""
- if 'fromeid' in kwargs:
- subjtype = session.describe(kwargs['fromeid'])[0]
+ if self.final:
+ assert not ('fromeid' in kwargs or 'toeid' in kwargs), kwargs
+ assert action in ('read', 'update')
+ if 'eid' in kwargs:
+ subjtype = session.describe(kwargs['eid'])[0]
+ else:
+ subjtype = objtype = None
else:
- subjtype = None
- if 'toeid' in kwargs:
- objtype = session.describe(kwargs['toeid'])[0]
- else:
- objtype = None
+ assert not 'eid' in kwargs, kwargs
+ assert action in ('read', 'add', 'delete')
+ if 'fromeid' in kwargs:
+ subjtype = session.describe(kwargs['fromeid'])[0]
+ else:
+ subjtype = None
+ if 'toeid' in kwargs:
+ objtype = session.describe(kwargs['toeid'])[0]
+ else:
+ objtype = None
if objtype and subjtype:
return self.rdef(subjtype, objtype).has_perm(session, action, **kwargs)
elif subjtype:
@@ -919,6 +918,11 @@
kwargs['o'] = toeid
return self._check(session, **kwargs)
+# in yams, default 'update' perm for attributes granted to managers and owners.
+# Within cw, we want to default to users who may edit the entity holding the
+# attribute.
+ybo.DEFAULT_ATTRPERMS['update'] = (
+ 'managers', ERQLExpression('U has_update_permission X'))
# workflow extensions #########################################################
--- a/schemas/bootstrap.py Thu Feb 11 12:19:08 2010 +0100
+++ b/schemas/bootstrap.py Mon Feb 15 18:44:47 2010 +0100
@@ -9,7 +9,7 @@
_ = unicode
from yams.buildobjs import (EntityType, RelationType, SubjectRelation,
- ObjectRelation, RichString, String, Boolean, Int)
+ RichString, String, Boolean, Int)
from cubicweb.schema import RQLConstraint
from cubicweb.schemas import META_ETYPE_PERMS, META_RTYPE_PERMS
@@ -131,15 +131,6 @@
'relation\'subject, object and to '
'the request user. '))
- read_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='*?', composite='subject',
- description=_('rql expression allowing to read entities/relations of this type'))
- add_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='*?', composite='subject',
- description=_('rql expression allowing to add entities/relations of this type'))
- delete_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='*?', composite='subject',
- description=_('rql expression allowing to delete entities/relations of this type'))
- update_permission = ObjectRelation('CWEType', cardinality='*?', composite='subject',
- description=_('rql expression allowing to update entities of this type'))
-
class CWConstraint(EntityType):
"""define a schema constraint"""
@@ -162,16 +153,6 @@
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
- read_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='**',
- description=_('groups allowed to read entities/relations of this type'))
- add_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'),
- description=_('groups allowed to add entities/relations of this type'))
- delete_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'),
- description=_('groups allowed to delete entities/relations of this type'))
- update_permission = ObjectRelation('CWEType',
- description=_('groups allowed to update entities of this type'))
-
-
class CWProperty(EntityType):
"""used for cubicweb configuration. Once a property has been created you
@@ -215,27 +196,44 @@
inlined = True
class read_permission(RelationType):
- """core relation giving to a group the permission to read an entity or
- relation type
+ """grant permission to read entity or relation through a group or rql
+ expression
"""
__permissions__ = META_RTYPE_PERMS
+ subject = ('CWEType', 'CWAttribute', 'CWRelation')
+ object = ('CWGroup', 'RQLExpression')
+ cardinality = '*?'
+ composite = 'subject'
class add_permission(RelationType):
- """core relation giving to a group the permission to add an entity or
- relation type
+ """grant permission to add entity or relation through a group or rql
+ expression
"""
__permissions__ = META_RTYPE_PERMS
+ subject = ('CWEType', 'CWRelation')
+ object = ('CWGroup', 'RQLExpression')
+ cardinality = '*?'
+ composite = 'subject'
class delete_permission(RelationType):
- """core relation giving to a group the permission to delete an entity or
- relation type
+ """grant permission to delete entity or relation through a group or rql
+ expression
"""
__permissions__ = META_RTYPE_PERMS
+ subject = ('CWEType', 'CWRelation')
+ object = ('CWGroup', 'RQLExpression')
+ cardinality = '*?'
+ composite = 'subject'
class update_permission(RelationType):
- """core relation giving to a group the permission to update an entity type
+ """grant permission to update entity or attribute through a group or rql
+ expression
"""
__permissions__ = META_RTYPE_PERMS
+ subject = ('CWEType', 'CWAttribute')
+ object = ('CWGroup', 'RQLExpression')
+ cardinality = '*?'
+ composite = 'subject'
class is_(RelationType):
--- a/server/migractions.py Thu Feb 11 12:19:08 2010 +0100
+++ b/server/migractions.py Mon Feb 15 18:44:47 2010 +0100
@@ -1166,6 +1166,10 @@
if not isinstance(rql, (tuple, list)):
rql = ( (rql, kwargs), )
res = None
+ try:
+ execute = self._cw.unsafe_execute
+ except AttributeError:
+ execute = self._cw.execute
for rql, kwargs in rql:
if kwargs:
msg = '%s (%s)' % (rql, kwargs)
@@ -1173,7 +1177,7 @@
msg = rql
if not ask_confirm or self.confirm('execute rql: %s ?' % msg):
try:
- res = self._cw.execute(rql, kwargs, cachekey)
+ res = execute(rql, kwargs, cachekey)
except Exception, ex:
if self.confirm('error: %s\nabort?' % ex):
raise
--- a/server/schemaserial.py Thu Feb 11 12:19:08 2010 +0100
+++ b/server/schemaserial.py Mon Feb 15 18:44:47 2010 +0100
@@ -189,13 +189,17 @@
definition dictionary as built by deserialize_ertype_permissions for a
given erschema's eid
"""
+ # reset erschema permissions here to avoid getting yams default anyway
+ erschema.permissions = dict((action, ()) for action in erschema.ACTIONS)
try:
thispermsdict = permsdict[erschema.eid]
except KeyError:
return
- permissions = erschema.permissions
for action, somethings in thispermsdict.iteritems():
- permissions[action] = tuple(
+ # XXX cw < 3.6.1 bw compat
+ if isinstance(erschema, schemamod.RelationDefinitionSchema) and erschema.final and action == 'add':
+ action = 'update'
+ erschema.permissions[action] = tuple(
isinstance(p, tuple) and erschema.rql_expression(*p) or p
for p in somethings)
--- a/server/sources/ldapuser.py Thu Feb 11 12:19:08 2010 +0100
+++ b/server/sources/ldapuser.py Mon Feb 15 18:44:47 2010 +0100
@@ -78,7 +78,7 @@
('auth-realm',
{'type' : 'string',
'default': None,
- 'help': 'realm to use when using gssapp/kerberos authentication.',
+ 'help': 'realm to use when using gssapi/kerberos authentication.',
'group': 'ldap-source', 'inputlevel': 1,
}),
--- a/server/test/data/schema.py Thu Feb 11 12:19:08 2010 +0100
+++ b/server/test/data/schema.py Mon Feb 15 18:44:47 2010 +0100
@@ -137,14 +137,13 @@
class para(RelationType):
__permissions__ = {
'read': ('managers', 'users', 'guests'),
- 'add': ('managers', ERQLExpression('X in_state S, S name "todo"')),
- 'delete': ('managers', ERQLExpression('X in_state S, S name "todo"')),
+ 'update': ('managers', ERQLExpression('X in_state S, S name "todo"')),
}
class test(RelationType):
__permissions__ = {'read': ('managers', 'users', 'guests'),
- 'delete': ('managers',),
- 'add': ('managers',)}
+ 'update': ('managers',),
+ }
class multisource_rel(RelationDefinition):
subject = ('Card', 'Note')
--- a/toolsutils.py Thu Feb 11 12:19:08 2010 +0100
+++ b/toolsutils.py Mon Feb 15 18:44:47 2010 +0100
@@ -10,6 +10,7 @@
# XXX move most of this in logilab.common (shellutils ?)
import os, sys
+import subprocess
from os import listdir, makedirs, environ, chmod, walk, remove
from os.path import exists, join, abspath, normpath
@@ -75,8 +76,8 @@
user decision
"""
import shutil
- p_output = os.popen('diff -u %s %s' % (appl_file, ref_file), 'r')
- diffs = p_output.read()
+ pipe = subprocess.Popen(['diff', '-u', appl_file, ref_file], stdout=subprocess.PIPE)
+ diffs = pipe.stdout.read()
if diffs:
if askconfirm:
print
--- a/vregistry.py Thu Feb 11 12:19:08 2010 +0100
+++ b/vregistry.py Mon Feb 15 18:44:47 2010 +0100
@@ -365,7 +365,6 @@
def initialization_completed(self):
for regname, reg in self.iteritems():
- self.debug('available in registry %s: %s', regname, sorted(reg))
reg.initialization_completed()
def load_file(self, filepath, modname, force_reload=False):
@@ -406,7 +405,6 @@
if objname.startswith('_'):
continue
self._load_ancestors_then_object(module.__name__, obj)
- self.debug('loaded %s', module)
def _load_ancestors_then_object(self, modname, appobjectcls):
"""handle automatic appobject class registration:
--- a/web/formfields.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/formfields.py Mon Feb 15 18:44:47 2010 +0100
@@ -816,6 +816,18 @@
def format_single_value(self, req, value):
return value
+ def process_form_value(self, form):
+ """process posted form and return correctly typed value"""
+ try:
+ return form.formvalues[self]
+ except KeyError:
+ value = self._process_form_value(form)
+ # if value is None, there are some remaining pending fields, we'll
+ # have to recompute this later -> don't cache in formvalues
+ if value is not None:
+ form.formvalues[self] = value
+ return value
+
def _process_form_value(self, form):
"""process posted form and return correctly typed value"""
widget = self.get_widget(form)
@@ -826,7 +838,6 @@
values = (values,)
eids = set()
for eid in values:
- # XXX 'not eid' for AutoCompletionWidget, deal with this in the widget
if not eid or eid == INTERNAL_FIELD_VALUE:
continue
typed_eid = form.actual_eid(eid)
--- a/web/formwidgets.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/formwidgets.py Mon Feb 15 18:44:47 2010 +0100
@@ -17,6 +17,7 @@
from cubicweb import tags, uilib
from cubicweb.web import stdmsgs, INTERNAL_FIELD_VALUE, ProcessFormError
+
class FieldWidget(object):
"""abstract widget class"""
# javascript / css files required by the widget
--- a/web/test/unittest_views_editforms.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/test/unittest_views_editforms.py Mon Feb 15 18:44:47 2010 +0100
@@ -16,7 +16,11 @@
AFS = uicfg.autoform_section
def rbc(entity, formtype, section):
- return [(rschema.type, x) for rschema, tschemas, x in AFS.relations_by_section(entity, formtype, section)]
+ if section in ('attributes', 'metadata', 'hidden'):
+ permission = 'update'
+ else:
+ permission = 'add'
+ return [(rschema.type, x) for rschema, tschemas, x in AFS.relations_by_section(entity, formtype, section, permission)]
class AutomaticEntityFormTC(CubicWebTC):
@@ -69,19 +73,16 @@
[('use_email', 'subject'),
])
# owned_by is defined both as subject and object relations on CWUser
- self.assertListEquals(rbc(e, 'main', 'hidden'),
- [('in_state', 'subject'),
- ('is', 'subject'),
- ('is_instance_of', 'subject'),
- ('has_text', 'subject'),
- ('identity', 'subject'),
- ('tags', 'object'),
- ('for_user', 'object'),
- ('created_by', 'object'),
- ('wf_info_for', 'object'),
- ('owned_by', 'object'),
- ('identity', 'object'),
- ])
+ self.assertListEquals(sorted(rbc(e, 'main', 'hidden')),
+ sorted([('has_text', 'subject'),
+ ('identity', 'subject'),
+ ('tags', 'object'),
+ ('for_user', 'object'),
+ ('created_by', 'object'),
+ ('wf_info_for', 'object'),
+ ('owned_by', 'object'),
+ ('identity', 'object'),
+ ]))
def test_inlined_view(self):
self.failUnless('main_inlined' in AFS.etype_get('CWUser', 'use_email', 'subject', 'EmailAddress'))
@@ -122,10 +123,8 @@
('connait', 'object')
])
self.assertListEquals(rbc(e, 'main', 'hidden'),
- [('is', 'subject'),
- ('has_text', 'subject'),
+ [('has_text', 'subject'),
('identity', 'subject'),
- ('is_instance_of', 'subject'),
('identity', 'object'),
])
--- a/web/uicfg.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/uicfg.py Mon Feb 15 18:44:47 2010 +0100
@@ -312,6 +312,10 @@
formsections.add('%s_%s' % (formtype, section))
def tag_relation(self, key, formtype, section=None):
+ if isinstance(formtype, tuple):
+ for ftype in formtype:
+ self.tag_relation(key, ftype, section)
+ return
if section is None:
tag = formtype
for formtype, section in self.bw_tag_map[tag].iteritems():
@@ -343,8 +347,8 @@
# overriden to avoid recomputing done in parent classes
return self._tagdefs.get(key, ())
- def relations_by_section(self, entity, formtype, section,
- permission=None, strict=False):
+ def relations_by_section(self, entity, formtype, section, permission,
+ strict=False):
"""return a list of (relation schema, target schemas, role) for the
given entity matching categories and permission.
@@ -359,52 +363,60 @@
else:
eid = None
strict = False
+ if permission == 'update':
+ assert section in ('attributes', 'metadata', 'hidden')
+ relpermission = 'add'
+ else:
+ assert section not in ('attributes', 'metadata', 'hidden')
+ relpermission = permission
cw = entity._cw
for rschema, targetschemas, role in eschema.relation_definitions(True):
- # check category first, potentially lower cost than checking
- # permission which may imply rql queries
_targetschemas = []
for tschema in targetschemas:
+ # check section's tag first, potentially lower cost than
+ # checking permission which may imply rql queries
if not tag in self.etype_get(eschema, rschema, role, tschema):
continue
rdef = rschema.role_rdef(eschema, tschema, role)
- if permission is not None and \
- not ((not strict and rdef.has_local_role(permission)) or
- rdef.has_perm(cw, permission, fromeid=eid)):
- continue
+ if rschema.final:
+ if not rdef.has_perm(cw, permission, eid=eid):
+ continue
+ elif strict or not rdef.has_local_role(relpermission):
+ if role == 'subject':
+ if not rdef.has_perm(cw, relpermission, fromeid=eid):
+ continue
+ elif role == 'object':
+ if not rdef.has_perm(cw, relpermission, toeid=eid):
+ continue
_targetschemas.append(tschema)
if not _targetschemas:
continue
targetschemas = _targetschemas
- if permission is not None:
- rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
- # tag allowing to hijack the permission machinery when
- # permission is not verifiable until the entity is actually
- # created...
- if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
- yield (rschema, targetschemas, role)
+ rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
+ # XXX tag allowing to hijack the permission machinery when
+ # permission is not verifiable until the entity is actually
+ # created...
+ if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
+ yield (rschema, targetschemas, role)
+ continue
+ if not rschema.final and role == 'subject':
+ # on relation with cardinality 1 or ?, we need delete perm as well
+ # if the relation is already set
+ if (relpermission == 'add'
+ and rdef.role_cardinality(role) in '1?'
+ and eid and entity.related(rschema.type, role)
+ and not rdef.has_perm(cw, 'delete', fromeid=eid,
+ toeid=entity.related(rschema.type, role)[0][0])):
continue
- if rschema.final:
- if not rdef.has_perm(cw, permission, fromeid=eid):
- continue
- elif role == 'subject':
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (permission == 'add'
- and rdef.role_cardinality(role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rdef.has_perm(cw, 'delete', fromeid=eid,
- toeid=entity.related(rschema.type, role)[0][0])):
- continue
- elif role == 'object':
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (permission == 'add'
- and rdef.role_cardinality(role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rdef.has_perm(cw, 'delete', toeid=eid,
- fromeid=entity.related(rschema.type, role)[0][0])):
- continue
+ elif role == 'object':
+ # on relation with cardinality 1 or ?, we need delete perm as well
+ # if the relation is already set
+ if (relpermission == 'add'
+ and rdef.role_cardinality(role) in '1?'
+ and eid and entity.related(rschema.type, role)
+ and not rdef.has_perm(cw, 'delete', toeid=eid,
+ fromeid=entity.related(rschema.type, role)[0][0])):
+ continue
yield (rschema, targetschemas, role)
autoform_section = AutoformSectionRelationTags('autoform_section')
@@ -442,8 +454,8 @@
class AutoformIsInlined(RelationTags):
"""XXX for < 3.6 bw compat"""
def tag_relation(self, key, tag):
- warn('autoform_is_inlined rtag is deprecated, use autoform_section '
- 'with inlined formtype and "attributes" or "hidden" section',
+ warn('autoform_is_inlined is deprecated, use autoform_section '
+ 'with formtype="inlined", section="attributes" or section="hidden"',
DeprecationWarning, stacklevel=3)
section = tag and 'inlined' or 'hidden'
autoform_section.tag_relation(key, 'main', section)
--- a/web/views/actions.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/actions.py Mon Feb 15 18:44:47 2010 +0100
@@ -31,7 +31,7 @@
# if user has no update right but it can modify some relation,
# display action anyway
form = entity._cw.vreg['forms'].select('edition', entity._cw,
- entity=entity)
+ entity=entity)
for dummy in form.editable_relations():
return 1
try:
--- a/web/views/autoform.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/autoform.py Mon Feb 15 18:44:47 2010 +0100
@@ -85,7 +85,10 @@
def __init__(self, *args, **kwargs):
for attr in self._select_attrs:
- setattr(self, attr, kwargs.pop(attr, None))
+ # don't pop attributes from kwargs, so the end-up in
+ # self.cw_extra_kwargs which is then passed to the edition form (see
+ # the .form method)
+ setattr(self, attr, kwargs.get(attr))
super(InlineEntityEditionFormView, self).__init__(*args, **kwargs)
def _entity(self):
@@ -384,7 +387,11 @@
related = []
if entity.has_eid():
rset = entity.related(rschema, role, limit=form.related_limit)
- if rschema.has_perm(form._cw, 'delete'):
+ if role == 'subject':
+ haspermkwargs = {'fromeid': entity.eid}
+ else:
+ haspermkwargs = {'toeid': entity.eid}
+ if rschema.has_perm(form._cw, 'delete', **haspermkwargs):
toggleable_rel_link_func = toggleable_relation_link
else:
toggleable_rel_link_func = lambda x, y, z: u''
@@ -650,7 +657,7 @@
return self.display_fields
# XXX we should simply put eid in the generated section, no?
return [(rtype, role) for rtype, _, role in self._relations_by_section(
- 'attributes', strict=strict) if rtype != 'eid']
+ 'attributes', 'update', strict) if rtype != 'eid']
def editable_relations(self):
"""return a sorted list of (relation's label, relation'schema, role) for
--- a/web/views/calendar.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/calendar.py Mon Feb 15 18:44:47 2010 +0100
@@ -155,7 +155,9 @@
last_day_of_month = date(year + 1, 1, 1) - timedelta(1)
else:
last_day_of_month = date(year, month + 1, 1) - timedelta(1)
- lastday = last_day_of_month + timedelta(6 - last_day_of_month.weekday())
+ # date range exclude last day so we should at least add one day, hence
+ # the 7
+ lastday = last_day_of_month + timedelta(7 - last_day_of_month.weekday())
month_dates = list(date_range(firstday, lastday))
dates = {}
task_max = 0
@@ -250,7 +252,6 @@
# output header
self.w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>' %
tuple(self._cw._(day) for day in WEEKDAYS))
-
# build calendar
for mdate, task_rows in zip(month_dates, days):
if mdate.weekday() == 0:
--- a/web/views/formrenderers.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/formrenderers.py Mon Feb 15 18:44:47 2010 +0100
@@ -92,7 +92,7 @@
self.render_fields(w, form, values)
self.render_buttons(w, form)
w(u'</fieldset>')
- w(u'</form>')
+ w(self.close_form(form, values))
errormsg = self.error_message(form)
if errormsg:
data.insert(0, errormsg)
@@ -171,6 +171,13 @@
tag += ' cubicweb:target="%s"' % xml_escape(form.cwtarget)
return tag + '>'
+ def close_form(self, form, values):
+ """seem dump but important for consistency w/ close form, and necessary
+ for form renderers overriding open_form to use something else or more than
+ and <form>
+ """
+ return '</form>'
+
def render_fields(self, w, form, values):
fields = self._render_hidden_fields(w, form)
if fields:
--- a/web/views/forms.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/forms.py Mon Feb 15 18:44:47 2010 +0100
@@ -266,6 +266,9 @@
self.form_renderer_id, self._cw, rset=self.cw_rset, row=self.cw_row,
col=self.cw_col, entity=self.edited_entity)
+ def should_display_add_new_relation_link(self, rschema, existant, card):
+ return False
+
# controller side method (eg POST reception handling)
def actual_eid(self, eid):
@@ -284,9 +287,6 @@
def editable_relations(self):
return ()
- def should_display_add_new_relation_link(self, rschema, existant, card):
- return False
-
@deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')
def subject_relation_vocabulary(self, rtype, limit=None):
"""defaut vocabulary method for the given relation, looking for
--- a/web/views/primary.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/primary.py Mon Feb 15 18:44:47 2010 +0100
@@ -46,8 +46,8 @@
self.render_entity(entity)
def render_entity(self, entity):
+ self.render_entity_toolbox(entity)
self.render_entity_title(entity)
- self.render_entity_toolbox(entity)
# entity's attributes and relations, excluding meta data
# if the entity isn't meta itself
if self.is_primary():
@@ -161,7 +161,7 @@
try:
label, rset, vid, dispctrl = box
except ValueError:
- warn('box views should now be defined as a 4-uple (label, rset, vid, dispctrl), '
+ warn('[3.5] box views should now be defined as a 4-uple (label, rset, vid, dispctrl), '
'please update %s' % self.__class__.__name__,
DeprecationWarning)
label, rset, vid = box
--- a/web/views/schema.py Thu Feb 11 12:19:08 2010 +0100
+++ b/web/views/schema.py Mon Feb 15 18:44:47 2010 +0100
@@ -380,7 +380,6 @@
def _generate(self, tmpfile):
"""display global schema information"""
- print 'skipedtypes', skip_types(self._cw)
visitor = FullSchemaVisitor(self._cw, self._cw.vreg.schema,
skiptypes=skip_types(self._cw))
s2d.schema2dot(outputfile=tmpfile, visitor=visitor)