|
1 # copyright 2003-2011 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 """Specific views for users and groups""" |
|
19 |
|
20 __docformat__ = "restructuredtext en" |
|
21 from cubicweb import _ |
|
22 |
|
23 from hashlib import sha1 # pylint: disable=E0611 |
|
24 |
|
25 from six import text_type |
|
26 from six.moves import range |
|
27 |
|
28 from logilab.mtconverter import xml_escape |
|
29 |
|
30 from cubicweb import tags |
|
31 from cubicweb.schema import display_name |
|
32 from cubicweb.predicates import one_line_rset, is_instance, match_user_groups |
|
33 from cubicweb.view import EntityView, StartupView |
|
34 from cubicweb.web import action, formwidgets |
|
35 from cubicweb.web.views import uicfg, tabs, tableview, actions, add_etype_button |
|
36 |
|
37 _pvs = uicfg.primaryview_section |
|
38 _pvs.tag_attribute(('CWUser', 'login'), 'hidden') |
|
39 |
|
40 _affk = uicfg.autoform_field_kwargs |
|
41 _affk.tag_subject_of(('CWUser', 'in_group', 'CWGroup'), |
|
42 {'widget': formwidgets.InOutWidget}) |
|
43 |
|
44 class UserPreferencesEntityAction(action.Action): |
|
45 __regid__ = 'prefs' |
|
46 __select__ = (one_line_rset() & is_instance('CWUser') & |
|
47 match_user_groups('owners', 'managers')) |
|
48 |
|
49 title = _('preferences') |
|
50 category = 'mainactions' |
|
51 |
|
52 def url(self): |
|
53 user = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) |
|
54 return user.absolute_url(vid='propertiesform') |
|
55 |
|
56 |
|
57 class FoafView(EntityView): |
|
58 __regid__ = 'foaf' |
|
59 __select__ = is_instance('CWUser') |
|
60 |
|
61 title = _('foaf') |
|
62 templatable = False |
|
63 content_type = 'text/xml' |
|
64 |
|
65 def call(self): |
|
66 self.w(u'''<?xml version="1.0" encoding="%s"?> |
|
67 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
|
68 xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#" |
|
69 xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self._cw.encoding) |
|
70 for i in range(self.cw_rset.rowcount): |
|
71 self.cell_call(i, 0) |
|
72 self.w(u'</rdf:RDF>\n') |
|
73 |
|
74 def entity_call(self, entity, **kwargs): |
|
75 entity.complete() |
|
76 # account |
|
77 self.w(u'<foaf:OnlineAccount rdf:about="%s">\n' % entity.absolute_url()) |
|
78 self.w(u' <foaf:accountName>%s</foaf:accountName>\n' % entity.login) |
|
79 self.w(u'</foaf:OnlineAccount>\n') |
|
80 # person |
|
81 self.w(u'<foaf:Person rdf:about="%s#user">\n' % entity.absolute_url()) |
|
82 self.w(u' <foaf:account rdf:resource="%s" />\n' % entity.absolute_url()) |
|
83 if entity.surname: |
|
84 self.w(u'<foaf:familyName>%s</foaf:familyName>\n' |
|
85 % xml_escape(entity.surname)) |
|
86 if entity.firstname: |
|
87 self.w(u'<foaf:givenName>%s</foaf:givenName>\n' |
|
88 % xml_escape(entity.firstname)) |
|
89 emailaddr = entity.cw_adapt_to('IEmailable').get_email() |
|
90 if emailaddr: |
|
91 self.w(u'<foaf:mbox_sha1sum>%s</foaf:mbox_sha1sum>\n' |
|
92 % sha1(emailaddr.encode('utf-8')).hexdigest()) |
|
93 self.w(u'</foaf:Person>\n') |
|
94 |
|
95 |
|
96 # group views ################################################################## |
|
97 |
|
98 _pvs.tag_attribute(('CWGroup', 'name'), 'hidden') |
|
99 _pvs.tag_subject_of(('CWGroup', 'read_permission', '*'), 'relations') |
|
100 _pvs.tag_subject_of(('CWGroup', 'add_permission', '*'), 'relations') |
|
101 _pvs.tag_subject_of(('CWGroup', 'delete_permission', '*'), 'relations') |
|
102 _pvs.tag_subject_of(('CWGroup', 'update_permission', '*'), 'relations') |
|
103 _pvs.tag_object_of(('CWUser', 'in_group', 'CWGroup'), 'hidden') |
|
104 _pvs.tag_object_of(('*', 'require_group', 'CWGroup'), 'hidden') |
|
105 |
|
106 |
|
107 class CWGroupPrimaryView(tabs.TabbedPrimaryView): |
|
108 __select__ = is_instance('CWGroup') |
|
109 tabs = [_('cwgroup-main'), _('cwgroup-permissions')] |
|
110 default_tab = 'cwgroup-main' |
|
111 |
|
112 |
|
113 class CWGroupMainTab(tabs.PrimaryTab): |
|
114 __regid__ = 'cwgroup-main' |
|
115 __select__ = tabs.PrimaryTab.__select__ & is_instance('CWGroup') |
|
116 |
|
117 def render_entity_attributes(self, entity): |
|
118 rset = self._cw.execute( |
|
119 'Any U, FN, LN, CD, LL ORDERBY L WHERE U in_group G, ' |
|
120 'U login L, U firstname FN, U surname LN, U creation_date CD, ' |
|
121 'U last_login_time LL, G eid %(x)s', {'x': entity.eid}) |
|
122 self.wview('cwgroup.users', rset, 'null') |
|
123 |
|
124 class CWGroupUsersTable(tableview.RsetTableView): |
|
125 __regid__ = 'cwgroup.users' |
|
126 __select__ = is_instance('CWUser') |
|
127 headers = (_(u'user'), _(u'first name'), _(u'last name'), |
|
128 _(u'creation date'), _(u'last login time')) |
|
129 layout_args = {'display_filter': 'top'} |
|
130 finalvid = 'editable-final' |
|
131 |
|
132 |
|
133 class CWGroupPermTab(EntityView): |
|
134 __regid__ = 'cwgroup-permissions' |
|
135 __select__ = is_instance('CWGroup') |
|
136 |
|
137 def entity_call(self, entity): |
|
138 self._cw.add_css(('cubicweb.schema.css','cubicweb.acl.css')) |
|
139 access_types = ('read', 'delete', 'add', 'update') |
|
140 w = self.w |
|
141 objtype_access = {'CWEType': ('read', 'delete', 'add', 'update'), |
|
142 'CWRelation': ('add', 'delete')} |
|
143 rql_cwetype = 'DISTINCT Any X WHERE X %s_permission CWG, X is CWEType, ' \ |
|
144 'CWG eid %%(e)s' |
|
145 rql_cwrelation = 'DISTINCT Any RT WHERE X %s_permission CWG, X is CWRelation, ' \ |
|
146 'X relation_type RT, CWG eid %%(e)s' |
|
147 self.render_objtype_access(entity, 'CWEType', objtype_access, rql_cwetype) |
|
148 self.render_objtype_access(entity, 'CWRelation', objtype_access, rql_cwrelation) |
|
149 |
|
150 def render_objtype_access(self, entity, objtype, objtype_access, rql): |
|
151 self.w(u'<h4>%s</h4>' % self._cw._(objtype)) |
|
152 for access_type in objtype_access[objtype]: |
|
153 rset = self._cw.execute(rql % access_type, {'e': entity.eid}) |
|
154 if rset: |
|
155 self.w(u'<div>%s:</div>' % self._cw.__(access_type + '_permission')) |
|
156 self.w(u'<div>%s</div><br/>' % self._cw.view('csv', rset, 'null')) |
|
157 |
|
158 |
|
159 class CWGroupInContextView(EntityView): |
|
160 __regid__ = 'incontext' |
|
161 __select__ = is_instance('CWGroup') |
|
162 |
|
163 def entity_call(self, entity, **kwargs): |
|
164 entity.complete() |
|
165 self.w(u'<a href="%s" class="%s">%s</a>' % ( |
|
166 entity.absolute_url(), xml_escape(entity.name), |
|
167 entity.printable_value('name'))) |
|
168 |
|
169 |
|
170 # user / groups management views ############################################### |
|
171 |
|
172 class ManageUsersAction(actions.ManagersAction): |
|
173 __regid__ = 'cwuser' # see rewrite rule /cwuser |
|
174 title = _('users and groups') |
|
175 category = 'manage' |
|
176 |
|
177 |
|
178 class UsersAndGroupsManagementView(tabs.TabsMixin, StartupView): |
|
179 __regid__ = 'cw.users-and-groups-management' |
|
180 __select__ = StartupView.__select__ & match_user_groups('managers') |
|
181 title = _('Users and groups management') |
|
182 tabs = [_('cw.users-management'), _('cw.groups-management'),] |
|
183 default_tab = 'cw.users-management' |
|
184 |
|
185 def call(self, **kwargs): |
|
186 """The default view representing the instance's management""" |
|
187 self.w(u'<h1>%s</h1>' % self._cw._(self.title)) |
|
188 self.render_tabs(self.tabs, self.default_tab) |
|
189 |
|
190 |
|
191 class CWUserManagementView(StartupView): |
|
192 __regid__ = 'cw.users-management' |
|
193 __select__ = StartupView.__select__ & match_user_groups('managers') |
|
194 cache_max_age = 0 # disable caching |
|
195 # XXX one could wish to display for instance only user's firstname/surname |
|
196 # for non managers but filtering out NULL caused crash with an ldapuser |
|
197 # source. The ldapuser source has been dropped and this code can be updated. |
|
198 rql = ('Any U,US,F,S,U,UAA,UDS, L,UAA,USN,UDSN ORDERBY L WHERE U is CWUser, ' |
|
199 'U login L, U firstname F, U surname S, ' |
|
200 'U in_state US, US name USN, ' |
|
201 'U primary_email UA?, UA address UAA, ' |
|
202 'U cw_source UDS, US name UDSN') |
|
203 |
|
204 def call(self, **kwargs): |
|
205 self.w(add_etype_button(self._cw, 'CWUser')) |
|
206 self.w(u'<div class="clear"></div>') |
|
207 self.wview('cw.users-table', self._cw.execute(self.rql)) |
|
208 |
|
209 |
|
210 class CWUsersTable(tableview.EntityTableView): |
|
211 __regid__ = 'cw.users-table' |
|
212 __select__ = is_instance('CWUser') |
|
213 columns = ['user', 'in_state', 'firstname', 'surname', |
|
214 'in_group', 'primary_email', 'cw_source'] |
|
215 layout_args = {'display_filter': 'top'} |
|
216 finalvid = 'editable-final' |
|
217 |
|
218 column_renderers = { |
|
219 'user': tableview.EntityTableColRenderer( |
|
220 renderfunc=lambda w,x: w(tags.a(x.login, href=x.absolute_url())), |
|
221 sortfunc=lambda x: x.login), |
|
222 'in_state': tableview.EntityTableColRenderer( |
|
223 renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state), |
|
224 sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state), |
|
225 'in_group': tableview.EntityTableColRenderer( |
|
226 renderfunc=lambda w,x: x.view('reledit', rtype='in_group', role='subject', w=w)), |
|
227 'primary_email': tableview.RelatedEntityColRenderer( |
|
228 getrelated=lambda x:x.primary_email and x.primary_email[0] or None), |
|
229 'cw_source': tableview.RelatedEntityColRenderer( |
|
230 getrelated=lambda x: x.cw_source[0]), |
|
231 } |
|
232 |
|
233 |
|
234 class CWGroupsManagementView(StartupView): |
|
235 __regid__ = 'cw.groups-management' |
|
236 __select__ = StartupView.__select__ & match_user_groups('managers') |
|
237 cache_max_age = 0 # disable caching |
|
238 rql = ('Any G,GN ORDERBY GN WHERE G is CWGroup, G name GN, NOT G name "owners"') |
|
239 |
|
240 def call(self, **kwargs): |
|
241 self.w(add_etype_button(self._cw, 'CWGroup')) |
|
242 self.w(u'<div class="clear"></div>') |
|
243 self.wview('cw.groups-table', self._cw.execute(self.rql)) |
|
244 |
|
245 |
|
246 class CWGroupsTable(tableview.EntityTableView): |
|
247 __regid__ = 'cw.groups-table' |
|
248 __select__ = is_instance('CWGroup') |
|
249 columns = ['group', 'nb_users'] |
|
250 layout_args = {'display_filter': 'top'} |
|
251 |
|
252 column_renderers = { |
|
253 'group': tableview.MainEntityColRenderer(), |
|
254 'nb_users': tableview.EntityTableColRenderer( |
|
255 header=_('num. users'), |
|
256 renderfunc=lambda w,x: w(text_type(x.num_users())), |
|
257 sortfunc=lambda x: x.num_users()), |
|
258 } |