# HG changeset patch # User Sandrine Ribeau # Date 1270549385 -7200 # Node ID e2476d78b06074f6a217a6f409e29a4b23a7d8cb # Parent 673b63953e7a1347dd63968367eb767648971bb0 ticket #787103, relation schema view enhancements diff -r 673b63953e7a -r e2476d78b060 schemaviewer.py --- a/schemaviewer.py Thu Mar 25 08:30:53 2010 -0700 +++ b/schemaviewer.py Tue Apr 06 12:23:05 2010 +0200 @@ -39,7 +39,6 @@ return Section(children=(Table(cols=2, cheaders=1, rheaders=1, children=data),), klass='acl') - def visit_schema(self, schema, display_relations=0, skiptypes=()): """get a layout for a whole schema""" title = Title(self.req._('Schema %s') % schema.name, @@ -187,6 +186,8 @@ val = getattr(rdef, prop) if val is None: val = '' + elif prop == 'constraints': + val = ', '.join([c.restriction for c in val]) elif isinstance(val, (list, tuple)): val = ', '.join(str(v) for v in val) elif val and isinstance(val, basestring): diff -r 673b63953e7a -r e2476d78b060 web/data/cubicweb.acl.css --- a/web/data/cubicweb.acl.css Thu Mar 25 08:30:53 2010 -0700 +++ b/web/data/cubicweb.acl.css Tue Apr 06 12:23:05 2010 +0200 @@ -17,13 +17,13 @@ } -h3.schema{ +h3.schema{ font-weight: bold; } h4 a, h4 a:link, -h4 a:visited{ +h4 a:visited{ color:#000; } @@ -39,11 +39,11 @@ table.schemaInfo td { padding: .3em .5em; border: 1px solid grey; - width:33%; + width:33%; } -table.schemaInfo tr th { +table.schemaInfo tr th { padding: 0.2em 0px 0.2em 5px; background-image:none; background-color:#dfdfdf; @@ -51,50 +51,45 @@ table.schemaInfo thead tr { border: 1px solid #dfdfdf; -} +} table.schemaInfo td { - padding: 3px 10px 3px 5px; + padding: 3px 10px 3px 5px; } -div.users, a.users{ +a.users{ color : #00CC33; font-weight: bold } -div.guests, a.guests{ +a.guests{ color : #ff7700; font-weight: bold; } -div.staff, a.staff{ - color : #0083ab; - font-weight: bold; -} - -div.owners, a.owners{ +a.owners{ color : #8b0000; font-weight: bold; } -div.managers, a.managers{ +a.managers{ color: #000000; } .discret, -a.grey{ +a.grey{ color:#666; } -a.grey:hover{ +a.grey:hover{ color:#000; } -.red{ +.red{ color : #ff7700; } -div#schema_security{ +div#schema_security{ width:100%; } /******************************************************************************/ diff -r 673b63953e7a -r e2476d78b060 web/views/cwuser.py --- a/web/views/cwuser.py Thu Mar 25 08:30:53 2010 -0700 +++ b/web/views/cwuser.py Tue Apr 06 12:23:05 2010 +0200 @@ -75,8 +75,8 @@ class CWGroupInContextView(EntityView): __regid__ = 'incontext' __select__ = implements('CWGroup') + def cell_call(self, row, col): - self._cw.add_css('cubicweb.acl.css') entity = self.cw_rset.complete_entity(row, col) self.w(u'%s' % ( entity.absolute_url(), entity.name, entity.printable_value('name'))) diff -r 673b63953e7a -r e2476d78b060 web/views/iprogress.py --- a/web/views/iprogress.py Thu Mar 25 08:30:53 2010 -0700 +++ b/web/views/iprogress.py Tue Apr 06 12:23:05 2010 +0200 @@ -17,9 +17,9 @@ from cubicweb.interfaces import IProgress, IMileStone from cubicweb.schema import display_name from cubicweb.view import EntityView - +from cubicweb.web.views.tableview import EntityAttributesTableView -class ProgressTableView(EntityView): +class ProgressTableView(EntityAttributesTableView): """The progress table view is able to display progress information of any object implement IMileStone. @@ -39,26 +39,13 @@ __regid__ = 'progress_table_view' title = _('task progression') __select__ = implements(IMileStone) + table_css = "progress" + css_files = ('cubicweb.iprogress.css',) # default columns of the table columns = (_('project'), _('milestone'), _('state'), _('eta_date'), _('cost'), _('progress'), _('todo_by')) - - def call(self, columns=None): - """displays all versions in a table""" - self._cw.add_css('cubicweb.iprogress.css') - _ = self._cw._ - self.columns = columns or self.columns - ecls = self._cw.vreg['etypes'].etype_class(self.cw_rset.description[0][0]) - self.w(u'') - self.table_header(ecls) - self.w(u'') - for row in xrange(self.cw_rset.rowcount): - self.cell_call(row=row, col=0) - self.w(u'') - self.w(u'
') - def cell_call(self, row, col): _ = self._cw._ entity = self.cw_rset.get_entity(row, col) @@ -91,20 +78,6 @@ """use entity's type as label""" return display_name(self._cw, ecls.__regid__) - def table_header(self, ecls): - """builds the table's header""" - self.w(u'') - _ = self._cw._ - for column in self.columns: - meth = getattr(self, 'header_for_%s' % column, None) - if meth: - colname = meth(ecls) - else: - colname = _(column) - self.w(u'%s' % xml_escape(colname)) - self.w(u'\n') - - ## cell management ######################################################## def build_project_cell(self, entity): """``project`` column cell renderer""" diff -r 673b63953e7a -r e2476d78b060 web/views/management.py --- a/web/views/management.py Thu Mar 25 08:30:53 2010 -0700 +++ b/web/views/management.py Tue Apr 06 12:23:05 2010 +0200 @@ -16,45 +16,14 @@ from cubicweb.uilib import html_traceback, rest_traceback from cubicweb.web import formwidgets as wdgs from cubicweb.web.formfields import guess_field +from cubicweb.web.views.schema import SecurityViewMixIn from yams.buildobjs import EntityType SUBMIT_MSGID = _('Submit bug report') MAIL_SUBMIT_MSGID = _('Submit bug report by mail') - -class SecurityViewMixIn(object): - """display security information for a given schema """ - - def schema_definition(self, eschema, link=True, access_types=None): - w = self.w - _ = self._cw._ - if not access_types: - access_types = eschema.ACTIONS - w(u'') - w(u'' % ( - _("permission"), _('granted to groups'), _('rql expressions'))) - for access_type in access_types: - w(u'') - w(u'' % self._cw.__('%s_perm' % access_type)) - groups = eschema.get_groups(access_type) - l = [] - groups = [(_(group), group) for group in groups] - for trad, group in sorted(groups): - if link: - # XXX we should get a group entity and call its absolute_url - # method - l.append(u'%s
' % ( - self._cw.build_url('cwgroup/%s' % group), group, trad)) - else: - l.append(u'
%s
' % (group, trad)) - w(u'' % u''.join(l)) - rqlexprs = eschema.get_rqlexprs(access_type) - w(u'' % u'

