7 """ |
7 """ |
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.common.ureports import Section, Table |
12 from logilab.mtconverter import xml_escape |
13 from logilab.mtconverter import xml_escape |
13 from yams import BASE_TYPES, schema2dot as s2d |
14 from yams import BASE_TYPES, schema2dot as s2d |
14 from yams.buildobjs import DEFAULT_ATTRPERMS |
15 from yams.buildobjs import DEFAULT_ATTRPERMS |
15 |
16 |
16 from cubicweb.selectors import (implements, yes, match_user_groups, |
17 from cubicweb.selectors import (implements, yes, match_user_groups, |
17 has_related_entities) |
18 has_related_entities, anonymous_user) |
18 from cubicweb.schema import (META_RTYPES, SCHEMA_TYPES, SYSTEM_RTYPES, |
19 from cubicweb.schema import (META_RTYPES, SCHEMA_TYPES, SYSTEM_RTYPES, |
19 WORKFLOW_TYPES, INTERNAL_TYPES) |
20 WORKFLOW_TYPES, INTERNAL_TYPES) |
20 from cubicweb.schemaviewer import SchemaViewer |
21 from cubicweb.schemaviewer import SchemaViewer |
21 from cubicweb.view import EntityView, StartupView |
22 from cubicweb.view import EntityView, StartupView |
22 from cubicweb import tags, uilib |
23 from cubicweb import tags, uilib |
23 from cubicweb.web import action, facet, uicfg |
24 from cubicweb.web import action, facet, uicfg |
24 from cubicweb.web.views import TmpFileViewMixin |
25 from cubicweb.web.views import TmpFileViewMixin |
25 from cubicweb.web.views import primary, baseviews, tabs, management |
26 from cubicweb.web.views import primary, baseviews, tabs, management, tableview |
26 |
27 |
27 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES |
28 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES |
28 SKIP_TYPES = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES |
29 SKIP_TYPES = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES |
29 | INTERNAL_TYPES) |
30 | INTERNAL_TYPES) |
30 SKIP_TYPES.update(set(('CWUser', 'CWGroup'))) |
31 SKIP_TYPES.update(set(('CWUser', 'CWGroup'))) |
187 rdef.subject, rschema, rdef.object)) |
188 rdef.subject, rschema, rdef.object)) |
188 self.schema_definition(rdef) |
189 self.schema_definition(rdef) |
189 self.w(u'</div>') |
190 self.w(u'</div>') |
190 |
191 |
191 |
192 |
192 class SchemaUreportsView(StartupView): |
|
193 __regid__ = 'schema-block' |
|
194 |
|
195 def call(self): |
|
196 viewer = SchemaViewer(self._cw) |
|
197 layout = viewer.visit_schema(self._cw.vreg.schema, display_relations=True, |
|
198 skiptypes=skip_types(self._cw)) |
|
199 self.w(uilib.ureport_as_html(layout)) |
|
200 |
|
201 |
|
202 # CWAttribute / CWRelation ##################################################### |
193 # CWAttribute / CWRelation ##################################################### |
203 |
194 |
204 class CWRDEFPrimaryView(primary.PrimaryView): |
195 class CWRDEFPrimaryView(primary.PrimaryView): |
205 __select__ = implements('CWAttribute', 'CWRelation') |
196 __select__ = implements('CWAttribute', 'CWRelation') |
206 cache_max_age = 60*60*2 # stay in http cache for 2 hours by default |
197 cache_max_age = 60*60*2 # stawy in http cache for 2 hours by default |
207 |
198 |
208 def render_entity_title(self, entity): |
199 def render_entity_title(self, entity): |
209 self.w(u'<h1><span class="etype">%s</span> %s</h1>' |
200 self.w(u'<h1><span class="etype">%s</span> %s</h1>' |
210 % (entity.dc_type().capitalize(), |
201 % (entity.dc_type().capitalize(), |
211 xml_escape(entity.dc_long_title()))) |
202 xml_escape(entity.dc_long_title()))) |
212 |
203 |
|
204 |
|
205 class CWAttributeConstraints(EntityView): |
|
206 __regid__ = 'attr_constraints' |
|
207 __select__ = implements('CWAttribute') |
|
208 |
|
209 def cell_call(self, row, col): |
|
210 entity = self.cw_rset.get_entity(row, col) |
|
211 rschema = self._cw.vreg.schema.rschema(entity.rtype.name) |
|
212 rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)] |
|
213 constraints = [xml_escape(str(c)) for c in getattr(rdef, 'constraints')] |
|
214 self.w(u', '.join(constraints)) |
|
215 |
|
216 |
|
217 class CWAttributeCellView(tableview.CellView): |
|
218 """display attribute name only in a cell view, link to |
|
219 cwattribute primary view""" |
|
220 __select__ = tableview.CellView.__select__ & implements('CWAttribute') |
|
221 |
|
222 def cell_call(self, row, col, cellvid=None): |
|
223 """display attribute name only in a cell view, link to |
|
224 cwattribute primary view""" |
|
225 etype, val = self.cw_rset.description[row][col], self.cw_rset[row][col] |
|
226 if val is not None and not self._cw.vreg.schema.eschema(etype).final: |
|
227 e = self.cw_rset.get_entity(row, col) |
|
228 if cellvid is not None and cellvid != 'incontext': |
|
229 self.wview(cellvid, e.as_rset(), 'null') |
|
230 else: |
|
231 desc = uilib.cut(e.dc_description(), 50) |
|
232 self.w(u'<a href="%s" title="%s">%s' % |
|
233 (xml_escape(e.absolute_url()) ,xml_escape(desc), |
|
234 self.cell_content(e))) |
|
235 self.w(u'</a>') |
|
236 elif val is None: |
|
237 # This is usually caused by a left outer join and in that case, |
|
238 # regular views will most certainly fail if they don't have |
|
239 # a real eid |
|
240 self.wview('final', self.cw_rset, row=row, col=col) |
|
241 else: |
|
242 self.wview(cellvid or 'final', self.cw_rset, 'null', row=row, col=col) |
|
243 |
|
244 def cell_content(self, entity): |
|
245 return entity.relation_type[0].name |
|
246 |
|
247 |
|
248 class CWRelationCellView(CWAttributeCellView): |
|
249 """display relation name and its translation only in a cell view, link to |
|
250 cwrelation primary view""" |
|
251 __select__ = tableview.CellView.__select__ & implements('CWRelation') |
|
252 |
|
253 def cell_content(self, entity): |
|
254 return u'%s (%s)' % (entity.relation_type[0].name, |
|
255 self._cw._(entity.relation_type[0].name)) |
213 |
256 |
214 # CWEType ###################################################################### |
257 # CWEType ###################################################################### |
215 |
258 |
216 class CWETypeOneLineView(baseviews.OneLineView): |
259 class CWETypeOneLineView(baseviews.OneLineView): |
217 __select__ = implements('CWEType') |
260 __select__ = implements('CWEType') |
224 super(CWETypeOneLineView, self).cell_call(row, col, **kwargs) |
267 super(CWETypeOneLineView, self).cell_call(row, col, **kwargs) |
225 if final: |
268 if final: |
226 self.w(u'</em>') |
269 self.w(u'</em>') |
227 |
270 |
228 |
271 |
229 class CWETypePrimaryView(tabs.TabsMixin, primary.PrimaryView): |
272 class CWETypePrimaryView(tabs.TabbedPrimaryView): |
230 __select__ = implements('CWEType') |
273 __select__ = implements('CWEType') |
231 title = _('in memory entity schema') |
274 tabs = [_('cwetype-text-tab'), _('cwetype-box-tab'), _('cwetype-workflow-tab'), |
232 main_related_section = False |
275 _('cwetype-views-tab'), _('cwetype-perm-tab')] |
233 tabs = [_('cwetype-schema-text'), _('cwetype-schema-image'), |
276 default_tab = 'cwetype-text-tab' |
234 _('cwetype-schema-permissions'), _('cwetype-workflow')] |
277 |
235 default_tab = 'cwetype-schema-text' |
278 |
236 |
279 # register generated msgid |
237 def render_entity(self, entity): |
280 _('i18ncard_1'), _('i18ncard_?'), _('i18ncard_+'), _('i18ncard_*') |
238 self.render_entity_title(entity) |
281 |
239 self.w(u'<div>%s</div>' % entity.description) |
282 class CWETypeTextTab(tabs.PrimaryTab): |
240 self.render_tabs(self.tabs, self.default_tab, entity) |
283 __regid__ = 'cwetype-text-tab' |
241 |
284 __select__ = tabs.PrimaryTab.__select__ & implements('CWEType') |
242 |
285 |
243 class CWETypeSTextView(EntityView): |
286 def render_entity_attributes(self, entity, siderelations=None): |
244 __regid__ = 'cwetype-schema-text' |
287 self.w(u'<div>%s</div>' % xml_escape(entity.description or u'')) |
245 __select__ = EntityView.__select__ & implements('CWEType') |
288 # entity schema image |
246 |
289 url = entity.absolute_url(vid='schemagraph') |
247 def cell_call(self, row, col): |
290 self.w(u'<img src="%s" alt="%s"/>' % ( |
248 entity = self.cw_rset.get_entity(row, col) |
291 xml_escape(url), |
|
292 xml_escape(self._cw._('graphical schema for %s') % entity.name))) |
|
293 # entity schema attributes |
249 self.w(u'<h2>%s</h2>' % _('Attributes')) |
294 self.w(u'<h2>%s</h2>' % _('Attributes')) |
250 rset = self._cw.execute('Any N,F,D,I,J,DE,A ' |
295 rset = self._cw.execute('Any A,F,DE,D,C, I,J,A ' |
251 'ORDERBY AA WHERE A is CWAttribute, ' |
296 'ORDERBY AA WHERE A is CWAttribute, ' |
252 'A ordernum AA, A defaultval D, ' |
297 'A ordernum AA, A defaultval D, ' |
253 'A description DE, ' |
298 'A description DE, A cardinality C, ' |
254 'A fulltextindexed I, A internationalizable J, ' |
299 'A fulltextindexed I, A internationalizable J, ' |
255 'A relation_type R, R name N, ' |
300 'A relation_type R, R name N, ' |
256 'A to_entity O, O name F, ' |
301 'A to_entity O, O name F, ' |
257 'A from_entity S, S eid %(x)s', |
302 'A from_entity S, S eid %(x)s', |
258 {'x': entity.eid}) |
303 {'x': entity.eid}) |
259 self.wview('editable-table', rset, 'null', displayfilter=True) |
304 self.wview('table', rset, 'null', |
|
305 cellvids={4: 'attr_cardinality', 7: 'attr_constraints'}, |
|
306 headers=(_(u'name'), _(u'type'), _(u'description'), |
|
307 _(u'default value'), _(u'required'), |
|
308 _(u'fulltext indexed'), _(u'internationalizable'), |
|
309 _(u'constraints')), |
|
310 mainindex=0) |
|
311 # entity schema relations |
260 self.w(u'<h2>%s</h2>' % _('Relations')) |
312 self.w(u'<h2>%s</h2>' % _('Relations')) |
261 rset = self._cw.execute( |
313 rset = self._cw.execute( |
262 'Any R,C,TT,K,D,A,RN,TTN ORDERBY RN ' |
314 'Any A, TT, "i18ncard_"+SUBSTRING(C, 1, 1),K,D,A,RN,TTN ORDERBY RN ' |
263 'WHERE A is CWRelation, A description D, A composite K, ' |
315 'WHERE A is CWRelation, A description D, A composite K, ' |
264 'A relation_type R, R name RN, A to_entity TT, TT name TTN, ' |
316 'A relation_type R, R name RN, A to_entity TT, TT name TTN, ' |
265 'A cardinality C, A from_entity S, S eid %(x)s', |
317 'A cardinality C, A from_entity S, S eid %(x)s', |
266 {'x': entity.eid}) |
318 {'x': entity.eid}) |
267 self.wview('editable-table', rset, 'null', displayfilter=True, |
319 if rset: |
268 displaycols=range(6), mainindex=5) |
320 self.w(u'<h5>%s %s</h5>' % (entity.name, _('is subject of:'))) |
|
321 self.wview('table', rset, 'null', |
|
322 cellvids={2: 'entity_relation_cardinality',}, |
|
323 headers=(_(u'name'), _(u'object type'), _(u'cardinality'), |
|
324 _(u'composite'), _(u'description'), |
|
325 _(u'relation direction')), |
|
326 displaycols=range(5), mainindex=0) |
|
327 self.w(u'<br/>') |
269 rset = self._cw.execute( |
328 rset = self._cw.execute( |
270 'Any R,C,TT,K,D,A,RN,TTN ORDERBY RN ' |
329 'Any A, TT, "i18ncard_"+SUBSTRING(C, 2, 1),K,D,A,RN,TTN ORDERBY RN ' |
271 'WHERE A is CWRelation, A description D, A composite K, ' |
330 'WHERE A is CWRelation, A description D, A composite K, ' |
272 'A relation_type R, R name RN, A from_entity TT, TT name TTN, ' |
331 'A relation_type R, R name RN, A from_entity TT, TT name TTN, ' |
273 'A cardinality C, A to_entity O, O eid %(x)s', |
332 'A cardinality C, A to_entity O, O eid %(x)s', |
274 {'x': entity.eid}) |
333 {'x': entity.eid}) |
275 self.wview('editable-table', rset, 'null', displayfilter=True, |
334 if rset: |
276 displaycols=range(6), mainindex=5) |
335 self.w(u'<h5>%s %s</h5>' % (entity.name, _('is object of:'))) |
277 |
336 self.wview('table', rset, 'null', |
278 |
337 cellvids={2: 'entity_relation_cardinality',}, |
279 class CWETypeSImageView(EntityView): |
338 headers=(_(u'name'), _(u'subject type'), _(u'cardinality'), |
280 __regid__ = 'cwetype-schema-image' |
339 _(u'composite'), _(u'description'), |
281 __select__ = EntityView.__select__ & implements('CWEType') |
340 _(u'relation direction')), |
282 |
341 displaycols=range(5), mainindex=0) |
283 def cell_call(self, row, col): |
342 |
|
343 |
|
344 class CWETypePermTab(EntityView, management.SecurityViewMixIn): |
|
345 __regid__ = 'cwetype-perm-tab' |
|
346 __select__ = EntityView.__select__ & implements('CWEType') & ~anonymous_user() |
|
347 |
|
348 def cell_call(self, row, col): |
|
349 self._cw.add_css('cubicweb.acl.css') |
284 entity = self.cw_rset.get_entity(row, col) |
350 entity = self.cw_rset.get_entity(row, col) |
285 url = entity.absolute_url(vid='schemagraph') |
351 eschema = self._cw.vreg.schema.eschema(entity.name) |
286 self.w(u'<img src="%s" alt="%s"/>' % ( |
352 self.w(u'<a id="%s" href="cwetype/%s">' % (eschema.type, eschema.type)) |
287 xml_escape(url), |
353 self.w(u'<h3 class="schema">%s (%s) ' % (eschema.type, _(eschema.type))) |
288 xml_escape(self._cw._('graphical schema for %s') % entity.name))) |
354 self.w(u'</h3></a>') |
289 |
355 self.w(u'<div style="margin: 0px 1.5em">') |
290 |
356 self.schema_definition(eschema) |
291 class CWETypeSPermView(EntityView): |
357 # display entity attributes only if they have some permissions modified |
292 __regid__ = 'cwetype-schema-permissions' |
358 modified_attrs = [] |
293 __select__ = EntityView.__select__ & implements('CWEType') |
359 self.w(u'<h4>%s</h4>' % _('attributes permissions:').capitalize()) |
294 |
360 for attr, etype in eschema.attribute_definitions(): |
295 def cell_call(self, row, col): |
361 if attr not in META_RTYPES: |
296 entity = self.cw_rset.get_entity(row, col) |
362 rdef = eschema.rdef(attr) |
297 _ = self._cw._ |
363 attrtype = str(rdef.rtype) |
298 self.w(u'<h2>%s</h2>' % _('Add permissions')) |
364 self.w(u'<h4 class="schema">%s (%s)</h4> ' % (attrtype, _(attrtype))) |
299 rset = self._cw.execute('Any P WHERE X add_permission P, ' |
365 self.schema_definition(rdef, link=False) |
300 'X eid %(x)s', |
366 self.w(u'</div>') |
301 {'x': entity.eid}) |
367 |
302 self.wview('outofcontext', rset, 'null') |
368 |
303 self.w(u'<h2>%s</h2>' % _('Read permissions')) |
369 class CWETypeWorkflowTab(EntityView): |
304 rset = self._cw.execute('Any P WHERE X read_permission P, ' |
370 __regid__ = 'cwetype-workflow-tab' |
305 'X eid %(x)s', |
|
306 {'x': entity.eid}) |
|
307 self.wview('outofcontext', rset, 'null') |
|
308 self.w(u'<h2>%s</h2>' % _('Update permissions')) |
|
309 rset = self._cw.execute('Any P WHERE X update_permission P, ' |
|
310 'X eid %(x)s', |
|
311 {'x': entity.eid}) |
|
312 self.wview('outofcontext', rset, 'null') |
|
313 self.w(u'<h2>%s</h2>' % _('Delete permissions')) |
|
314 rset = self._cw.execute('Any P WHERE X delete_permission P, ' |
|
315 'X eid %(x)s', |
|
316 {'x': entity.eid}) |
|
317 self.wview('outofcontext', rset, 'null') |
|
318 |
|
319 |
|
320 class CWETypeSWorkflowView(EntityView): |
|
321 __regid__ = 'cwetype-workflow' |
|
322 __select__ = (EntityView.__select__ & implements('CWEType') & |
371 __select__ = (EntityView.__select__ & implements('CWEType') & |
323 has_related_entities('workflow_of', 'object')) |
372 has_related_entities('workflow_of', 'object')) |
324 |
373 |
325 def cell_call(self, row, col): |
374 def cell_call(self, row, col): |
326 entity = self.cw_rset.get_entity(row, col) |
375 entity = self.cw_rset.get_entity(row, col) |