1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
16 # You should have received a copy of the GNU Lesser General Public License along |
|
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
18 """security management and error screens""" |
|
19 |
|
20 __docformat__ = "restructuredtext en" |
|
21 from cubicweb import _ |
|
22 |
|
23 |
|
24 from logilab.mtconverter import xml_escape |
|
25 from logilab.common.registry import yes |
|
26 |
|
27 from cubicweb.predicates import none_rset, match_user_groups, authenticated_user |
|
28 from cubicweb.view import AnyRsetView, StartupView, EntityView, View |
|
29 from cubicweb.uilib import html_traceback, rest_traceback, exc_message |
|
30 from cubicweb.web import formwidgets as wdgs |
|
31 from cubicweb.web.formfields import guess_field |
|
32 from cubicweb.web.views.schema import SecurityViewMixIn |
|
33 |
|
34 from yams.buildobjs import EntityType |
|
35 |
|
36 SUBMIT_MSGID = _('Submit bug report') |
|
37 MAIL_SUBMIT_MSGID = _('Submit bug report by mail') |
|
38 |
|
39 class SecurityManagementView(SecurityViewMixIn, EntityView): |
|
40 """display security information for a given entity""" |
|
41 __regid__ = 'security' |
|
42 __select__ = EntityView.__select__ & authenticated_user() |
|
43 |
|
44 title = _('security') |
|
45 |
|
46 def call(self): |
|
47 self.w(u'<div id="progress">%s</div>' % self._cw._('validating...')) |
|
48 super(SecurityManagementView, self).call() |
|
49 |
|
50 def entity_call(self, entity): |
|
51 self._cw.add_js('cubicweb.edition.js') |
|
52 self._cw.add_css('cubicweb.acl.css') |
|
53 w = self.w |
|
54 _ = self._cw._ |
|
55 w(u'<h1><span class="etype">%s</span> <a href="%s">%s</a></h1>' |
|
56 % (entity.dc_type().capitalize(), |
|
57 xml_escape(entity.absolute_url()), |
|
58 xml_escape(entity.dc_title()))) |
|
59 # first show permissions defined by the schema |
|
60 self.w('<h2>%s</h2>' % _('Schema\'s permissions definitions')) |
|
61 self.permissions_table(entity.e_schema) |
|
62 self.w('<h2>%s</h2>' % _('Manage security')) |
|
63 # ownership information |
|
64 if self._cw.vreg.schema.rschema('owned_by').has_perm(self._cw, 'add', |
|
65 fromeid=entity.eid): |
|
66 self.owned_by_edit_form(entity) |
|
67 else: |
|
68 self.owned_by_information(entity) |
|
69 |
|
70 def owned_by_edit_form(self, entity): |
|
71 self.w('<h3>%s</h3>' % self._cw._('Ownership')) |
|
72 msg = self._cw._('ownerships have been changed') |
|
73 form = self._cw.vreg['forms'].select('base', self._cw, entity=entity, |
|
74 form_renderer_id='onerowtable', submitmsg=msg, |
|
75 form_buttons=[wdgs.SubmitButton()], |
|
76 domid='ownership%s' % entity.eid, |
|
77 __redirectvid='security', |
|
78 __redirectpath=entity.rest_path()) |
|
79 field = guess_field(entity.e_schema, |
|
80 self._cw.vreg.schema['owned_by'], |
|
81 req=self._cw) |
|
82 form.append_field(field) |
|
83 form.render(w=self.w, display_progress_div=False) |
|
84 |
|
85 def owned_by_information(self, entity): |
|
86 ownersrset = entity.related('owned_by') |
|
87 if ownersrset: |
|
88 self.w('<h3>%s</h3>' % self._cw._('Ownership')) |
|
89 self.w(u'<div class="ownerInfo">') |
|
90 self.w(self._cw._('this entity is currently owned by') + ' ') |
|
91 self.wview('csv', entity.related('owned_by'), 'null') |
|
92 self.w(u'</div>') |
|
93 # else we don't know if this is because entity has no owner or becayse |
|
94 # user as no access to owner users entities |
|
95 |
|
96 |
|
97 class ErrorView(AnyRsetView): |
|
98 """default view when no result has been found""" |
|
99 __select__ = yes() |
|
100 __regid__ = 'error' |
|
101 |
|
102 def page_title(self): |
|
103 """returns a title according to the result set - used for the |
|
104 title in the HTML header |
|
105 """ |
|
106 return self._cw._('an error occurred') |
|
107 |
|
108 def _excinfo(self): |
|
109 req = self._cw |
|
110 ex = req.data.get('ex') |
|
111 excinfo = req.data.get('excinfo') |
|
112 if 'errmsg' in req.data: |
|
113 errmsg = req.data['errmsg'] |
|
114 exclass = None |
|
115 else: |
|
116 errmsg = exc_message(ex, req.encoding) |
|
117 exclass = ex.__class__.__name__ |
|
118 return errmsg, exclass, excinfo |
|
119 |
|
120 def call(self): |
|
121 req = self._cw.reset_headers() |
|
122 w = self.w |
|
123 title = self._cw._('an error occurred') |
|
124 w(u'<h2>%s</h2>' % title) |
|
125 ex, exclass, excinfo = self._excinfo() |
|
126 if excinfo is not None and self._cw.vreg.config['print-traceback']: |
|
127 if exclass is None: |
|
128 w(u'<div class="tb">%s</div>' |
|
129 % xml_escape(ex).replace("\n","<br />")) |
|
130 else: |
|
131 w(u'<div class="tb">%s: %s</div>' |
|
132 % (exclass, xml_escape(ex).replace("\n","<br />"))) |
|
133 w(u'<hr />') |
|
134 w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, '')) |
|
135 else: |
|
136 w(u'<div class="tb">%s</div>' % (xml_escape(ex).replace("\n","<br />"))) |
|
137 # if excinfo is not None, it's probably not a bug |
|
138 if excinfo is None: |
|
139 return |
|
140 vcconf = self._cw.cnx.repo.get_versions() |
|
141 w(u"<div>") |
|
142 eversion = vcconf.get('cubicweb', self._cw._('no version information')) |
|
143 # NOTE: tuple wrapping needed since eversion is itself a tuple |
|
144 w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,)) |
|
145 cversions = [] |
|
146 for cube in self._cw.vreg.config.cubes(): |
|
147 cubeversion = vcconf.get(cube, self._cw._('no version information')) |
|
148 w(u"<b>Cube %s version:</b> %s<br/>\n" % (cube, cubeversion)) |
|
149 cversions.append((cube, cubeversion)) |
|
150 w(u"</div>") |
|
151 # creates a bug submission link if submit-mail is set |
|
152 if self._cw.vreg.config['submit-mail']: |
|
153 form = self._cw.vreg['forms'].select('base', self._cw, rset=None, |
|
154 mainform=False) |
|
155 binfo = text_error_description(ex, excinfo, req, eversion, cversions) |
|
156 form.add_hidden('description', binfo, |
|
157 # we must use a text area to keep line breaks |
|
158 widget=wdgs.TextArea({'class': 'hidden'})) |
|
159 # add a signature so one can't send arbitrary text |
|
160 form.add_hidden('__signature', req.vreg.config.sign_text(binfo)) |
|
161 form.add_hidden('__bugreporting', '1') |
|
162 form.form_buttons = [wdgs.SubmitButton(MAIL_SUBMIT_MSGID)] |
|
163 form.action = req.build_url('reportbug') |
|
164 form.render(w=w) |
|
165 |
|
166 |
|
167 def text_error_description(ex, excinfo, req, eversion, cubes): |
|
168 binfo = rest_traceback(excinfo, xml_escape(ex)) |
|
169 binfo += u'\n\n:URL: %s\n' % req.url() |
|
170 if not '__bugreporting' in req.form: |
|
171 binfo += u'\n:form params:\n' |
|
172 binfo += u'\n'.join(u' * %s = %s' % (k, v) for k, v in req.form.items()) |
|
173 binfo += u'\n\n:CubicWeb version: %s\n' % (eversion,) |
|
174 for pkg, pkgversion in cubes: |
|
175 binfo += u":Cube %s version: %s\n" % (pkg, pkgversion) |
|
176 binfo += '\n' |
|
177 return binfo |
|
178 |
|
179 |
|
180 class CwStats(View): |
|
181 """A textual stats output for monitoring tools such as munin """ |
|
182 |
|
183 __regid__ = 'processinfo' |
|
184 content_type = 'text/plain' |
|
185 templatable = False |
|
186 __select__ = none_rset() & match_user_groups('users', 'managers') |
|
187 |
|
188 def call(self): |
|
189 stats = self._cw.call_service('repo_stats') |
|
190 stats['looping_tasks'] = ', '.join('%s (%s seconds)' % (n, i) for n, i in stats['looping_tasks']) |
|
191 stats['threads'] = ', '.join(sorted(stats['threads'])) |
|
192 for k in stats: |
|
193 if k in ('extid_cache_size', 'type_source_cache_size'): |
|
194 continue |
|
195 if k.endswith('_cache_size'): |
|
196 stats[k] = '%s / %s' % (stats[k]['size'], stats[k]['maxsize']) |
|
197 results = [] |
|
198 for element in stats: |
|
199 results.append(u'%s %s' % (element, stats[element])) |
|
200 self.w(u'\n'.join(results)) |
|