'.join(expr.expression for expr in rqlexprs)) - w(u'\n') - w(u'
%s%s%s
%s%s%s
') - -class SecurityManagementView(EntityView, SecurityViewMixIn): +class SecurityManagementView(SecurityViewMixIn, EntityView): """display security information for a given entity""" __regid__ = 'security' __select__ = EntityView.__select__ & authenticated_user() @@ -77,7 +46,7 @@ xml_escape(entity.dc_title()))) # first show permissions defined by the schema self.w('

%s

' % _('schema\'s permissions definitions')) - self.schema_definition(entity.e_schema) + self.permissions_table(entity.e_schema) self.w('

%s

' % _('manage security')) # ownership information if self._cw.vreg.schema.rschema('owned_by').has_perm(self._cw, 'add', diff -r 673b63953e7a -r e2476d78b060 web/views/schema.py --- a/web/views/schema.py Thu Mar 25 08:30:53 2010 -0700 +++ b/web/views/schema.py Tue Apr 06 12:23:05 2010 +0200 @@ -15,7 +15,7 @@ from yams.buildobjs import DEFAULT_ATTRPERMS from cubicweb.selectors import (implements, yes, match_user_groups, - has_related_entities, anonymous_user) + has_related_entities, authenticated_user) from cubicweb.schema import (META_RTYPES, SCHEMA_TYPES, SYSTEM_RTYPES, WORKFLOW_TYPES, INTERNAL_TYPES) from cubicweb.schemaviewer import SchemaViewer @@ -23,7 +23,7 @@ from cubicweb import tags, uilib from cubicweb.web import action, facet, uicfg from cubicweb.web.views import TmpFileViewMixin -from cubicweb.web.views import primary, baseviews, tabs, management, tableview +from cubicweb.web.views import primary, baseviews, tabs, tableview, iprogress ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES SKIP_TYPES = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES @@ -40,23 +40,91 @@ _pvs.tag_subject_of(('*', '%s_permission' % _action, '*'), 'hidden') _pvs.tag_object_of(('*', '%s_permission' % _action, '*'), 'hidden') +_pvs.tag_object_of(('Workflow', 'workflow_of', 'CWEType'), 'hidden') +_pvs.tag_subject_of(('CWEType', 'default_workflow', 'Workflow'), 'hidden') + +_pvs.tag_object_of(('*', 'relation_type', 'CWRType'), 'hidden') + + +class SecurityViewMixIn(object): + """mixin providing methods to display security information for a entity, + relation or relation definition schema + """ + + def permissions_table(self, erschema, permissions=None): + self._cw.add_css('cubicweb.acl.css') + w = self.w + _ = self._cw._ + w(u'') + w(u'' % ( + _("permission"), _('granted to groups'), _('rql expressions'))) + w(u'
%s%s%s
') + w(u'\n' % + (_('permission'), _('granted to groups'), + _('rql expressions'))) + for action in erschema.ACTIONS: + w(u'\n') + w(u'
%s%s%s
%s' % _(action)) + if permissions is None: + groups = erschema.get_groups(action) + else: + groups = permissions[action][1] + # XXX get group entity and call it's incontext view + groups = [u'%s' % ( + group, self._cw.build_url('cwgroup/%s' % group), label) + for group, label in sorted((_(g), g) for group in groups)] + w(u'
'.join(groups)) + w(u'
') + if permissions is None: + rqlexprs = sorted(e.expression for e in erschema.get_rqlexprs(action)) + else: + rqlexprs = permissions[action][1] + w(u'
'.join(rqlexprs)) + w(u'
') + + def grouped_permissions_table(self, rschema): + # group relation definitions with identical permissions + perms = {} + for rdef in rschema.rdefs.itervalues(): + rdef_perms = [] + for action in ('read', 'add', 'delete'): + groups = sorted(rdef.get_groups(action)) + exprs = sorted(e.expression for e in rdef.get_rqlexprs(action)) + rdef_perms.append( (action, (tuple(groups), tuple(exprs))) ) + rdef_perms = tuple(rdef_perms) + if rdef_perms in perms: + perms[rdef_perms].append( (rdef.subject, rdef.object) ) + else: + perms[rdef_perms] = [(rdef.subject, rdef.object)] + # set layout permissions in a table for each group of relation + # definition + w = self.w + w(u'
') + tmpl = u'[%s %s %s]' + for perm, rdefs in perms: + w(u'
%s
' % u', '.join( + tmpl % (_(s.type), _(rschema.type), _(o.type)) for s, o in rdefs)) + # accessing rdef from previous loop by design: only used to get + # ACTIONS + self.permissions_table(rdef, dict(perm)) + w(u'
') + + # global schema view ########################################################### class SchemaView(tabs.TabsMixin, StartupView): __regid__ = 'schema' title = _('instance schema') - tabs = [_('schema-text'), _('schema-image'), _('schema-security')] - default_tab = 'schema-text' + tabs = [_('schema-description'), _('schema-image'), _('schema-security')] + default_tab = 'schema-description' def call(self): """display schema information""" - self._cw.add_js('cubicweb.ajax.js') - self._cw.add_css(('cubicweb.schema.css','cubicweb.acl.css')) self.w(u'

%s

' % _('Schema of the data model')) self.render_tabs(self.tabs, self.default_tab) -class SchemaTabImageView(StartupView): +class SchemaImageTab(StartupView): __regid__ = 'schema-image' def call(self): @@ -69,8 +137,8 @@ self._cw._("graphical representation of the instance'schema"))) -class SchemaTabTextView(StartupView): - __regid__ = 'schema-text' +class SchemaDescriptionTab(StartupView): + __regid__ = 'schema-description' def call(self): rset = self._cw.execute('Any X ORDERBY N WHERE X is CWEType, X name N, ' @@ -84,7 +152,7 @@ (owl_downloadurl, self._cw._(u'Download schema as OWL'))) -class SchemaPermissionsView(StartupView, management.SecurityViewMixIn): +class SchemaPermissionsTab(SecurityViewMixIn, StartupView): __regid__ = 'schema-security' __select__ = StartupView.__select__ & match_user_groups('managers') @@ -127,16 +195,19 @@ self.w(u'') def has_non_default_perms(self, rdef): - for access_type in rdef.ACTIONS: + """return true if the given *attribute* relation definition has custom + permission + """ + for action in rdef.ACTIONS: def_rqlexprs = [] def_groups = [] - for perm in DEFAULT_ATTRPERMS[access_type]: + for perm in DEFAULT_ATTRPERMS[action]: if not isinstance(perm, basestring): def_rqlexprs.append(perm.expression) else: def_groups.append(perm) - rqlexprs = [rql.expression for rql in rdef.get_rqlexprs(access_type)] - groups = rdef.get_groups(access_type) + rqlexprs = [rql.expression for rql in rdef.get_rqlexprs(action)] + groups = rdef.get_groups(action) if groups != frozenset(def_groups) or \ frozenset(rqlexprs) != frozenset(def_rqlexprs): return True @@ -154,7 +225,7 @@ url, self._cw.external_resource('UP_ICON'), _('up'))) self.w(u'') self.w(u'
') - self.schema_definition(eschema) + self.permissions_table(eschema) # display entity attributes only if they have some permissions modified modified_attrs = [] for attr, etype in eschema.attribute_definitions(): @@ -168,7 +239,7 @@ for rdef in modified_attrs: attrtype = str(rdef.rtype) self.w(u'

%s (%s)

' % (attrtype, _(attrtype))) - self.schema_definition(rdef) + self.permissions_table(rdef) self.w(u'
') def display_relations(self, relations): @@ -182,105 +253,23 @@ self.w(u'%s' % ( url, self._cw.external_resource('UP_ICON'), _('up'))) self.w(u'') - self.w(u'
') - for rdef in rschema.rdefs.itervalues(): - self.w(u'

%s %s %s

' % ( - rdef.subject, rschema, rdef.object)) - self.schema_definition(rdef) - self.w(u'
') - - -# CWAttribute / CWRelation ##################################################### - -class CWRDEFPrimaryView(primary.PrimaryView): - __select__ = implements('CWAttribute', 'CWRelation') - cache_max_age = 60*60*2 # stawy in http cache for 2 hours by default - - def render_entity_title(self, entity): - self.w(u'

%s %s

' - % (entity.dc_type().capitalize(), - xml_escape(entity.dc_long_title()))) - - -class CWAttributeConstraints(EntityView): - __regid__ = 'attr_constraints' - __select__ = implements('CWAttribute') - - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - rschema = self._cw.vreg.schema.rschema(entity.rtype.name) - rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)] - constraints = [xml_escape(str(c)) for c in getattr(rdef, 'constraints')] - self.w(u', '.join(constraints)) - + self.grouped_permissions_table(rschema) -class CWAttributeCellView(tableview.CellView): - """display attribute name only in a cell view, link to - cwattribute primary view""" - __select__ = tableview.CellView.__select__ & implements('CWAttribute') - - def cell_call(self, row, col, cellvid=None): - """display attribute name only in a cell view, link to - cwattribute primary view""" - etype, val = self.cw_rset.description[row][col], self.cw_rset[row][col] - if val is not None and not self._cw.vreg.schema.eschema(etype).final: - e = self.cw_rset.get_entity(row, col) - if cellvid is not None and cellvid != 'incontext': - self.wview(cellvid, e.as_rset(), 'null') - else: - desc = uilib.cut(e.dc_description(), 50) - self.w(u'%s' % - (xml_escape(e.absolute_url()) ,xml_escape(desc), - self.cell_content(e))) - self.w(u'') - elif val is None: - # This is usually caused by a left outer join and in that case, - # regular views will most certainly fail if they don't have - # a real eid - self.wview('final', self.cw_rset, row=row, col=col) - else: - self.wview(cellvid or 'final', self.cw_rset, 'null', row=row, col=col) - - def cell_content(self, entity): - return entity.relation_type[0].name - - -class CWRelationCellView(CWAttributeCellView): - """display relation name and its translation only in a cell view, link to - cwrelation primary view""" - __select__ = tableview.CellView.__select__ & implements('CWRelation') - - def cell_content(self, entity): - return u'%s (%s)' % (entity.relation_type[0].name, - self._cw._(entity.relation_type[0].name)) # CWEType ###################################################################### -class CWETypeOneLineView(baseviews.OneLineView): - __select__ = implements('CWEType') - - def cell_call(self, row, col, **kwargs): - entity = self.cw_rset.get_entity(row, col) - final = entity.final - if final: - self.w(u'') - super(CWETypeOneLineView, self).cell_call(row, col, **kwargs) - if final: - self.w(u'') - +# register msgid generated in entity relations tables +_('i18ncard_1'), _('i18ncard_?'), _('i18ncard_+'), _('i18ncard_*') class CWETypePrimaryView(tabs.TabbedPrimaryView): __select__ = implements('CWEType') - tabs = [_('cwetype-text-tab'), _('cwetype-box-tab'), _('cwetype-workflow-tab'), - _('cwetype-views-tab'), _('cwetype-perm-tab')] - default_tab = 'cwetype-text-tab' + tabs = [_('cwetype-description'), _('cwetype-box'), _('cwetype-workflow'), + _('cwetype-views'), _('cwetype-permissions')] + default_tab = 'cwetype-description' -# register generated msgid -_('i18ncard_1'), _('i18ncard_?'), _('i18ncard_+'), _('i18ncard_*') - -class CWETypeTextTab(tabs.PrimaryTab): - __regid__ = 'cwetype-text-tab' +class CWETypeDescriptionTab(tabs.PrimaryTab): + __regid__ = 'cwetype-description' __select__ = tabs.PrimaryTab.__select__ & implements('CWEType') def render_entity_attributes(self, entity, siderelations=None): @@ -292,17 +281,17 @@ xml_escape(self._cw._('graphical schema for %s') % entity.name))) # entity schema attributes self.w(u'

%s

' % _('Attributes')) - rset = self._cw.execute('Any A,F,DE,D,C, I,J,A ' - 'ORDERBY AA WHERE A is CWAttribute, ' - 'A ordernum AA, A defaultval D, ' - 'A description DE, A cardinality C, ' - 'A fulltextindexed I, A internationalizable J, ' - 'A relation_type R, R name N, ' - 'A to_entity O, O name F, ' - 'A from_entity S, S eid %(x)s', - {'x': entity.eid}) + rset = self._cw.execute( + 'Any A,F,DE,D,C, I,J,A ORDERBY AA WHERE A is CWAttribute, ' + 'A ordernum AA, A defaultval D, A description DE, A cardinality C, ' + 'A fulltextindexed I, A internationalizable J, ' + 'A relation_type R, R name N, A to_entity O, O name F, ' + 'A from_entity S, S eid %(x)s', + {'x': entity.eid}) self.wview('table', rset, 'null', - cellvids={4: 'attr_cardinality', 7: 'attr_constraints'}, + cellvids={0: 'rdef-name-cell', + 4: 'etype-attr-cardinality-cell', + 7: 'rdef-constraints-cell'}, headers=(_(u'name'), _(u'type'), _(u'description'), _(u'default value'), _(u'required'), _(u'fulltext indexed'), _(u'internationalizable'), @@ -311,7 +300,7 @@ # entity schema relations self.w(u'

%s

' % _('Relations')) rset = self._cw.execute( - 'Any A, TT, "i18ncard_"+SUBSTRING(C, 1, 1),K,D,A,RN,TTN ORDERBY RN ' + 'Any A, TT, "i18ncard_"+SUBSTRING(C, 1, 1),K,D,A,A,RN,TTN ORDERBY RN ' 'WHERE A is CWRelation, A description D, A composite K, ' 'A relation_type R, R name RN, A to_entity TT, TT name TTN, ' 'A cardinality C, A from_entity S, S eid %(x)s', @@ -319,14 +308,16 @@ if rset: self.w(u'
%s %s
' % (entity.name, _('is subject of:'))) self.wview('table', rset, 'null', - cellvids={2: 'entity_relation_cardinality',}, + cellvids={0: 'rdef-name-cell', + 2: 'etype-rel-cardinality-cell', + 5: 'rdef-constraints-cell'}, headers=(_(u'name'), _(u'object type'), _(u'cardinality'), _(u'composite'), _(u'description'), - _(u'relation direction')), + _(u'constraints'), _(u'relation direction')), displaycols=range(5), mainindex=0) self.w(u'
') rset = self._cw.execute( - 'Any A, TT, "i18ncard_"+SUBSTRING(C, 2, 1),K,D,A,RN,TTN ORDERBY RN ' + 'Any A, TT, "i18ncard_"+SUBSTRING(C, 2, 1),K,D,A,A,RN,TTN ORDERBY RN ' 'WHERE A is CWRelation, A description D, A composite K, ' 'A relation_type R, R name RN, A from_entity TT, TT name TTN, ' 'A cardinality C, A to_entity O, O eid %(x)s', @@ -334,42 +325,67 @@ if rset: self.w(u'
%s %s
' % (entity.name, _('is object of:'))) self.wview('table', rset, 'null', - cellvids={2: 'entity_relation_cardinality',}, + cellvids={0: 'rdef-object-name-cell', + 2: 'etype-rel-cardinality-cell', + 5: 'rdef-constraints-cell'}, headers=(_(u'name'), _(u'subject type'), _(u'cardinality'), _(u'composite'), _(u'description'), - _(u'relation direction')), + _(u'constraints'), _(u'relation direction')), displaycols=range(5), mainindex=0) -class CWETypePermTab(EntityView, management.SecurityViewMixIn): - __regid__ = 'cwetype-perm-tab' - __select__ = EntityView.__select__ & implements('CWEType') & ~anonymous_user() +class CWETypeAttributeCardinalityCell(baseviews.FinalView): + __regid__ = 'etype-attr-cardinality-cell' + + def cell_call(self, row, col): + if self.cw_rset.rows[row][col][0] == '1': + self.w(self._cw._(u'required')) + + +class CWETypeRelationCardinalityCell(baseviews.FinalView): + __regid__ = 'etype-rel-cardinality-cell' + + def cell_call(self, row, col): + self.w(self._cw._(self.cw_rset.rows[row][col])) + + +class CWETypeBoxTab(EntityView): + __regid__ = 'cwetype-box' + __select__ = implements('CWEType') + + def cell_call(self, row, col): + viewer = SchemaViewer(self._cw) + entity = self.cw_rset.get_entity(row, col) + eschema = self._cw.vreg.schema.eschema(entity.name) + layout = viewer.visit_entityschema(eschema) + self.w(uilib.ureport_as_html(layout)) + self.w(u'
') + + +class CWETypePermTab(SecurityViewMixIn, EntityView): + __regid__ = 'cwetype-permissions' + __select__ = implements('CWEType') & authenticated_user() def cell_call(self, row, col): self._cw.add_css('cubicweb.acl.css') entity = self.cw_rset.get_entity(row, col) eschema = self._cw.vreg.schema.eschema(entity.name) - self.w(u'' % (eschema.type, eschema.type)) - self.w(u'

%s (%s) ' % (eschema.type, _(eschema.type))) - self.w(u'

') self.w(u'
') - self.schema_definition(eschema) - # display entity attributes only if they have some permissions modified - modified_attrs = [] + self.permissions_table(eschema) self.w(u'

%s

' % _('attributes permissions:').capitalize()) for attr, etype in eschema.attribute_definitions(): if attr not in META_RTYPES: rdef = eschema.rdef(attr) attrtype = str(rdef.rtype) self.w(u'

%s (%s)

' % (attrtype, _(attrtype))) - self.schema_definition(rdef, link=False) + self.permissions_table(rdef) self.w(u'
') class CWETypeWorkflowTab(EntityView): - __regid__ = 'cwetype-workflow-tab' - __select__ = (EntityView.__select__ & implements('CWEType') & - has_related_entities('workflow_of', 'object')) + __regid__ = 'cwetype-workflow' + __select__ = (implements('CWEType') + & has_related_entities('workflow_of', 'object')) def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) @@ -396,21 +412,8 @@ wf.absolute_url(), self._cw._('more info about this workflow'))) -class CWETypeBoxTab(EntityView): - __regid__ = 'cwetype-box-tab' - __select__ = EntityView.__select__ & implements('CWEType') - - def cell_call(self, row, col): - viewer = SchemaViewer(self._cw) - entity = self.cw_rset.get_entity(row, col) - eschema = self._cw.vreg.schema.eschema(entity.name) - layout = viewer.visit_entityschema(eschema) - self.w(uilib.ureport_as_html(layout)) - self.w(u'
') - - class CWETypeViewsTab(EntityView): - __regid__ = 'cwetype-views-tab' + __regid__ = 'cwetype-views' __select__ = EntityView.__select__ & implements('CWEType') def cell_call(self, row, col): @@ -427,23 +430,117 @@ if v.category != 'startupview'] +class CWETypeOneLineView(baseviews.OneLineView): + __select__ = implements('CWEType') + + def cell_call(self, row, col, **kwargs): + entity = self.cw_rset.get_entity(row, col) + if entity.final: + self.w(u'') + super(CWETypeOneLineView, self).cell_call(row, col, **kwargs) + if entity.final: + self.w(u'') + + # CWRType ###################################################################### -class CWRTypeSchemaView(primary.PrimaryView): +class CWRTypePrimaryView(tabs.TabbedPrimaryView): __select__ = implements('CWRType') - title = _('in memory relation schema') - main_related_section = False + tabs = [_('cwrtype-description'), _('cwrtype-permissions')] + default_tab = 'cwrtype-description' + - def render_entity_attributes(self, entity): - super(CWRTypeSchemaView, self).render_entity_attributes(entity) +class CWRTypeDescriptionTab(tabs.PrimaryTab): + __regid__ = 'cwrtype-description' + __select__ = implements('CWRType') + + def render_entity_attributes(self, entity, siderelations=None): + self.w(u'
%s
' % xml_escape(entity.description or u'')) rschema = self._cw.vreg.schema.rschema(entity.name) - viewer = SchemaViewer(self._cw) - layout = viewer.visit_relationschema(rschema, title=False) - self.w(uilib.ureport_as_html(layout)) if not rschema.final: msg = self._cw._('graphical schema for %s') % entity.name self.w(tags.img(src=entity.absolute_url(vid='schemagraph'), alt=msg)) + rset = self._cw.execute('Any R,ST,OT,C,CC,R WHERE R is CWRelation, ' + 'R relation_type RT, RT eid %(x)s, ' + 'R from_type ST, R to_type OT, ' + 'R cardinality C, R composite CC', + {'x': entity.eid}) + self.wview('table', rset, 'null', + headers=(_(u'relation'), _(u'subject'), _(u'object'), + _(u'cardinality'), _(u'composite'), + _(u'constraints')), + cellvids={5: 'rdef-constraints-cell'}) + + +class CWRTypePermTab(SecurityViewMixIn, EntityView): + __regid__ = 'cwrtype-permissions' + __select__ = implements('CWRType') & authenticated_user() + + def cell_call(self, row, col): + self._cw.add_css('cubicweb.acl.css') + entity = self.cw_rset.get_entity(row, col) + rschema = self._cw.vreg.schema.rschema(entity.name) + self.grouped_permissions_table(rschema) + + +# CWAttribute / CWRelation ##################################################### + +class CWRDEFPrimaryView(tabs.TabbedPrimaryView): + __select__ = implements('CWRelation', 'CWAttribute') + tabs = [_('cwrdef-description'), _('cwrdef-permissions')] + default_tab = 'cwrdef-description' + +class CWRDEFDescriptionTab(tabs.PrimaryTab): + __regid__ = 'cwrdef-description' + __select__ = implements('CWRelation', 'CWAttribute') + +class CWRDEFPermTab(SecurityViewMixIn, EntityView): + __regid__ = 'cwrdef-permissions' + __select__ = implements('CWRelation', 'CWAttribute') & authenticated_user() + + def cell_call(self, row, col): + entity = self.cw_rset.get_entity(row, col) + rschema = self._cw.vreg.schema.rschema(entity.rtype.name) + rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)] + self.display_permission(rdef) + + +class CWRDEFNameView(tableview.CellView): + """display relation name and its translation only in a cell view, link to + relation definition's primary view (for use in entity type relations table + for instance) + """ + __regid__ = 'rdef-name-cell' + __select__ = implements('CWRelation', 'CWAttribute') + + def cell_content(self, entity): + rtype = entity.relation_type[0].name + # XXX use contect entity + pgettext + return u'%s (%s)' % (rtype, self._cw._(rtype)) + +class CWRDEFObjectNameView(tableview.CellView): + """same as CWRDEFNameView but when the context is the object entity + """ + __regid__ = 'rdef-object-name-cell' + __select__ = implements('CWRelation', 'CWAttribute') + + def cell_content(self, entity): + rtype = entity.relation_type[0].name + # XXX use contect entity + pgettext + return u'%s (%s)' % (rtype, self._cw.__(rtype + '_object')) + +class CWRDEFConstraintsCell(EntityView): + __regid__ = 'rdef-constraints-cell' + __select__ = implements('CWAttribute', 'CWRelation') + + def cell_call(self, row, col): + entity = self.cw_rset.get_entity(row, col) + rschema = self._cw.vreg.schema.rschema(entity.rtype.name) + rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)] + constraints = [xml_escape(str(c)) for c in getattr(rdef, 'constraints')] + self.w(u', '.join(constraints)) + # schema images ############################################################### @@ -509,25 +606,6 @@ s2d.schema2dot(outputfile=tmpfile, visitor=visitor) -# final views ################################################################# - -class CardinalityRequiredCellView(baseviews.FinalView): - __regid__ = 'attr_cardinality' - - def cell_call(self, row, col): - value = self.cw_rset.rows[row][col] - if value is not None and value[0] == '1': - self.w(self._cw._(u'required')) - -class I18NCardinalityCellView(baseviews.FinalView): - __regid__ = 'entity_relation_cardinality' - - def cell_call(self, row, col): - value = self.cw_rset.rows[row][col] - if value is not None: - self.w(self._cw._(value)) - - # misc: facets, actions ######################################################## class CWFinalFacet(facet.AttributeFacet): diff -r 673b63953e7a -r e2476d78b060 web/views/tableview.py --- a/web/views/tableview.py Thu Mar 25 08:30:53 2010 -0700 +++ b/web/views/tableview.py Tue Apr 06 12:23:05 2010 +0200 @@ -326,3 +326,67 @@ class EditableInitialTableTableView(InitialTableView): __regid__ = 'editable-initialtable' finalview = 'editable-final' + + +class EntityAttributesTableView(EntityView): + """This table displays entity attributes in a table and allow to set a + specific method to help building cell content for each attribute as well as + column header. + + Table will render entity cell by using the appropriate build_COLNAME_cell + methods if defined otherwise cell content will be entity.COLNAME. + + Table will render column header using the method header_for_COLNAME if + defined otherwise COLNAME will be used. + """ + __abstract__ = True + columns = () + table_css = "listing" + css_files = () + + def call(self, columns=None): + if self.css_files: + self._cw.add_css(self.css_files) + _ = self._cw._ + self.columns = columns or self.columns + ecls = self._cw.vreg['etypes'].etype_class(self.cw_rset.description[0][0]) + self.w(u'' % self.table_css) + self.table_header(ecls) + self.w(u'') + for row in xrange(self.cw_rset.rowcount): + self.cell_call(row=row, col=0) + self.w(u'') + self.w(u'
') + + def cell_call(self, row, col): + _ = self._cw._ + entity = self.cw_rset.get_entity(row, col) + infos = {} + for col in self.columns: + meth = getattr(self, 'build_%s_cell' % col, None) + # find the build method or try to find matching attribute + if meth: + content = meth(entity) + else: + content = entity.printable_value(col) + infos[col] = content + self.w(u"""""") + line = u''.join(u'%%(%s)s' % col for col in self.columns) + self.w(line % infos) + self.w(u'\n') + + def table_header(self, ecls): + """builds the table's header""" + self.w(u'') + _ = self._cw._ + for column in self.columns: + meth = getattr(self, 'header_for_%s' % column, None) + if meth: + colname = meth(ecls) + else: + colname = _(column) + self.w(u'%s' % xml_escape(colname)) + self.w(u'\n') + +