--- a/cwconfig.py Tue Apr 28 20:08:16 2009 +0200
+++ b/cwconfig.py Tue Apr 28 20:08:46 2009 +0200
@@ -189,6 +189,14 @@
'help': 'web server root url',
'group': 'main', 'inputlevel': 1,
}),
+ ('use-request-subdomain',
+ {'type' : 'yn',
+ 'default': None,
+ 'help': ('if set, base-url subdomain is replaced by the request\'s '
+ 'host, to help managing sites with several subdomains in a '
+ 'single cubicweb instance'),
+ 'group': 'main', 'inputlevel': 1,
+ }),
('mangle-emails',
{'type' : 'yn',
'default': False,
--- a/etwist/server.py Tue Apr 28 20:08:16 2009 +0200
+++ b/etwist/server.py Tue Apr 28 20:08:46 2009 +0200
@@ -10,6 +10,7 @@
import select
from time import mktime
from datetime import date, timedelta
+from urlparse import urlsplit, urlunsplit
from twisted.application import service, strports
from twisted.internet import reactor, task, threads
@@ -167,6 +168,12 @@
else:
https = False
baseurl = self.base_url
+ if self.config['use-request-subdomain']:
+ scheme, netloc, url, query, fragment = urlsplit(baseurl)
+ if '.' in netloc:
+ netloc = '.'.join(host.split('.')[:1] + netloc.split('.')[1:])
+ baseurl = urlunsplit((scheme, netloc, url, query, fragment))
+ self.warning('base_url is %s for this request', baseurl)
req = CubicWebTwistedRequestAdapter(request, self.appli.vreg, https, baseurl)
if req.authmode == 'http':
# activate realm-based auth
--- a/schemaviewer.py Tue Apr 28 20:08:16 2009 +0200
+++ b/schemaviewer.py Tue Apr 28 20:08:46 2009 +0200
@@ -157,7 +157,7 @@
return layout
_ = self.req._
if self.req.user.matching_groups('managers'):
- layout.append(self.format_acls(eschema, ('read', 'add', 'delete', 'update')))
+ # layout.append(self.format_acls(eschema, ('read', 'add', 'delete', 'update')))
# possible views for this entity type
views = [_(view.title) for view in self.possible_views(etype)]
layout.append(Section(children=(Table(cols=1, rheaders=1,
--- a/server/sources/rql2sql.py Tue Apr 28 20:08:16 2009 +0200
+++ b/server/sources/rql2sql.py Tue Apr 28 20:08:46 2009 +0200
@@ -951,6 +951,8 @@
if rel is not None:
rel._q_needcast = value
return self.keyword_map[value]()
+ if constant.type == 'Boolean':
+ value = self.dbms_helper.boolean_value(value)
if constant.type == 'Substitute':
_id = constant.value
if isinstance(_id, unicode):
--- a/web/data/cubicweb.acl.css Tue Apr 28 20:08:16 2009 +0200
+++ b/web/data/cubicweb.acl.css Tue Apr 28 20:08:46 2009 +0200
@@ -9,19 +9,90 @@
/* security edition form (views/management.py) */
/******************************************************************************/
+h2.schema{
+ background : #ff7700;
+ color: #fff;
+ font-weight: bold;
+ padding : 0.1em 0.3em;
+}
+
+
+h3.schema{
+ font-weight: bold;
+}
+
+h4 a,
+h4 a:link,
+h4 a:visited{
+ color:#000;
+ }
+
table.schemaInfo {
- margin: 1ex 1em;
+ margin: 1em 0em;
text-align: left;
border: 1px solid black;
border-collapse: collapse;
+ width:100%;
}
table.schemaInfo th,
table.schemaInfo td {
- padding: 0em 1em;
- border: 1px solid black;
+ padding: .3em .5em;
+ border: 1px solid grey;
+ width:33%;
+}
+
+
+table.schemaInfo tr th {
+ padding: 0.2em 0px 0.2em 5px;
+ background-image:none;
+ background-color:#dfdfdf;
+}
+
+table.schemaInfo thead tr {
+ border: 1px solid #dfdfdf;
+}
+
+table.schemaInfo td {
+ padding: 3px 10px 3px 5px;
+
}
+.users{
+ color : #00CC33;
+ font-weight: bold }
+
+.guests{
+ color : #ff7700;
+ font-weight: bold;
+}
+
+.staff{
+ color : #0083ab;
+ font-weight: bold;
+}
+
+.owners{
+ color : #8b0000;
+ font-weight: bold;
+}
+
+.discret,
+a.grey{
+ color:#666;
+}
+
+a.grey:hover{
+ color:#000;
+}
+
+.red{
+ color : #ff7700;
+ }
+
+div#schema_security{
+ width:780px;
+ }
/******************************************************************************/
/* user groups edition form (views/euser.py) */
/******************************************************************************/
--- a/web/data/external_resources Tue Apr 28 20:08:16 2009 +0200
+++ b/web/data/external_resources Tue Apr 28 20:08:46 2009 +0200
@@ -52,3 +52,4 @@
DOWNLOAD_ICON = DATADIR/download.gif
UPLOAD_ICON = DATADIR/upload.gif
GMARKER_ICON = DATADIR/gmap_blue_marker.png
+UP_ICON = DATADIR/up.gif
Binary file web/data/up.gif has changed
--- a/web/form.py Tue Apr 28 20:08:16 2009 +0200
+++ b/web/form.py Tue Apr 28 20:08:46 2009 +0200
@@ -30,28 +30,6 @@
http_cache_manager = NoHTTPCacheManager
add_to_breadcrumbs = False
- def __init__(self, req, rset, **kwargs):
- super(FormViewMixIn, self).__init__(req, rset, **kwargs)
- # get validation session data which may have been previously set.
- # deleting validation errors here breaks form reloading (errors are
- # no more available), they have to be deleted by application's publish
- # method on successful commit
- formurl = req.url()
- forminfo = req.get_session_data(formurl)
- if forminfo:
- req.data['formvalues'] = forminfo['values']
- req.data['formerrors'] = errex = forminfo['errors']
- req.data['displayederrors'] = set()
- # if some validation error occured on entity creation, we have to
- # get the original variable name from its attributed eid
- foreid = errex.entity
- for var, eid in forminfo['eidmap'].items():
- if foreid == eid:
- errex.eid = var
- break
- else:
- errex.eid = foreid
-
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -80,22 +58,13 @@
self.req.set_page_data('rql_varmaker', varmaker)
self.varmaker = varmaker
- # XXX deprecated with new form system. Should disappear
-
- domid = 'entityForm'
- category = 'form'
- controller = 'edit'
- http_cache_manager = NoHTTPCacheManager
- add_to_breadcrumbs = False
-
def __init__(self, req, rset, **kwargs):
super(FormMixIn, self).__init__(req, rset, **kwargs)
# get validation session data which may have been previously set.
# deleting validation errors here breaks form reloading (errors are
# no more available), they have to be deleted by application's publish
# method on successful commit
- formurl = req.url()
- forminfo = req.get_session_data(formurl)
+ forminfo = req.get_session_data(req.url())
if forminfo:
req.data['formvalues'] = forminfo['values']
req.data['formerrors'] = errex = forminfo['errors']
@@ -110,6 +79,14 @@
else:
errex.eid = foreid
+ # XXX deprecated with new form system. Should disappear
+
+ domid = 'entityForm'
+ category = 'form'
+ controller = 'edit'
+ http_cache_manager = NoHTTPCacheManager
+ add_to_breadcrumbs = False
+
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -371,10 +348,11 @@
values found in 1. and 2. are expected te be already some 'display'
value while those found in 3. and 4. are expected to be correctly typed.
"""
- if field.name in self._previous_values:
- value = self._previous_values[field.name]
- elif field.name in self.req.form:
- value = self.req.form[field.name]
+ qname = self.form_field_name(field)
+ if qname in self._previous_values:
+ value = self._previous_values[qname]
+ elif qname in self.req.form:
+ value = self.req.form[qname]
else:
if field.name in rendervalues:
value = rendervalues[field.name]
@@ -449,6 +427,9 @@
self.form_add_hidden('__linkto', linkto)
msg = '%s %s' % (msg, self.req._('and linked'))
self.form_add_hidden('__message', msg)
+ # in case of direct instanciation
+ self.schema = self.edited_entity.schema
+ self.vreg = self.edited_entity.vreg
def _errex_match_field(self, errex, field):
"""return true if the field has some error in given validation exception
--- a/web/views/cwuser.py Tue Apr 28 20:08:16 2009 +0200
+++ b/web/views/cwuser.py Tue Apr 28 20:08:46 2009 +0200
@@ -57,10 +57,11 @@
return entity.name()
def is_side_related(self, rschema, eschema):
+ # XXX only bookmarked_by defined in cw...
return rschema.type in ['interested_in', 'tags',
- 'todo_by', 'bookmarked_by',
+ 'todo_by', 'bookmarked_by']
- ]
+
class FoafView(EntityView):
id = 'foaf'
__select__ = implements('CWUser')
--- a/web/views/management.py Tue Apr 28 20:08:16 2009 +0200
+++ b/web/views/management.py Tue Apr 28 20:08:46 2009 +0200
@@ -22,8 +22,47 @@
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.req._
+ if not access_types:
+ access_types = eschema.ACTIONS
+ w(u'<table class="schemaInfo">')
+ w(u'<tr><th>%s</th><th>%s</th><th>%s</th></tr>' % (
+ _("permission"), _('granted to groups'), _('rql expressions')))
+ for access_type in access_types:
+ w(u'<tr>')
+ w(u'<td>%s</td>' % _('%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:
+ l.append(u'<a href="%s" class="%s">%s</a><br/>' % (
+ self.build_url('egroup/%s' % group), group, trad))
+ else:
+ l.append(u'<div class="%s">%s</div>' % (group, trad))
+ w(u'<td>%s</td>' % u''.join(l))
+ rqlexprs = eschema.get_rqlexprs(access_type)
+ w(u'<td>%s</td>' % u'<br/><br/>'.join(expr.expression for expr in rqlexprs))
+ w(u'</tr>\n')
+ w(u'</table>')
-class SecurityManagementView(EntityView):
+ def has_schema_modified_permissions(self, eschema, access_types):
+ """ return True if eschema's actual permissions are diffrents
+ from the default ones
+ """
+ for access_type in access_types:
+ if eschema.get_rqlexprs(access_type):
+ return True
+ if eschema.get_groups(access_type) != \
+ frozenset(eschema.get_default_groups()[access_type]):
+ return True
+ return False
+
+class SecurityManagementView(EntityView, SecurityViewMixIn):
"""display security information for a given entity"""
id = 'security'
title = _('security')
@@ -40,7 +79,7 @@
html_escape(entity.dc_title())))
# first show permissions defined by the schema
self.w('<h2>%s</h2>' % _('schema\'s permissions definitions'))
- self.schema_definition(entity)
+ self.schema_definition(entity.e_schema)
self.w('<h2>%s</h2>' % _('manage security'))
# ownership information
if self.schema.rschema('owned_by').has_perm(self.req, 'add',
@@ -48,7 +87,7 @@
self.owned_by_edit_form(entity)
else:
self.owned_by_information(entity)
- # epermissions
+ # cwpermissions
if 'require_permission' in entity.e_schema.subject_relations():
w('<h3>%s</h3>' % _('permissions for this entity'))
reqpermschema = self.schema.rschema('require_permission')
@@ -56,26 +95,6 @@
if reqpermschema.has_perm(self.req, 'add', fromeid=entity.eid):
self.require_permission_edit_form(entity)
- def schema_definition(self, entity):
- w = self.w
- _ = self.req._
- w(u'<table class="schemaInfo">')
- w(u'<tr><th>%s</th><th>%s</th><th>%s</th></tr>' % (
- _("access type"), _('granted to groups'), _('rql expressions')))
- for access_type in ('read', 'add', 'update', 'delete'):
- w(u'<tr>')
- w(u'<th>%s</th>' % self.req.__('%s_permission' % access_type))
- groups = entity.e_schema.get_groups(access_type)
- l = []
- for group in groups:
- l.append(u'<a href="%s">%s</a>' % (
- self.build_url('egroup/%s' % group), _(group)))
- w(u'<td>%s</td>' % u', '.join(l))
- rqlexprs = entity.e_schema.get_rqlexprs(access_type)
- w(u'<td>%s</td>' % u'<br/>'.join(expr.expression for expr in rqlexprs))
- w(u'</tr>\n')
- w(u'</table>')
-
def owned_by_edit_form(self, entity):
self.w('<h3>%s</h3>' % self.req._('ownership'))
msg = self.req._('ownerships have been changed')
@@ -116,18 +135,18 @@
w(u'<table class="schemaInfo">')
w(u'<tr><th>%s</th><th>%s</th></tr>' % (_("permission"),
_('granted to groups')))
- for eperm in entity.require_permission:
+ for cwperm in entity.require_permission:
w(u'<tr>')
if dellinktempl:
- w(u'<td>%s%s</td>' % (dellinktempl % eperm.eid,
- eperm.view('oneline')))
+ w(u'<td>%s%s</td>' % (dellinktempl % cwperm.eid,
+ cwperm.view('oneline')))
else:
- w(u'<td>%s</td>' % eperm.view('oneline'))
- w(u'<td>%s</td>' % self.view('csv', eperm.related('require_group'), 'null'))
+ w(u'<td>%s</td>' % cwperm.view('oneline'))
+ w(u'<td>%s</td>' % self.view('csv', cwperm.related('require_group'), 'null'))
w(u'</tr>\n')
w(u'</table>')
else:
- self.w(self.req._('no associated epermissions'))
+ self.w(self.req._('no associated permissions'))
def require_permission_edit_form(self, entity):
w = self.w
--- a/web/views/primary.py Tue Apr 28 20:08:16 2009 +0200
+++ b/web/views/primary.py Tue Apr 28 20:08:46 2009 +0200
@@ -44,27 +44,41 @@
def render_entity(self, entity):
"""return html to display the given entity"""
- siderelations = []
self.render_entity_title(entity)
self.render_entity_metadata(entity)
# entity's attributes and relations, excluding meta data
# if the entity isn't meta itself
- boxes = self._preinit_side_related(entity, siderelations)
+ boxes = self._preinit_side_related(entity)
if boxes:
self.w(u'<table width="100%"><tr><td width="75%">')
self.w(u'<div>')
self.w(u'<div class="mainInfo">')
- self.render_entity_attributes(entity, siderelations)
+ try:
+ self.render_entity_attributes(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_attributes is '
+ 'deprecated')
+ self.render_entity_attributes(entity, [])
self.w(u'</div>')
self.content_navigation_components('navcontenttop')
if self.main_related_section:
- self.render_entity_relations(entity, siderelations)
+ try:
+ self.render_entity_relations(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_relations is '
+ 'deprecated')
+ self.render_entity_relations(entity, [])
self.w(u'</div>')
if boxes:
self.w(u'</td><td>')
# side boxes
self.w(u'<div class="primaryRight">')
- self.render_side_related(entity, siderelations)
+ try:
+ self.render_side_related(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_relations is '
+ 'deprecated')
+ self.render_entity_relations(entity, [])
self.w(u'</div>')
self.w(u'</td></tr></table>')
self.content_navigation_components('navcontentbottom')
@@ -117,7 +131,7 @@
"""default implementation return an empty string"""
return u''
- def render_entity_attributes(self, entity, siderelations):
+ def render_entity_attributes(self, entity, siderelations=None):
for rschema, targetschema in self.iter_attributes(entity):
attr = rschema.type
if targetschema.type in ('Password', 'Bytes'):
@@ -134,56 +148,51 @@
continue
self._render_related_entities(entity, rschema, value)
- def _preinit_side_related(self, entity, siderelations):
- self._sideboxes = None
- self._related_entities = []
+ def _preinit_side_related(self, entity):
+ self._sideboxes = []
if hasattr(self, 'get_side_boxes_defs'):
- self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
+ self._sideboxes = [(label, rset, 'sidebox') for label, rset in self.get_side_boxes_defs(entity)
if rset]
else:
eschema = entity.e_schema
maxrelated = self.req.property_value('navigation.related-limit')
- for rschema, targetschemas, x in self.iter_relations(entity):
+ for rschema, targetschemas, role in self.iter_relations(entity):
+ if self.is_side_related(rschema, eschema):
+ try:
+ related = entity.related(rschema.type, role, limit=maxrelated+1)
+ except Unauthorized:
+ continue
+ if not related:
+ continue
+ label = display_name(self.req, rschema.type, role)
+ self._sideboxes.append((label, related, 'autolimited'))
+ self._contextboxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ return self._sideboxes or self._contextboxes
+
+ def render_entity_relations(self, entity, siderelations=None):
+ eschema = entity.e_schema
+ for rschema, targetschemas, x in self.iter_relations(entity):
+ if not self.is_side_related(rschema, eschema):
try:
related = entity.related(rschema.type, x, limit=maxrelated+1)
except Unauthorized:
continue
- if not related:
- continue
- if self.is_side_related(rschema, eschema):
- siderelations.append((rschema, related, x))
- continue
- self._related_entities.append((rschema, related, x))
- self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
- row=self.row, view=self,
- context='incontext'))
- return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations
-
- def render_entity_relations(self, entity, siderelations):
- if self._related_entities:
- for rschema, related, x in self._related_entities:
self._render_related_entities(entity, rschema, related, x)
- def render_side_related(self, entity, siderelations):
+ def render_side_related(self, entity, siderelations=None):
"""display side related relations:
non-meta in a first step, meta in a second step
"""
if self._sideboxes:
- for label, rset in self._sideboxes:
+ for label, rset, vid in self._sideboxes:
self.w(u'<div class="sideRelated">')
- self.wview('sidebox', rset, title=label)
+ self.wview(vid, rset, title=label)
self.w(u'</div>')
- elif siderelations:
- self.w(u'<div class="sideRelated">')
- for relatedinfos in siderelations:
- # if not relatedinfos[0].meta:
- # continue
- self._render_related_entities(entity, *relatedinfos)
- self.w(u'</div>')
-
- if self._boxes_in_context:
- for box in self._boxes_in_context:
+ if self._contextboxes:
+ for box in self._contextboxes:
try:
box.dispatch(w=self.w, row=self.row)
except NotImplementedError:
@@ -203,24 +212,31 @@
else:
if not related:
return
- show_label = self.show_rel_label
- # if not too many entities, show them all in a list
- maxrelated = self.req.property_value('navigation.related-limit')
- if related.rowcount <= maxrelated:
- if related.rowcount == 1:
- value = self.view('incontext', related, row=0)
- elif 1 < related.rowcount <= 5:
- value = self.view('csv', related)
- else:
- value = '<div>' + self.view('simplelist', related) + '</div>'
- # else show links to display related entities
- else:
- rql = related.printable_rql()
- related.limit(maxrelated)
- value = '<div>' + self.view('simplelist', related)
- value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
- self.req._('see them all'))
- value += '</div>'
+ value = self.view('autolimited', related)
label = display_name(self.req, rschema.type, role)
self.field(label, value, show_label=show_label, tr=False)
+
+class RelatedView(EntityView):
+ id = 'autolimited'
+ def call(self):
+ # if not too many entities, show them all in a list
+ maxrelated = self.req.property_value('navigation.related-limit')
+ if self.rset.rowcount <= maxrelated:
+ if self.rset.rowcount == 1:
+ self.wview('incontext', self.rset, row=0)
+ elif 1 < self.rset.rowcount <= 5:
+ self.wview('csv', self.rset)
+ else:
+ self.w(u'<div>')
+ self.wview('simplelist', self.rset)
+ self.w(u'</div>')
+ # else show links to display related entities
+ else:
+ rql = self.rset.printable_rql()
+ self.rset.limit(maxself.rset)
+ self.w(u'<div>')
+ self.wview('simplelist', self.rset)
+ self.w(u'[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
+ self.req._('see them all')))
+ self.w(u'</div>')
--- a/web/views/startup.py Tue Apr 28 20:08:16 2009 +0200
+++ b/web/views/startup.py Tue Apr 28 20:08:46 2009 +0200
@@ -10,10 +10,12 @@
from logilab.common.textutils import unormalize
from logilab.mtconverter import html_escape
-from cubicweb.view import StartupView
-from cubicweb.common.uilib import ureport_as_html, ajax_replace_url
+from cubicweb.common.uilib import ureport_as_html, unormalize, ajax_replace_url
+from cubicweb.common.view import StartupView
+from cubicweb.common.selectors import match_user_group
from cubicweb.web.httpcache import EtagHTTPCacheManager
-
+from cubicweb.web.views.management import SecurityViewMixIn
+from copy import deepcopy
_ = unicode
@@ -159,25 +161,135 @@
def call(self):
"""display schema information"""
self.req.add_js('cubicweb.ajax.js')
- self.req.add_css('cubicweb.schema.css')
+ self.req.add_css(('cubicweb.schema.css','cubicweb.acl.css'))
withmeta = int(self.req.form.get('withmeta', 0))
+ section = self.req.form.get('sec', '')
self.w(u'<img src="%s" alt="%s"/>\n' % (
html_escape(self.req.build_url('view', vid='schemagraph', withmeta=withmeta)),
self.req._("graphical representation of the application'schema")))
if withmeta:
self.w(u'<div><a href="%s">%s</a></div>' % (
- self.build_url('schema', withmeta=0),
+ html_escape(self.build_url('schema', withmeta=0, sec=section)),
self.req._('hide meta-data')))
else:
self.w(u'<div><a href="%s">%s</a></div>' % (
- self.build_url('schema', withmeta=1),
+ html_escape(self.build_url('schema', withmeta=1, sec=section)),
self.req._('show meta-data')))
- self.w(u'<div id="detailed_schema"><a href="%s">%s</a></div>' %
+ self.w(u'<a href="%s">%s</a><br/>' %
(html_escape(ajax_replace_url('detailed_schema', '', 'schematext',
skipmeta=int(not withmeta))),
self.req._('detailed schema view')))
+ if self.req.user.matching_groups('managers'):
+ self.w(u'<a href="%s">%s</a>' %
+ (html_escape(ajax_replace_url('detailed_schema', '', 'schema_security',
+ skipmeta=int(not withmeta))),
+ self.req._('security')))
+ self.w(u'<div id="detailed_schema">')
+ if section:
+ self.wview(section, None)
+ self.w(u'</div>')
+
+
+class ManagerSchemaPermissionsView(StartupView, SecurityViewMixIn):
+ id = 'schema_security'
+ require_groups = ('managers',)
+ __selectors__ = StartupView.__selectors__ + (match_user_group,)
+
+ def call(self, display_relations=True,
+ skiprels=('is', 'is_instance_of', 'identity', 'owned_by', 'created_by')):
+ _ = self.req._
+ formparams = {}
+ formparams['sec'] = self.id
+ formparams['withmeta'] = int(self.req.form.get('withmeta', True))
+ schema = self.schema
+ # compute entities
+ entities = [eschema for eschema in schema.entities()
+ if not eschema.is_final()]
+ if not formparams['withmeta']:
+ entities = [eschema for eschema in entities
+ if not eschema.meta]
+ # compute relations
+ relations = []
+ if display_relations:
+ relations = [rschema for rschema in schema.relations()
+ if not (rschema.is_final() or rschema.type in skiprels)]
+ if not formparams['withmeta']:
+ relations = [rschema for rschema in relations
+ if not rschema.meta]
+ # index
+ self.w(u'<div id="schema_security"><a id="index" href="index"/>')
+ self.w(u'<h2 class="schema">%s</h2>' % _('index').capitalize())
+ self.w(u'<h4>%s</h4>' % _('Entities').capitalize())
+ ents = []
+ for eschema in sorted(entities):
+ url = html_escape(self.build_url('schema', **formparams) + '#' + eschema.type)
+ ents.append(u'<a class="grey" href="%s">%s</a> (%s)' % (url, eschema.type, _(eschema.type)))
+ self.w('%s' % ', '.join(ents))
+ self.w(u'<h4>%s</h4>' % (_('relations').capitalize()))
+ rels = []
+ for eschema in sorted(relations):
+ url = html_escape(self.build_url('schema', **formparams) + '#' + eschema.type)
+ rels.append(u'<a class="grey" href="%s">%s</a> (%s), ' % (url , eschema.type, _(eschema.type)))
+ self.w('%s' % ', '.join(ents))
+ # entities
+ self.display_entities(entities, formparams)
+ # relations
+ if relations:
+ self.display_relations(relations, formparams)
+ self.w(u'</div>')
+
+ def display_entities(self, entities, formparams):
+ _ = self.req._
+ self.w(u'<a id="entities" href="entities"/>')
+ self.w(u'<h2 class="schema">%s</h2>' % _('permissions for entities').capitalize())
+ for eschema in sorted(entities):
+ self.w(u'<a id="%s" href="%s"/>' % (eschema.type, eschema.type))
+ self.w(u'<h3 class="schema">%s (%s) ' % (eschema.type, _(eschema.type)))
+ url = html_escape(self.build_url('schema', **formparams) + '#index')
+ self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % (url, self.req.external_resource('UP_ICON'), _('up')))
+ self.w(u'</h3>')
+ self.w(u'<div style="margin: 0px 1.5em">')
+ self.schema_definition(eschema, link=False)
+
+ # display entity attributes only if they have some permissions modified
+ modified_attrs = []
+ for attr, etype in eschema.attribute_definitions():
+ if self.has_schema_modified_permissions(attr, attr.ACTIONS):
+ modified_attrs.append(attr)
+ if modified_attrs:
+ self.w(u'<h4>%s</h4>' % _('attributes with modified permissions:').capitalize())
+ self.w(u'</div>')
+ self.w(u'<div style="margin: 0px 6em">')
+ for attr in modified_attrs:
+ self.w(u'<h4 class="schema">%s (%s)</h4> ' % (attr.type, _(attr.type)))
+ self.schema_definition(attr, link=False)
+ self.w(u'</div>')
+ else:
+ self.w(u'</div>')
+ def display_relations(self, relations, formparams):
+ _ = self.req._
+ self.w(u'<a id="relations" href="relations"/>')
+ self.w(u'<h2 class="schema">%s </h2>' % _('permissions for relations').capitalize())
+ for rschema in sorted(relations):
+ self.w(u'<a id="%s" href="%s"/>' % (rschema.type, rschema.type))
+ self.w(u'<h3 class="schema">%s (%s) ' % (rschema.type, _(rschema.type)))
+ url = html_escape(self.build_url('schema', **formparams) + '#index')
+ self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % (url, self.req.external_resource('UP_ICON'), _('up')))
+ self.w(u'</h3>')
+ self.w(u'<div style="margin: 0px 1.5em">')
+ subjects = [str(subj) for subj in rschema.subjects()]
+ self.w(u'<div><strong>%s</strong> %s (%s)</div>' % (_('subject_plural:'),
+ ', '.join( [str(subj) for subj in rschema.subjects()]),
+ ', '.join( [_(str(subj)) for subj in rschema.subjects()])))
+ self.w(u'<div><strong>%s</strong> %s (%s)</div>' % (_('object_plural:'),
+ ', '.join( [str(obj) for obj in rschema.objects()]),
+ ', '.join( [_(str(obj)) for obj in rschema.objects()])))
+ self.schema_definition(rschema, link=False)
+ self.w(u'</div>')
+
+
class SchemaUreportsView(StartupView):
id = 'schematext'