|
1 """management and error screens |
|
2 |
|
3 |
|
4 :organization: Logilab |
|
5 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
7 """ |
|
8 __docformat__ = "restructuredtext en" |
|
9 |
|
10 from logilab.mtconverter import html_escape |
|
11 |
|
12 from logilab.common.decorators import cached |
|
13 |
|
14 from cubicweb.common.utils import UStringIO |
|
15 from cubicweb.common.view import AnyRsetView, StartupView, EntityView |
|
16 from cubicweb.common.uilib import (html_traceback, rest_traceback, html_escape, |
|
17 toggle_link) |
|
18 from cubicweb.common.selectors import (yes_selector, onelinerset_selector, |
|
19 accept_rset_selector, norset_selector, |
|
20 chainfirst, chainall) |
|
21 from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs |
|
22 from cubicweb.web.widgets import StaticComboBoxWidget |
|
23 from cubicweb.web.form import FormMixIn |
|
24 |
|
25 _ = unicode |
|
26 |
|
27 def begin_form(w, entity, redirectvid, redirectpath=None, msg=None): |
|
28 w(u'<form method="post" action="%s">\n' % entity.req.build_url('edit')) |
|
29 w(u'<fieldset>\n') |
|
30 w(u'<input type="hidden" name="__redirectvid" value="%s"/>\n' % redirectvid) |
|
31 w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % ( |
|
32 html_escape(redirectpath or entity.rest_path()))) |
|
33 w(u'<input type="hidden" name="eid" value="%s"/>\n' % entity.eid) |
|
34 w(u'<input type="hidden" name="%s" value="%s"/>\n' % ( |
|
35 eid_param('__type', entity.eid), entity.e_schema)) |
|
36 if msg: |
|
37 w(u'<input type="hidden" name="__message" value="%s"/>\n' |
|
38 % html_escape(msg)) |
|
39 |
|
40 |
|
41 class SecurityManagementView(EntityView): |
|
42 """display security information for a given entity""" |
|
43 id = 'security' |
|
44 title = _('security') |
|
45 |
|
46 def cell_call(self, row, col): |
|
47 self.req.add_js('cubicweb.edition.js') |
|
48 self.req.add_css('cubicweb.acl.css') |
|
49 entity = self.entity(row, col) |
|
50 w = self.w |
|
51 _ = self.req._ |
|
52 w(u'<h1><span class="etype">%s</span> <a href="%s">%s</a></h1>' |
|
53 % (entity.dc_type().capitalize(), |
|
54 html_escape(entity.absolute_url()), |
|
55 html_escape(entity.dc_title()))) |
|
56 # first show permissions defined by the schema |
|
57 self.w('<h2>%s</h2>' % _('schema\'s permissions definitions')) |
|
58 self.schema_definition(entity) |
|
59 self.w('<h2>%s</h2>' % _('manage security')) |
|
60 # ownership information |
|
61 if self.schema.rschema('owned_by').has_perm(self.req, 'add', |
|
62 fromeid=entity.eid): |
|
63 self.owned_by_edit_form(entity) |
|
64 else: |
|
65 self.owned_by_information(entity) |
|
66 # epermissions |
|
67 if 'require_permission' in entity.e_schema.subject_relations(): |
|
68 w('<h3>%s</h3>' % _('permissions for this entity')) |
|
69 reqpermschema = self.schema.rschema('require_permission') |
|
70 self.require_permission_information(entity, reqpermschema) |
|
71 if reqpermschema.has_perm(self.req, 'add', fromeid=entity.eid): |
|
72 self.require_permission_edit_form(entity) |
|
73 |
|
74 def schema_definition(self, entity): |
|
75 w = self.w |
|
76 _ = self.req._ |
|
77 w(u'<table class="schemaInfo">') |
|
78 w(u'<tr><th>%s</th><th>%s</th><th>%s</th></tr>' % ( |
|
79 _("access type"), _('granted to groups'), _('rql expressions'))) |
|
80 for access_type in ('read', 'add', 'update', 'delete'): |
|
81 w(u'<tr>') |
|
82 w(u'<th>%s</th>' % self.req.__('%s_permission' % access_type)) |
|
83 groups = entity.e_schema.get_groups(access_type) |
|
84 l = [] |
|
85 for group in groups: |
|
86 l.append(u'<a href="%s">%s</a>' % ( |
|
87 self.build_url('egroup/%s' % group), _(group))) |
|
88 w(u'<td>%s</td>' % u', '.join(l)) |
|
89 rqlexprs = entity.e_schema.get_rqlexprs(access_type) |
|
90 w(u'<td>%s</td>' % u'<br/>'.join(expr.expression for expr in rqlexprs)) |
|
91 w(u'</tr>\n') |
|
92 w(u'</table>') |
|
93 |
|
94 def owned_by_edit_form(self, entity): |
|
95 self.w('<h3>%s</h3>' % self.req._('ownership')) |
|
96 begin_form(self.w, entity, 'security', msg= _('ownerships have been changed')) |
|
97 self.w(u'<table border="0">\n') |
|
98 self.w(u'<tr><td>\n') |
|
99 wdg = entity.get_widget('owned_by') |
|
100 self.w(wdg.edit_render(entity)) |
|
101 self.w(u'</td><td>\n') |
|
102 self.w(self.button_ok()) |
|
103 self.w(u'</td></tr>\n</table>\n') |
|
104 self.w(u'</fieldset></form>\n') |
|
105 |
|
106 def owned_by_information(self, entity): |
|
107 ownersrset = entity.related('owned_by') |
|
108 if ownersrset: |
|
109 self.w('<h3>%s</h3>' % self.req._('ownership')) |
|
110 self.w(u'<div class="ownerInfo">') |
|
111 self.w(self.req._('this entity is currently owned by') + ' ') |
|
112 self.wview('csv', entity.related('owned_by'), 'null') |
|
113 self.w(u'</div>') |
|
114 # else we don't know if this is because entity has no owner or becayse |
|
115 # user as no access to owner users entities |
|
116 |
|
117 def require_permission_information(self, entity, reqpermschema): |
|
118 if entity.require_permission: |
|
119 w = self.w |
|
120 _ = self.req._ |
|
121 if reqpermschema.has_perm(self.req, 'delete', fromeid=entity.eid): |
|
122 delurl = self.build_url('edit', __redirectvid='security', |
|
123 __redirectpath=entity.rest_path()) |
|
124 delurl = delurl.replace('%', '%%') |
|
125 # don't give __delete value to build_url else it will be urlquoted |
|
126 # and this will replace %s by %25s |
|
127 delurl += '&__delete=%s:require_permission:%%s' % entity.eid |
|
128 dellinktempl = u'[<a href="%s" title="%s">-</a>] ' % ( |
|
129 html_escape(delurl), _('delete this permission')) |
|
130 else: |
|
131 dellinktempl = None |
|
132 w(u'<table class="schemaInfo">') |
|
133 w(u'<tr><th>%s</th><th>%s</th></tr>' % (_("permission"), |
|
134 _('granted to groups'))) |
|
135 for eperm in entity.require_permission: |
|
136 w(u'<tr>') |
|
137 if dellinktempl: |
|
138 w(u'<td>%s%s</td>' % (dellinktempl % eperm.eid, |
|
139 eperm.view('oneline'))) |
|
140 else: |
|
141 w(u'<td>%s</td>' % eperm.view('oneline')) |
|
142 w(u'<td>%s</td>' % self.view('csv', eperm.related('require_group'), 'null')) |
|
143 w(u'</tr>\n') |
|
144 w(u'</table>') |
|
145 else: |
|
146 self.w(self.req._('no associated epermissions')) |
|
147 |
|
148 def require_permission_edit_form(self, entity): |
|
149 w = self.w |
|
150 _ = self.req._ |
|
151 newperm = self.vreg.etype_class('EPermission')(self.req, None) |
|
152 newperm.eid = self.req.varmaker.next() |
|
153 w(u'<p>%s</p>' % _('add a new permission')) |
|
154 begin_form(w, newperm, 'security', entity.rest_path()) |
|
155 w(u'<input type="hidden" name="%s" value="__cubicweb_internal_field__"/>' |
|
156 % eid_param('edito-require_permission', newperm.eid)) |
|
157 w(u'<input type="hidden" name="%s" value="%s"/>' |
|
158 % (eid_param('require_permission', newperm.eid), entity.eid)) |
|
159 w(u'<table border="0">\n') |
|
160 w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th> </th></tr>\n' |
|
161 % (_("name"), _("label"), _('granted to groups'))) |
|
162 if getattr(entity, '__permissions__', None): |
|
163 wdg = StaticComboBoxWidget(self.vreg, self.schema['EPermission'], |
|
164 self.schema['name'], self.schema['String'], |
|
165 vocabfunc=lambda x: entity.__permissions__) |
|
166 else: |
|
167 wdg = newperm.get_widget('name') |
|
168 w(u'<tr><td>%s</td>\n' % wdg.edit_render(newperm)) |
|
169 wdg = newperm.get_widget('label') |
|
170 w(u'<td>%s</td>\n' % wdg.edit_render(newperm)) |
|
171 wdg = newperm.get_widget('require_group') |
|
172 w(u'<td>%s</td>\n' % wdg.edit_render(newperm)) |
|
173 w(u'<td>%s</td></tr>\n' % self.button_ok()) |
|
174 w(u'</table>') |
|
175 w(u'</fieldset></form>\n') |
|
176 |
|
177 def button_ok(self): |
|
178 return (u'<input class="validateButton" type="submit" name="submit" value="%s"/>' |
|
179 % self.req._(stdmsgs.BUTTON_OK)) |
|
180 |
|
181 |
|
182 class ErrorView(AnyRsetView): |
|
183 """default view when no result has been found""" |
|
184 __selectors__ = (yes_selector,) |
|
185 id = 'error' |
|
186 |
|
187 def page_title(self): |
|
188 """returns a title according to the result set - used for the |
|
189 title in the HTML header |
|
190 """ |
|
191 return self.req._('an error occured') |
|
192 |
|
193 def call(self): |
|
194 req = self.req.reset_headers() |
|
195 _ = req._ |
|
196 ex = req.data.get('ex')#_("unable to find exception information")) |
|
197 excinfo = req.data.get('excinfo') |
|
198 title = _('an error occured') |
|
199 self.w(u'<h2>%s</h2>' % title) |
|
200 if 'errmsg' in req.data: |
|
201 ex = req.data['errmsg'] |
|
202 else: |
|
203 ex = exc_message(ex, req.encoding) |
|
204 if excinfo is not None and self.config['print-traceback']: |
|
205 exclass = ex.__class__.__name__ |
|
206 self.w(u'<div class="tb">%s: %s</div>' % (exclass, html_escape(ex).replace("\n","<br />"))) |
|
207 self.w(u'<hr />') |
|
208 self.w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, '')) |
|
209 else: |
|
210 self.w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />"))) |
|
211 # if excinfo is not None, it's probably not a bug |
|
212 if excinfo is None: |
|
213 return |
|
214 vcconf = self.config.vc_config() |
|
215 self.w(u"<div>") |
|
216 eversion = vcconf.get('cubicweb', _('no version information')) |
|
217 # NOTE: tuple wrapping needed since eversion is itself a tuple |
|
218 self.w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,)) |
|
219 for pkg in self.config.cubes(): |
|
220 pkgversion = vcconf.get(pkg, _('no version information')) |
|
221 self.w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion)) |
|
222 self.w(u"</div>") |
|
223 # creates a bug submission link if SUBMIT_URL is set |
|
224 submiturl = self.config['submit-url'] |
|
225 if submiturl: |
|
226 binfo = text_error_description(ex, excinfo, req, eversion, |
|
227 [(pkg, vcconf.get(pkg, _('no version information'))) |
|
228 for pkg in self.config.cubes()]) |
|
229 self.w(u'<form action="%s" method="post">\n' % html_escape(submiturl)) |
|
230 self.w(u'<fieldset>\n') |
|
231 self.w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo)) |
|
232 self.w(u'<input type="hidden" name="description_format" value="text/rest"/>') |
|
233 self.w(u'<input type="hidden" name="__bugreporting" value="1"/>') |
|
234 self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report')) |
|
235 self.w(u'</fieldset>\n') |
|
236 self.w(u'</form>\n') |
|
237 submitmail = self.config['submit-mail'] |
|
238 if submitmail: |
|
239 binfo = text_error_description(ex, excinfo, req, eversion, |
|
240 [(pkg, vcconf.get(pkg, _('no version information'))) |
|
241 for pkg in self.config.cubes()]) |
|
242 self.w(u'<form action="%s" method="post">\n' % req.build_url('reportbug')) |
|
243 self.w(u'<fieldset>\n') |
|
244 self.w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo)) |
|
245 self.w(u'<input type="hidden" name="__bugreporting" value="1"/>') |
|
246 self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail')) |
|
247 self.w(u'</fieldset>\n') |
|
248 self.w(u'</form>\n') |
|
249 |
|
250 |
|
251 def exc_message(ex, encoding): |
|
252 try: |
|
253 return unicode(ex) |
|
254 except: |
|
255 try: |
|
256 return unicode(str(ex), encoding, 'replace') |
|
257 except: |
|
258 return unicode(repr(ex), encoding, 'replace') |
|
259 |
|
260 def text_error_description(ex, excinfo, req, eversion, cubes): |
|
261 binfo = rest_traceback(excinfo, html_escape(ex)) |
|
262 binfo += u'\n\n:URL: %s\n' % req.url() |
|
263 if not '__bugreporting' in req.form: |
|
264 binfo += u'\n:form params:\n' |
|
265 binfo += u'\n'.join(u' * %s = %s' % (k, v) for k, v in req.form.iteritems()) |
|
266 binfo += u'\n\n:CubicWeb version: %s\n' % (eversion,) |
|
267 for pkg, pkgversion in cubes: |
|
268 binfo += u":Package %s version: %s\n" % (pkg, pkgversion) |
|
269 binfo += '\n' |
|
270 return binfo |
|
271 |
|
272 # some string we want to be internationalizable for nicer display of eproperty |
|
273 # groups |
|
274 _('navigation') |
|
275 _('ui') |
|
276 _('actions') |
|
277 _('boxes') |
|
278 _('components') |
|
279 _('contentnavigation') |
|
280 |
|
281 class SystemEpropertiesForm(FormMixIn, StartupView): |
|
282 controller = 'edit' |
|
283 id = 'systemepropertiesform' |
|
284 title = _('site configuration') |
|
285 require_groups = ('managers',) |
|
286 category = 'startupview' |
|
287 |
|
288 def linkable(self): |
|
289 return True |
|
290 |
|
291 def url(self): |
|
292 """return the url associated with this view. We can omit rql here""" |
|
293 return self.build_url('view', vid=self.id) |
|
294 |
|
295 def call(self, **kwargs): |
|
296 """The default view representing the application's index""" |
|
297 self.req.add_js('cubicweb.edition.js') |
|
298 self.req.add_css('cubicweb.preferences.css') |
|
299 vreg = self.vreg |
|
300 values = self.defined_keys |
|
301 groupedopts = {} |
|
302 mainopts = {} |
|
303 # "self.id=='systemepropertiesform'" to skip site wide properties on |
|
304 # user's preference but not site's configuration |
|
305 for key in vreg.user_property_keys(self.id=='systemepropertiesform'): |
|
306 parts = key.split('.') |
|
307 if parts[0] in vreg: |
|
308 # appobject configuration |
|
309 reg, oid, propid = parts |
|
310 groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key) |
|
311 else: |
|
312 mainopts.setdefault(parts[0], []).append(key) |
|
313 # precompute form to consume error message |
|
314 for group, keys in mainopts.items(): |
|
315 mainopts[group] = self.form(keys, False) |
|
316 for group, objects in groupedopts.items(): |
|
317 for oid, keys in objects.items(): |
|
318 groupedopts[group][oid] = self.form(keys, True) |
|
319 |
|
320 w = self.w |
|
321 req = self.req |
|
322 _ = req._ |
|
323 w(u'<h1>%s</h1>\n' % _(self.title)) |
|
324 w(self.error_message()) |
|
325 for label, group, form in sorted((_(g), g, f) |
|
326 for g, f in mainopts.iteritems()): |
|
327 w(u'<h2 class="propertiesform">%s</h2>\n' % |
|
328 (toggle_link('fieldset_' + group, label))) |
|
329 w(u'<div id="fieldset_%s" class="hidden">' % group) |
|
330 w(u'<fieldset class="subentity">') |
|
331 w(form) |
|
332 w(u'</fieldset></div>') |
|
333 for label, group, objects in sorted((_(g), g, o) |
|
334 for g, o in groupedopts.iteritems()): |
|
335 w(u'<h2 class="propertiesform">%s</h2>\n' % |
|
336 (toggle_link('fieldset_' + group, label))) |
|
337 w(u'<div id="fieldset_%s" class="hidden">' % group) |
|
338 for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f) |
|
339 for o, f in objects.iteritems()): |
|
340 w(u'<fieldset class="subentity">') |
|
341 w(u'<legend class="componentTitle">%s</legend>\n' % label) |
|
342 docmsgid = '%s_%s_description' % (group, oid) |
|
343 doc = _(docmsgid) |
|
344 if doc != docmsgid: |
|
345 w(u'<p class="description">%s</p>' % html_escape(doc)) |
|
346 w(form) |
|
347 w(u'</fieldset>') |
|
348 w(u'</div>') |
|
349 |
|
350 |
|
351 |
|
352 @property |
|
353 @cached |
|
354 def eprops_rset(self): |
|
355 return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U') |
|
356 |
|
357 @property |
|
358 def defined_keys(self): |
|
359 values = {} |
|
360 for i, entity in enumerate(self.eprops_rset.entities()): |
|
361 values[entity.pkey] = i |
|
362 return values |
|
363 |
|
364 def entity_for_key(self, key): |
|
365 values = self.defined_keys |
|
366 if key in values: |
|
367 entity = self.eprops_rset.get_entity(values[key], 0) |
|
368 else: |
|
369 entity = self.vreg.etype_class('EProperty')(self.req, None, None) |
|
370 entity.eid = self.req.varmaker.next() |
|
371 entity['value'] = self.vreg.property_value(key) |
|
372 return entity |
|
373 |
|
374 def form(self, keys, splitlabel=False): |
|
375 stream = UStringIO() |
|
376 w = stream.write |
|
377 w(u'<form action="%s" method="post">\n' % self.build_url()) |
|
378 w(u'<fieldset>\n') |
|
379 w(u'<input type="hidden" name="__errorurl" value="%s"/>\n' |
|
380 % html_escape(self.req.url())) |
|
381 w(u'<input type="hidden" name="__form_id" value="%s"/>\n' % self.id) |
|
382 path = self.req.relative_path() |
|
383 if '?' in path: |
|
384 path, params = path.split('?', 1) |
|
385 w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n' |
|
386 % html_escape(params)) |
|
387 w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path) |
|
388 #w(u'<input type="hidden" name="__redirectrql" value=""/>\n') |
|
389 w(u'<input type="hidden" name="__message" value="%s"/>\n' |
|
390 % self.req._('changes applied')) |
|
391 w(u'<table><tr><td>\n') |
|
392 |
|
393 w(u'<table>\n') |
|
394 for key in keys: |
|
395 w(u'<tr>\n') |
|
396 self.form_row(w, key, splitlabel) |
|
397 w(u'</tr>\n') |
|
398 w(u'</table>\n') |
|
399 w(u'</td></tr><tr><td>\n') |
|
400 w(self.button_ok()) |
|
401 w(self.button_cancel()) |
|
402 w(u'</td></tr></table>\n') |
|
403 w(u'</fieldset>\n') |
|
404 w(u'</form>\n') |
|
405 return stream.getvalue() |
|
406 |
|
407 def form_row(self, w, key, splitlabel): |
|
408 entity = self.entity_for_key(key) |
|
409 eid = entity.eid |
|
410 if splitlabel: |
|
411 w(u'<td class="label">%s</td>' % self.req._(key.split('.')[-1])) |
|
412 else: |
|
413 w(u'<td class="label">%s</td>' % self.req._(key)) |
|
414 wdg = self.vreg.property_value_widget(key, req=self.req) |
|
415 error = wdg.render_error(entity) |
|
416 w(u'<td class="%s">' % (error and 'error' or '')) |
|
417 w(error) |
|
418 self.form_row_hiddens(w, entity, key) |
|
419 w(wdg.edit_render(entity)) |
|
420 w(u'</td>\n') |
|
421 w(u'<td>%s</td>' % wdg.render_help(entity)) |
|
422 return entity |
|
423 |
|
424 def form_row_hiddens(self, w, entity, key): |
|
425 eid = entity.eid |
|
426 w(u'<input type="hidden" name="eid" value="%s"/>' % eid) |
|
427 w(u'<input type="hidden" name="%s" value="EProperty"/>' % eid_param('__type', eid)) |
|
428 w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key)) |
|
429 w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), '')) |
|
430 |
|
431 |
|
432 class EpropertiesForm(SystemEpropertiesForm): |
|
433 id = 'epropertiesform' |
|
434 title = _('preferences') |
|
435 require_groups = ('users', 'managers') # we don't want guests to be able to come here |
|
436 __selectors__ = chainfirst(norset_selector, |
|
437 chainall(onelinerset_selector, accept_rset_selector)), |
|
438 accepts = ('EUser',) |
|
439 |
|
440 @classmethod |
|
441 def accept_rset(cls, req, rset, row, col): |
|
442 if row is None: |
|
443 row = 0 |
|
444 score = super(EpropertiesForm, cls).accept_rset(req, rset, row, col) |
|
445 # check current user is the rset user or he is in the managers group |
|
446 if score and (req.user.eid == rset[row][col or 0] |
|
447 or req.user.matching_groups('managers')): |
|
448 return score |
|
449 return 0 |
|
450 |
|
451 @property |
|
452 def user(self): |
|
453 if self.rset is None: |
|
454 return self.req.user |
|
455 return self.rset.get_entity(self.row or 0, self.col or 0) |
|
456 |
|
457 @property |
|
458 @cached |
|
459 def eprops_rset(self): |
|
460 return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V,' |
|
461 'P for_user U, U eid %(x)s', {'x': self.user.eid}) |
|
462 |
|
463 def form_row_hiddens(self, w, entity, key): |
|
464 super(EpropertiesForm, self).form_row_hiddens(w, entity, key) |
|
465 # if user is in the managers group and the property is being created, |
|
466 # we have to set for_user explicitly |
|
467 if not entity.has_eid() and self.user.matching_groups('managers'): |
|
468 eid = entity.eid |
|
469 w(u'<input type="hidden" name="%s" value="%s"/>' |
|
470 % (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE)) |
|
471 w(u'<input type="hidden" name="%s" value="%s"/>' |
|
472 % (eid_param('for_user', eid), self.user.eid)) |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 class ProcessInformationView(StartupView): |
|
478 id = 'info' |
|
479 title = _('server information') |
|
480 require_groups = ('managers',) |
|
481 |
|
482 def call(self, **kwargs): |
|
483 """display server information""" |
|
484 vcconf = self.config.vc_config() |
|
485 req = self.req |
|
486 _ = req._ |
|
487 # display main information |
|
488 self.w(u'<h3>%s</h3>' % _('Application')) |
|
489 self.w(u'<table border="1">') |
|
490 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % ( |
|
491 'CubicWeb', vcconf.get('cubicweb', _('no version information')))) |
|
492 for pkg in self.config.cubes(): |
|
493 pkgversion = vcconf.get(pkg, _('no version information')) |
|
494 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % ( |
|
495 pkg, pkgversion)) |
|
496 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % ( |
|
497 _('home'), self.config.apphome)) |
|
498 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % ( |
|
499 _('base url'), req.base_url())) |
|
500 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % ( |
|
501 _('data directory url'), req.datadir_url)) |
|
502 self.w(u'</table>') |
|
503 self.w(u'<br/>') |
|
504 # environment and request and server information |
|
505 try: |
|
506 # need to remove our adapter and then modpython-apache wrapper... |
|
507 env = req._areq._req.subprocess_env |
|
508 except AttributeError: |
|
509 return |
|
510 self.w(u'<h3>%s</h3>' % _('Environment')) |
|
511 self.w(u'<table border="1">') |
|
512 for attr in env.keys(): |
|
513 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' |
|
514 % (attr, html_escape(env[attr]))) |
|
515 self.w(u'</table>') |
|
516 self.w(u'<h3>%s</h3>' % _('Request')) |
|
517 self.w(u'<table border="1">') |
|
518 for attr in ('filename', 'form', 'hostname', 'main', 'method', |
|
519 'path_info', 'protocol', |
|
520 'search_state', 'the_request', 'unparsed_uri', 'uri'): |
|
521 val = getattr(req, attr) |
|
522 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' |
|
523 % (attr, html_escape(val))) |
|
524 self.w(u'</table>') |
|
525 server = req.server |
|
526 self.w(u'<h3>%s</h3>' % _('Server')) |
|
527 self.w(u'<table border="1">') |
|
528 for attr in dir(server): |
|
529 val = getattr(server, attr) |
|
530 if attr.startswith('_') or callable(val): |
|
531 continue |
|
532 self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>' |
|
533 % (attr, html_escape(val))) |
|
534 self.w(u'</table>') |
|
535 |