# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1238097800 -3600 # Node ID 9b23a6836c320be32d9050d05ed47f03b1d71ef1 # Parent 6a7636b32a97883811dcb1d612b9bc74ee5a958b support for old __rtags__ diff -r 6a7636b32a97 -r 9b23a6836c32 entities/__init__.py --- a/entities/__init__.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entities/__init__.py Thu Mar 26 21:03:20 2009 +0100 @@ -23,36 +23,7 @@ """an entity instance has e_schema automagically set on the class and instances have access to their issuing cursor """ - id = 'Any' - __rtags__ = { - 'is' : ('generated', 'link'), - 'is_instance_of' : ('generated', 'link'), - 'identity' : ('generated', 'link'), - - # use primary and not generated for eid since it has to be an hidden - # field in edition - ('eid', '*', 'subject'): 'primary', - ('creation_date', '*', 'subject'): 'generated', - ('modification_date', '*', 'subject'): 'generated', - ('has_text', '*', 'subject'): 'generated', - - ('require_permission', '*', 'subject') : ('generated', 'link'), - ('owned_by', '*', 'subject') : ('generated', 'link'), - ('created_by', '*', 'subject') : ('generated', 'link'), - - ('wf_info_for', '*', 'subject') : ('generated', 'link'), - ('wf_info_for', '*', 'object') : ('generated', 'link'), - - ('description', '*', 'subject'): 'secondary', - - # XXX should be moved in their respective cubes - ('filed_under', '*', 'subject') : ('generic', 'link'), - ('filed_under', '*', 'object') : ('generic', 'create'), - # generated since there is a componant to handle comments - ('comments', '*', 'subject') : ('generated', 'link'), - ('comments', '*', 'object') : ('generated', 'link'), - } - + id = 'Any' __implements__ = (IBreadCrumbs, IFeed) @classmethod @@ -277,64 +248,11 @@ tschema = rschema.subjects(cls.e_schema)[0] wdg = widget(cls.vreg, tschema, rschema, cls, 'object') return wdg - + + @obsolete('use AutomaticEntityForm.relations_by_category') def relations_by_category(self, categories=None, permission=None): - if categories is not None: - if not isinstance(categories, (list, tuple, set, frozenset)): - categories = (categories,) - if not isinstance(categories, (set, frozenset)): - categories = frozenset(categories) - eschema, rtags = self.e_schema, self.rtags - if self.has_eid(): - eid = self.eid - else: - eid = None - for rschema, targetschemas, role in eschema.relation_definitions(True): - if rschema in ('identity', 'has_text'): - continue - # check category first, potentially lower cost than checking - # permission which may imply rql queries - if categories is not None: - targetschemas = [tschema for tschema in targetschemas - if rtags.get_tags(rschema.type, tschema.type, role).intersection(categories)] - if not targetschemas: - continue - tags = rtags.get_tags(rschema.type, role=role) - if permission is not None: - # 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 tags: - yield (rschema, targetschemas, role) - continue - if rschema.is_final(): - if not rschema.has_perm(self.req, permission, eid): - continue - elif role == 'subject': - if not ((eid is None and rschema.has_local_role(permission)) or - rschema.has_perm(self.req, permission, fromeid=eid)): - continue - # on relation with cardinality 1 or ?, we need delete perm as well - # if the relation is already set - if (permission == 'add' - and rschema.cardinality(eschema, targetschemas[0], role) in '1?' - and self.has_eid() and self.related(rschema.type, role) - and not rschema.has_perm(self.req, 'delete', fromeid=eid, - toeid=self.related(rschema.type, role)[0][0])): - continue - elif role == 'object': - if not ((eid is None and rschema.has_local_role(permission)) or - rschema.has_perm(self.req, permission, toeid=eid)): - continue - # on relation with cardinality 1 or ?, we need delete perm as well - # if the relation is already set - if (permission == 'add' - and rschema.cardinality(targetschemas[0], eschema, role) in '1?' - and self.has_eid() and self.related(rschema.type, role) - and not rschema.has_perm(self.req, 'delete', toeid=eid, - fromeid=self.related(rschema.type, role)[0][0])): - continue - yield (rschema, targetschemas, role) + from cubicweb.web.views.editform import AutomaticEntityForm + return AutomaticEntityForm.relations_by_category(entity, categories, permission) def srelations_by_category(self, categories=None, permission=None): result = [] diff -r 6a7636b32a97 -r 9b23a6836c32 entities/authobjs.py --- a/entities/authobjs.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entities/authobjs.py Thu Mar 26 21:03:20 2009 +0100 @@ -13,7 +13,6 @@ class EGroup(AnyEntity): id = 'EGroup' fetch_attrs, fetch_order = fetch_config(['name']) - __rtags__ = dict(in_group='create') def db_key_name(self): """XXX goa specific""" @@ -24,18 +23,6 @@ id = 'EUser' fetch_attrs, fetch_order = fetch_config(['login', 'firstname', 'surname']) - __rtags__ = { 'firstname' : 'secondary', - 'surname' : 'secondary', - 'last_login_time' : 'generated', - 'todo_by' : 'create', - 'use_email' : 'inlineview', # 'primary', - 'in_state' : 'primary', - 'in_group' : 'primary', - ('owned_by', '*', 'object') : ('generated', 'link'), - ('created_by','*','object') : ('generated', 'link'), - ('bookmarked_by', '*', 'object'): ('generated', 'create'), - } - # used by repository to check if the user can log in or not AUTHENTICABLE_STATES = ('activated',) diff -r 6a7636b32a97 -r 9b23a6836c32 entities/lib.py --- a/entities/lib.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entities/lib.py Thu Mar 26 21:03:20 2009 +0100 @@ -25,10 +25,6 @@ id = 'EmailAddress' fetch_attrs, fetch_order = fetch_config(['address', 'alias', 'canonical']) - widgets = { - 'address' : "EmailWidget", - } - def dc_title(self): if self.alias: return '%s <%s>' % (self.alias, self.display_address()) @@ -94,13 +90,7 @@ class EProperty(AnyEntity): id = 'EProperty' - fetch_attrs, fetch_order = fetch_config(['pkey', 'value']) - - widgets = { - 'pkey' : "PropertyKeyWidget", - 'value' : "PropertyValueWidget", - } - + fetch_attrs, fetch_order = fetch_config(['pkey', 'value']) rest_attr = 'pkey' def typed_value(self): @@ -120,10 +110,6 @@ """customized class for Bookmark entities""" id = 'Bookmark' fetch_attrs, fetch_order = fetch_config(['title', 'path']) - widgets = { - 'path' : "StringWidget", - } - __rtags__ = {'path': 'primary'} def actual_url(self): url = self.req.build_url(self.path) diff -r 6a7636b32a97 -r 9b23a6836c32 entities/schemaobjs.py --- a/entities/schemaobjs.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entities/schemaobjs.py Thu Mar 26 21:03:20 2009 +0100 @@ -1,7 +1,7 @@ """schema definition related entities :organization: Logilab -:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" @@ -17,14 +17,7 @@ class EEType(AnyEntity): id = 'EEType' fetch_attrs, fetch_order = fetch_config(['name']) - __rtags__ = { - ('final', '*', 'subject'): 'generated', - - ('state_of', '*', 'object'): 'create', - ('transition_of', '*', 'object'): 'create', - ('from_entity', '*', 'object'): 'link', - ('to_entity', '*', 'object'): 'link', - } + def dc_title(self): return self.req._(self.name) @@ -47,11 +40,6 @@ class ERType(AnyEntity): id = 'ERType' fetch_attrs, fetch_order = fetch_config(['name']) - __rtags__ = { - ('final', '*', 'subject'): 'generated', - - ('relation_type', '*', 'object') : 'create', - } def dc_title(self): return self.req._(self.name) @@ -100,11 +88,6 @@ class ENFRDef(AnyEntity): id = 'ENFRDef' fetch_attrs = fetch_config(['cardinality'])[0] - __rtags__ = { - ('relation_type', 'ERType', 'subject') : 'inlineview', - ('from_entity', 'EEType', 'subject') : 'inlineview', - ('to_entity', 'EEType', 'subject') : 'inlineview', - } def dc_title(self): return u'%s %s %s' % ( @@ -171,10 +154,6 @@ id = 'RQLExpression' fetch_attrs, fetch_order = fetch_config(['exprtype', 'mainvars', 'expression']) - widgets = { - 'expression' : "StringWidget", - } - def dc_title(self): return '%s(%s)' % (self.exprtype, self.expression or u'') @@ -209,11 +188,6 @@ id = 'EPermission' fetch_attrs, fetch_order = fetch_config(['name', 'label']) - - __rtags__ = { - 'require_group' : 'primary', - } - def dc_title(self): if self.label: return '%s (%s)' % (self.req._(self.name), self.label) diff -r 6a7636b32a97 -r 9b23a6836c32 entities/wfobjs.py --- a/entities/wfobjs.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entities/wfobjs.py Thu Mar 26 21:03:20 2009 +0100 @@ -1,14 +1,14 @@ """workflow definition and history related entities :organization: Logilab -:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" from cubicweb.entities import AnyEntity, fetch_config - + class Transition(AnyEntity): """customized class for Transition entities @@ -17,9 +17,6 @@ """ id = 'Transition' fetch_attrs, fetch_order = fetch_config(['name']) - __rtags__ = {('destination_state', '*', 'subject'): 'create', - ('allowed_transition', '*', 'object') : 'create', - } def may_be_passed(self, eid, stateeid): """return true if the logged user may pass this transition @@ -66,11 +63,7 @@ id = 'State' fetch_attrs, fetch_order = fetch_config(['name']) rest_attr = 'eid' - - __rtags__ = {'destination_state' : 'create', - 'allowed_transition' : 'create' - } - + def transitions(self, entity, desteid=None): rql = ('Any T,N,DS where S allowed_transition T, S eid %(x)s, ' 'T name N, T destination_state DS, ' diff -r 6a7636b32a97 -r 9b23a6836c32 entity.py --- a/entity.py Thu Mar 26 20:54:40 2009 +0100 +++ b/entity.py Thu Mar 26 21:03:20 2009 +0100 @@ -6,6 +6,8 @@ """ __docformat__ = "restructuredtext en" +from warnings import warn + from logilab.common import interface from logilab.common.compat import all from logilab.common.decorators import cached @@ -39,164 +41,70 @@ return '1' -class RelationTags(object): - - MODE_TAGS = frozenset(('link', 'create')) - CATEGORY_TAGS = frozenset(('primary', 'secondary', 'generic', 'generated', - 'inlineview')) +MODE_TAGS = set(('link', 'create')) +CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata')) - def __init__(self, eclass, tagdefs): - # XXX if a rtag is redefined in a subclass, - # the rtag of the base class overwrite the rtag of the subclass - self.eclass = eclass - self._tagdefs = {} - for relation, tags in tagdefs.iteritems(): - # tags must become a set - if isinstance(tags, basestring): - tags = set((tags,)) - elif not isinstance(tags, set): - tags = set(tags) - # relation must become a 3-uple (rtype, targettype, role) - if isinstance(relation, basestring): - self._tagdefs[(relation, '*', 'subject')] = tags - self._tagdefs[(relation, '*', 'object')] = tags - elif len(relation) == 1: # useful ? - self._tagdefs[(relation[0], '*', 'subject')] = tags - self._tagdefs[(relation[0], '*', 'object')] = tags - elif len(relation) == 2: - rtype, ttype = relation - ttype = bw_normalize_etype(ttype) # XXX bw compat - self._tagdefs[rtype, ttype, 'subject'] = tags - self._tagdefs[rtype, ttype, 'object'] = tags - elif len(relation) == 3: - relation = list(relation) # XXX bw compat - relation[1] = bw_normalize_etype(relation[1]) - self._tagdefs[tuple(relation)] = tags - else: - raise ValueError('bad rtag definition (%r)' % (relation,)) - +try: + from cubicweb.web.views.editforms import AutomaticEntityForm + from cubicweb.web.views.boxes import EditBox - def __initialize__(self): - # eclass.[*]schema are only set when registering - self.schema = self.eclass.schema - eschema = self.eschema = self.eclass.e_schema - rtags = self._tagdefs - # expand wildcards in rtags and add automatic tags - for rschema, tschemas, role in sorted(eschema.relation_definitions(True)): - rtype = rschema.type - star_tags = rtags.pop((rtype, '*', role), set()) - for tschema in tschemas: - tags = rtags.setdefault((rtype, tschema.type, role), set(star_tags)) - if role == 'subject': - X, Y = eschema, tschema - card = rschema.rproperty(X, Y, 'cardinality')[0] - composed = rschema.rproperty(X, Y, 'composite') == 'object' - else: - X, Y = tschema, eschema - card = rschema.rproperty(X, Y, 'cardinality')[1] - composed = rschema.rproperty(X, Y, 'composite') == 'subject' - # set default category tags if needed - if not tags & self.CATEGORY_TAGS: - if card in '1+': - if not rschema.is_final() and composed: - category = 'generated' - elif rschema.is_final() and ( - rschema.type.endswith('_format') - or rschema.type.endswith('_encoding')): - category = 'generated' - else: - category = 'primary' - elif rschema.is_final(): - if (rschema.type.endswith('_format') - or rschema.type.endswith('_encoding')): - category = 'generated' - else: - category = 'secondary' - else: - category = 'generic' - tags.add(category) - if not tags & self.MODE_TAGS: - if card in '?1': - # by default, suppose link mode if cardinality doesn't allow - # more than one relation - mode = 'link' - elif rschema.rproperty(X, Y, 'composite') == role: - # if self is composed of the target type, create mode - mode = 'create' - else: - # link mode by default - mode = 'link' - tags.add(mode) - - def _default_target(self, rschema, role='subject'): - eschema = self.eschema - if role == 'subject': - return eschema.subject_relation(rschema).objects(eschema)[0] - else: - return eschema.object_relation(rschema).subjects(eschema)[0] - - # dict compat - def __getitem__(self, key): - if isinstance(key, basestring): - key = (key,) - return self.get_tags(*key) - - __contains__ = __getitem__ + def dispatch_rtags(tags, rtype, role, stype, otype): + for tag in tags: + if tag in MODE_TAGS: + EditBox.rmode.set_rtag(tag, rtype, role, stype, otype) + elif tag in CATEGORY_TAGS: + AutomaticEntityForm.rcategories.set_rtag(tag, rtype, role, stype, otype) + elif tag == 'inlined': + AutomaticEntityForm.rinline.set_rtag(True, rtype, role, stype, otype) + else: + raise ValueError(tag) + +except ImportError: + AutomaticEntityForm = None - def get_tags(self, rtype, targettype=None, role='subject'): - rschema = self.schema.rschema(rtype) - if targettype is None: - tschema = self._default_target(rschema, role) - else: - tschema = self.schema.eschema(targettype) - return self._tagdefs[(rtype, tschema.type, role)] - - __call__ = get_tags + def dispatch_rtags(*args): + pass - def get_mode(self, rtype, targettype=None, role='subject'): - # XXX: should we make an assertion on rtype not being final ? - # assert not rschema.is_final() - tags = self.get_tags(rtype, targettype, role) - # do not change the intersection order ! - modes = tags & self.MODE_TAGS - assert len(modes) == 1 - return modes.pop() - - def get_category(self, rtype, targettype=None, role='subject'): - tags = self.get_tags(rtype, targettype, role) - categories = tags & self.CATEGORY_TAGS - assert len(categories) == 1 - return categories.pop() - - def is_inlined(self, rtype, targettype=None, role='subject'): - # return set(('primary', 'secondary')) & self.get_tags(rtype, targettype) - return 'inlineview' in self.get_tags(rtype, targettype, role) - - class metaentity(type): """this metaclass sets the relation tags on the entity class and deals with the `widgets` attribute """ def __new__(mcs, name, bases, classdict): # collect baseclass' rtags - tagdefs = {} - widgets = {} - for base in bases: - tagdefs.update(getattr(base, '__rtags__', {})) - widgets.update(getattr(base, 'widgets', {})) - # update with the class' own rtgas - tagdefs.update(classdict.get('__rtags__', {})) - widgets.update(classdict.get('widgets', {})) - # XXX decide whether or not it's a good idea to replace __rtags__ - # good point: transparent support for inheritance levels >= 2 - # bad point: we loose the information of which tags are specific - # to this entity class - classdict['__rtags__'] = tagdefs - classdict['widgets'] = widgets - eclass = super(metaentity, mcs).__new__(mcs, name, bases, classdict) - # adds the "rtags" attribute - eclass.rtags = RelationTags(eclass, tagdefs) - return eclass + if '__rtags__' in classdict: + etype = classdict['id'] + warn('%s: __rtags__ is deprecated' % name, DeprecationWarning) + for relation, tags in classdict.pop('__rtags__').iteritems(): + # tags must become an iterable + if isinstance(tags, basestring): + tags = (tags,) + # relation must become a 3-uple (rtype, targettype, role) + if isinstance(relation, basestring): + dispatch_rtags(tags, relation, 'subject', etype, '*') + dispatch_rtags(tags, relation, 'object', '*', etype) + elif len(relation) == 1: # useful ? + dispatch_rtags(tags, relation[0], 'subject', etype, '*') + dispatch_rtags(tags, relation[0], 'object', '*', etype) + elif len(relation) == 2: + rtype, ttype = relation + ttype = bw_normalize_etype(ttype) # XXX bw compat + dispatch_rtags(tags, rtype, 'subject', etype, ttype) + dispatch_rtags(tags, rtype, 'object', ttype, etype) + elif len(relation) == 3: + rtype, ttype, role = relation + ttype = bw_normalize_etype(ttype) + if role == 'subject': + dispatch_rtags(tags, rtype, 'subject', etype, ttype) + else: + dispatch_rtags(tags, rtype, 'object', ttype, etype) + else: + raise ValueError('bad rtag definition (%r)' % (relation,)) + if 'widgets' in classdict and AutomaticEntityForm is not None: + etype = classdict['id'] + warn('%s: widgets is deprecated' % name, DeprecationWarning) + for relation, wdgname in classdict.pop('widgets').iteritems(): + AutomaticEntityForm.rwidgets.set_rtag(wdgname, rtype, 'subject', etype) + return super(metaentity, mcs).__new__(mcs, name, bases, classdict) class Entity(AppRsetObject, dict): @@ -273,7 +181,6 @@ if mixins: cls.__bases__ = tuple(mixins + [p for p in cls.__bases__ if not p is object]) cls.debug('plugged %s mixins on %s', mixins, etype) - cls.rtags.__initialize__() @classmethod def fetch_rql(cls, user, restriction=None, fetchattrs=None, mainvar='X', diff -r 6a7636b32a97 -r 9b23a6836c32 web/views/baseforms.py --- a/web/views/baseforms.py Thu Mar 26 20:54:40 2009 +0100 +++ b/web/views/baseforms.py Thu Mar 26 21:03:20 2009 +0100 @@ -21,6 +21,7 @@ from cubicweb.web.controller import NAV_FORM_PARAMETERS from cubicweb.web.widgets import checkbox, InputWidget, ComboBoxWidget from cubicweb.web.form import FormMixIn +from cubicweb.web.views.editforms import AutomaticEntityForm _ = unicode @@ -326,7 +327,7 @@ # should_* method extracted to allow overriding def should_inline_relation_form(self, entity, rschema, targettype, role): - return entity.rtags.is_inlined(rschema, targettype, role) + return AutomaticForm.rinlined.etype_rtag(entity.id, role, rschema, targettype) def should_display_inline_relation_form(self, rschema, existant, card): return not existant and card in '1+' @@ -428,7 +429,7 @@ def should_inline_relation_form(self, entity, rschema, targettype, role): if rschema == self.rschema: return False - return entity.rtags.is_inlined(rschema, targettype, role) + return AutomaticForm.rinlined.etype_rtag(entity.id, role, rschema, targettype) @cached def keep_entity(self, entity): diff -r 6a7636b32a97 -r 9b23a6836c32 web/views/editforms.py --- a/web/views/editforms.py Thu Mar 26 20:54:40 2009 +0100 +++ b/web/views/editforms.py Thu Mar 26 21:03:20 2009 +0100 @@ -249,10 +249,11 @@ def editable_attributes(self): """return a list of (relation schema, role) to edit for the entity """ - return [(rschema, x) for rschema, _, x in self.relations_by_category(self.attrcategories, 'add') - if rschema != 'eid'] - - def relations_by_category(self, categories=None, permission=None): + return [(rschema, x) for rschema, _, x in self.relations_by_category( + self.entity, self.attrcategories, 'add') if rschema != 'eid'] + + @classmethod + def relations_by_category(cls, entity, categories=None, permission=None): """return a list of (relation schema, target schemas, role) matching categories and permission """ @@ -261,11 +262,11 @@ categories = (categories,) if not isinstance(categories, (set, frozenset)): categories = frozenset(categories) - eschema = self.edited_entity.e_schema - rtags = self.rcategories - permsoverrides = self.rpermissions_overrides - if self.edited_entity.has_eid(): - eid = self.edited_entity.eid + eschema = entity.e_schema + rtags = cls.rcategories + permsoverrides = cls.rpermissions_overrides + if entity.has_eid(): + eid = entity.eid else: eid = None for rschema, targetschemas, role in eschema.relation_definitions(True): @@ -286,31 +287,31 @@ yield (rschema, targetschemas, role) continue if rschema.is_final(): - if not rschema.has_perm(self.req, permission, eid): + if not rschema.has_perm(entity.req, permission, eid): continue elif role == 'subject': if not ((eid is None and rschema.has_local_role(permission)) or - rschema.has_perm(self.req, permission, fromeid=eid)): + rschema.has_perm(entity.req, permission, fromeid=eid)): continue # on relation with cardinality 1 or ?, we need delete perm as well # if the relation is already set if (permission == 'add' and rschema.cardinality(eschema, targetschemas[0], role) in '1?' - and eid and self.edited_entity.related(rschema.type, role) - and not rschema.has_perm(self.req, 'delete', fromeid=eid, - toeid=self.edited_entity.related(rschema.type, role)[0][0])): + and eid and entity.related(rschema.type, role) + and not rschema.has_perm(entity.req, 'delete', fromeid=eid, + toeid=entity.related(rschema.type, role)[0][0])): continue elif role == 'object': if not ((eid is None and rschema.has_local_role(permission)) or - rschema.has_perm(self.req, permission, toeid=eid)): + rschema.has_perm(entity.req, permission, toeid=eid)): continue # on relation with cardinality 1 or ?, we need delete perm as well # if the relation is already set if (permission == 'add' and rschema.cardinality(targetschemas[0], eschema, role) in '1?' - and eid and self.edited_entity.related(rschema.type, role) - and not rschema.has_perm(self.req, 'delete', toeid=eid, - fromeid=self.edited_entity.related(rschema.type, role)[0][0])): + and eid and entity.related(rschema.type, role) + and not rschema.has_perm(entity.req, 'delete', toeid=eid, + fromeid=entity.related(rschema.type, role)[0][0])): continue yield (rschema, targetschemas, role) @@ -321,8 +322,8 @@ return a list of (relation's label, relation'schema, role) """ result = [] - for rschema, ttypes, role in self.relations_by_category(categories, - permission): + for rschema, ttypes, role in self.relations_by_category( + self.entity, categories, permission): if rschema.is_final(): continue result.append( (rschema.display_name(self.req, role), rschema, role) )