8 __docformat__ = "restructuredtext en" |
8 __docformat__ = "restructuredtext en" |
9 |
9 |
10 from itertools import cycle |
10 from itertools import cycle |
11 |
11 |
12 from logilab.mtconverter import xml_escape |
12 from logilab.mtconverter import xml_escape |
13 from yams import schema2dot as s2d |
13 from yams import BASE_TYPES, schema2dot as s2d |
14 |
14 |
15 from cubicweb.selectors import implements, yes |
15 from cubicweb.selectors import implements, yes, match_user_groups |
16 from cubicweb.schema import META_RELATIONS_TYPES, SCHEMA_TYPES |
16 from cubicweb.schema import META_RELATIONS_TYPES, SCHEMA_TYPES |
17 from cubicweb.schemaviewer import SchemaViewer |
17 from cubicweb.schemaviewer import SchemaViewer |
18 from cubicweb.view import EntityView, StartupView |
18 from cubicweb.view import EntityView, StartupView |
19 from cubicweb.common import tags, uilib |
19 from cubicweb.common import tags, uilib |
20 from cubicweb.web import action |
20 from cubicweb.web import action, facet |
21 from cubicweb.web.views import TmpFileViewMixin, primary, baseviews, tabs |
21 from cubicweb.web.views import TmpFileViewMixin |
22 from cubicweb.web.facet import AttributeFacet |
22 from cubicweb.web.views import primary, baseviews, tabs, management |
23 |
23 |
24 SKIP_TYPES = set() |
24 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES |
25 SKIP_TYPES.update(META_RELATIONS_TYPES) |
25 SKIP_TYPES = ALWAYS_SKIP_TYPES | META_RELATIONS_TYPES |
26 SKIP_TYPES.update(SCHEMA_TYPES) |
26 SKIP_TYPES.update(set(('Transition', 'State', 'TrInfo', |
|
27 'CWUser', 'CWGroup', |
|
28 'CWCache', 'CWProperty', 'CWPermission', |
|
29 'ExternalUri'))) |
27 |
30 |
28 def skip_types(req): |
31 def skip_types(req): |
29 if int(req.form.get('skipmeta', True)): |
32 if int(req.form.get('skipmeta', True)): |
30 return SKIP_TYPES |
33 return SKIP_TYPES |
31 return () |
34 return ALWAYS_SKIP_TYPES |
32 |
35 |
33 class ViewSchemaAction(action.Action): |
36 # global schema view ########################################################### |
|
37 |
|
38 class SchemaView(tabs.TabsMixin, StartupView): |
34 id = 'schema' |
39 id = 'schema' |
35 __select__ = yes() |
40 title = _('application schema') |
36 |
41 tabs = [_('schema-text'), _('schema-image')] |
37 title = _("site schema") |
42 default_tab = 'schema-text' |
38 category = 'siteactions' |
43 |
39 order = 30 |
44 def call(self): |
40 |
45 """display schema information""" |
41 def url(self): |
46 self.req.add_js('cubicweb.ajax.js') |
42 return self.build_url(self.id) |
47 self.req.add_css(('cubicweb.schema.css','cubicweb.acl.css')) |
43 |
48 self.w(u'<h1>%s</h1>' % _('Schema of the data model')) |
|
49 self.render_tabs(self.tabs, self.default_tab) |
|
50 |
|
51 |
|
52 class SchemaTabImageView(StartupView): |
|
53 id = 'schema-image' |
|
54 |
|
55 def call(self): |
|
56 self.w(_(u'<div>This schema of the data model <em>excludes</em> the ' |
|
57 u'meta-data, but you can also display a <a href="%s">complete ' |
|
58 u'schema with meta-data</a>.</div>') |
|
59 % xml_escape(self.build_url('view', vid='schemagraph', skipmeta=0))) |
|
60 self.w(u'<img src="%s" alt="%s"/>\n' % ( |
|
61 xml_escape(self.req.build_url('view', vid='schemagraph', skipmeta=1)), |
|
62 self.req._("graphical representation of the application'schema"))) |
|
63 |
|
64 |
|
65 class SchemaTabTextView(StartupView): |
|
66 id = 'schema-text' |
|
67 |
|
68 def call(self): |
|
69 rset = self.req.execute('Any X ORDERBY N WHERE X is CWEType, X name N, ' |
|
70 'X final FALSE') |
|
71 self.wview('table', rset, displayfilter=True) |
|
72 |
|
73 |
|
74 class ManagerSchemaPermissionsView(StartupView, management.SecurityViewMixIn): |
|
75 id = 'schema-security' |
|
76 __select__ = StartupView.__select__ & match_user_groups('managers') |
|
77 |
|
78 def call(self, display_relations=True): |
|
79 self.req.add_css('cubicweb.acl.css') |
|
80 skiptypes = skip_types(self.req) |
|
81 formparams = {} |
|
82 formparams['sec'] = self.id |
|
83 if not skiptypes: |
|
84 formparams['skipmeta'] = u'0' |
|
85 schema = self.schema |
|
86 # compute entities |
|
87 entities = sorted(eschema for eschema in schema.entities() |
|
88 if not (eschema.is_final() or eschema in skiptypes)) |
|
89 # compute relations |
|
90 if display_relations: |
|
91 relations = sorted(rschema for rschema in schema.relations() |
|
92 if not (rschema.is_final() |
|
93 or rschema in skiptypes |
|
94 or rschema in META_RELATIONS_TYPES)) |
|
95 else: |
|
96 relations = [] |
|
97 # index |
|
98 _ = self.req._ |
|
99 self.w(u'<div id="schema_security"><a id="index" href="index"/>') |
|
100 self.w(u'<h2 class="schema">%s</h2>' % _('index').capitalize()) |
|
101 self.w(u'<h4>%s</h4>' % _('Entities').capitalize()) |
|
102 ents = [] |
|
103 for eschema in sorted(entities): |
|
104 url = xml_escape(self.build_url('schema', **formparams)) |
|
105 ents.append(u'<a class="grey" href="%s#%s">%s</a> (%s)' % ( |
|
106 url, eschema.type, eschema.type, _(eschema.type))) |
|
107 self.w(u', '.join(ents)) |
|
108 self.w(u'<h4>%s</h4>' % (_('relations').capitalize())) |
|
109 rels = [] |
|
110 for rschema in sorted(relations): |
|
111 url = xml_escape(self.build_url('schema', **formparams)) |
|
112 rels.append(u'<a class="grey" href="%s#%s">%s</a> (%s), ' % ( |
|
113 url , rschema.type, rschema.type, _(rschema.type))) |
|
114 self.w(u', '.join(ents)) |
|
115 # entities |
|
116 self.display_entities(entities, formparams) |
|
117 # relations |
|
118 if relations: |
|
119 self.display_relations(relations, formparams) |
|
120 self.w(u'</div>') |
|
121 |
|
122 def display_entities(self, entities, formparams): |
|
123 _ = self.req._ |
|
124 self.w(u'<a id="entities" href="entities"/>') |
|
125 self.w(u'<h2 class="schema">%s</h2>' % _('permissions for entities').capitalize()) |
|
126 for eschema in entities: |
|
127 self.w(u'<a id="%s" href="%s"/>' % (eschema.type, eschema.type)) |
|
128 self.w(u'<h3 class="schema">%s (%s) ' % (eschema.type, _(eschema.type))) |
|
129 url = xml_escape(self.build_url('schema', **formparams) + '#index') |
|
130 self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % ( |
|
131 url, self.req.external_resource('UP_ICON'), _('up'))) |
|
132 self.w(u'</h3>') |
|
133 self.w(u'<div style="margin: 0px 1.5em">') |
|
134 self.schema_definition(eschema, link=False) |
|
135 # display entity attributes only if they have some permissions modified |
|
136 modified_attrs = [] |
|
137 for attr, etype in eschema.attribute_definitions(): |
|
138 if self.has_schema_modified_permissions(attr, attr.ACTIONS): |
|
139 modified_attrs.append(attr) |
|
140 if modified_attrs: |
|
141 self.w(u'<h4>%s</h4>' % _('attributes with modified permissions:').capitalize()) |
|
142 self.w(u'</div>') |
|
143 self.w(u'<div style="margin: 0px 6em">') |
|
144 for attr in modified_attrs: |
|
145 self.w(u'<h4 class="schema">%s (%s)</h4> ' % (attr.type, _(attr.type))) |
|
146 self.schema_definition(attr, link=False) |
|
147 self.w(u'</div>') |
|
148 |
|
149 def display_relations(self, relations, formparams): |
|
150 _ = self.req._ |
|
151 self.w(u'<a id="relations" href="relations"/>') |
|
152 self.w(u'<h2 class="schema">%s </h2>' % _('permissions for relations').capitalize()) |
|
153 for rschema in relations: |
|
154 self.w(u'<a id="%s" href="%s"/>' % (rschema.type, rschema.type)) |
|
155 self.w(u'<h3 class="schema">%s (%s) ' % (rschema.type, _(rschema.type))) |
|
156 url = xml_escape(self.build_url('schema', **formparams) + '#index') |
|
157 self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % ( |
|
158 url, self.req.external_resource('UP_ICON'), _('up'))) |
|
159 self.w(u'</h3>') |
|
160 self.w(u'<div style="margin: 0px 1.5em">') |
|
161 subjects = [str(subj) for subj in rschema.subjects()] |
|
162 self.w(u'<div><strong>%s</strong> %s (%s)</div>' % ( |
|
163 _('subject_plural:'), |
|
164 ', '.join(str(subj) for subj in rschema.subjects()), |
|
165 ', '.join(_(str(subj)) for subj in rschema.subjects()))) |
|
166 self.w(u'<div><strong>%s</strong> %s (%s)</div>' % ( |
|
167 _('object_plural:'), |
|
168 ', '.join(str(obj) for obj in rschema.objects()), |
|
169 ', '.join(_(str(obj)) for obj in rschema.objects()))) |
|
170 self.schema_definition(rschema, link=False) |
|
171 self.w(u'</div>') |
|
172 |
|
173 |
|
174 class SchemaUreportsView(StartupView): |
|
175 id = 'schema-block' |
|
176 |
|
177 def call(self): |
|
178 viewer = SchemaViewer(self.req) |
|
179 layout = viewer.visit_schema(self.schema, display_relations=True, |
|
180 skiptypes=skip_types(self.req)) |
|
181 self.w(uilib.ureport_as_html(layout)) |
|
182 |
|
183 |
|
184 # CWAttribute / CWRelation ##################################################### |
44 |
185 |
45 class CWRDEFPrimaryView(primary.PrimaryView): |
186 class CWRDEFPrimaryView(primary.PrimaryView): |
46 __select__ = implements('CWAttribute', 'CWRelation') |
187 __select__ = implements('CWAttribute', 'CWRelation') |
47 cache_max_age = 60*60*2 # stay in http cache for 2 hours by default |
188 cache_max_age = 60*60*2 # stay in http cache for 2 hours by default |
48 |
189 |
236 eschema = self.vreg.schema.eschema(entity.name) |
381 eschema = self.vreg.schema.eschema(entity.name) |
237 visitor = OneHopESchemaVisitor(self.req, eschema, |
382 visitor = OneHopESchemaVisitor(self.req, eschema, |
238 skiptypes=skip_types(self.req)) |
383 skiptypes=skip_types(self.req)) |
239 s2d.schema2dot(outputfile=tmpfile, visitor=visitor) |
384 s2d.schema2dot(outputfile=tmpfile, visitor=visitor) |
240 |
385 |
|
386 |
241 class CWRTypeSchemaImageView(CWETypeSchemaImageView): |
387 class CWRTypeSchemaImageView(CWETypeSchemaImageView): |
242 __select__ = implements('CWRType') |
388 __select__ = implements('CWRType') |
243 |
389 |
244 def _generate(self, tmpfile): |
390 def _generate(self, tmpfile): |
245 """display schema information for an entity""" |
391 """display schema information for an entity""" |
246 entity = self.entity(self.row, self.col) |
392 entity = self.entity(self.row, self.col) |
247 rschema = self.vreg.schema.rschema(entity.name) |
393 rschema = self.vreg.schema.rschema(entity.name) |
248 visitor = OneHopRSchemaVisitor(self.req, rschema) |
394 visitor = OneHopRSchemaVisitor(self.req, rschema) |
249 s2d.schema2dot(outputfile=tmpfile, visitor=visitor) |
395 s2d.schema2dot(outputfile=tmpfile, visitor=visitor) |
250 |
396 |
251 ### facets |
397 |
252 |
398 # misc: facets, actions ######################################################## |
253 class CWFinalFacet(AttributeFacet): |
399 |
|
400 class CWFinalFacet(facet.AttributeFacet): |
254 id = 'cwfinal-facet' |
401 id = 'cwfinal-facet' |
255 __select__ = AttributeFacet.__select__ & implements('CWEType', 'CWRType') |
402 __select__ = facet.AttributeFacet.__select__ & implements('CWEType', 'CWRType') |
256 rtype = 'final' |
403 rtype = 'final' |
|
404 |
|
405 class ViewSchemaAction(action.Action): |
|
406 id = 'schema' |
|
407 __select__ = yes() |
|
408 |
|
409 title = _("site schema") |
|
410 category = 'siteactions' |
|
411 order = 30 |
|
412 |
|
413 def url(self): |
|
414 return self.build_url(self.id) |