Browse Source

improve a bit user/workspace admin screen

Damien ACCORSI 8 years ago
parent
commit
dd84222efd

+ 56 - 3
tracim/tracim/controllers/admin/user.py View File

@@ -18,6 +18,8 @@ from formencode import Schema
18 18
 from formencode.validators import FieldsMatch
19 19
 
20 20
 from tracim.controllers import TIMRestController
21
+from tracim.controllers.user import UserWorkspaceRestController
22
+
21 23
 from tracim.lib import CST
22 24
 from tracim.lib import helpers as h
23 25
 from tracim.lib.base import logger
@@ -212,6 +214,52 @@ class UserPasswordAdminRestController(TIMRestController):
212 214
         tg.redirect(next_url)
213 215
 
214 216
 
217
+class UserWorkspaceRestController(TIMRestController):
218
+
219
+    def _before(self, *args, **kw):
220
+        """
221
+        Instantiate the current workspace in tg.tmpl_context
222
+        :param args:
223
+        :param kw:
224
+        :return:
225
+        """
226
+        super(self.__class__, self)._before(args, kw)
227
+
228
+        api = UserApi(tg.tmpl_context.current_user)
229
+        user_id = tg.request.controller_state.routing_args.get('user_id')
230
+        user = api.get_one(user_id)
231
+        tg.tmpl_context.user_id = user_id
232
+        tg.tmpl_context.user = user
233
+
234
+    @tg.expose()
235
+    def enable_notifications(self, workspace_id, next_url=None):
236
+        workspace_id = int(workspace_id)
237
+        api = WorkspaceApi(tg.tmpl_context.current_user)
238
+
239
+        workspace = api.get_one(workspace_id)
240
+        api.enable_notifications(tg.tmpl_context.user, workspace)
241
+        tg.flash(_('User {}: notification enabled for workspace {}').format(
242
+            tg.tmpl_context.user.get_display_name(), workspace.label))
243
+
244
+        if next_url:
245
+            tg.redirect(tg.url(next_url))
246
+        tg.redirect(self.parent_controller.url(None, 'me'))
247
+
248
+    @tg.expose()
249
+    def disable_notifications(self, workspace_id, next_url=None):
250
+        workspace_id = int(workspace_id)
251
+        api = WorkspaceApi(tg.tmpl_context.current_user)
252
+
253
+        workspace = api.get_one(workspace_id)
254
+        api.disable_notifications(tg.tmpl_context.user, workspace)
255
+        tg.flash(_('User {}: notification disabled for workspace {}').format(
256
+            tg.tmpl_context.user.get_display_name(), workspace.label))
257
+
258
+        if next_url:
259
+            tg.redirect(tg.url(next_url))
260
+        tg.redirect(self.parent_controller.url(None, 'me'))
261
+
262
+
215 263
 class UserRestController(TIMRestController):
216 264
     """
217 265
      CRUD Controller allowing to manage Users
@@ -220,6 +268,7 @@ class UserRestController(TIMRestController):
220 268
 
221 269
     password = UserPasswordAdminRestController()
222 270
     profile = UserProfileAdminRestController()
271
+    workspaces = UserWorkspaceRestController()
223 272
 
224 273
     @classmethod
225 274
     def current_item_id_key_in_context(cls):
@@ -289,10 +338,14 @@ class UserRestController(TIMRestController):
289 338
 
290 339
         user = api.get_one(user_id) # FIXME
291 340
 
292
-        dictified_user = Context(CTX.USER).toDict(user, 'user')
341
+        role_api = RoleApi(tg.tmpl_context.current_user)
342
+        role_list = role_api.get_roles_for_select_field()
343
+
344
+        dictified_user = Context(CTX.ADMIN_USER).toDict(user, 'user')
293 345
         current_user_content = Context(CTX.CURRENT_USER).toDict(tmpl_context.current_user)
294
-        fake_api_content = DictLikeClass(current_user=current_user_content)
295
-        fake_api = Context(CTX.WORKSPACE).toDict(fake_api_content)
346
+        fake_api_content = DictLikeClass(current_user=current_user_content,
347
+                                         role_types=role_list)
348
+        fake_api = Context(CTX.ADMIN_USER).toDict(fake_api_content)
296 349
 
297 350
         return DictLikeClass(result = dictified_user, fake_api=fake_api)
298 351
 

+ 5 - 6
tracim/tracim/controllers/admin/workspace.py View File

@@ -54,7 +54,6 @@ class RoleInWorkspaceRestController(TIMRestController, BaseController):
54 54
     def get_one(self, user_id):
55 55
         pass
56 56
 
57
-
58 57
     def put(self, *args, **kw):
59 58
         pass
60 59
 
@@ -90,22 +89,22 @@ class RoleInWorkspaceRestController(TIMRestController, BaseController):
90 89
     def undelete(self, user_id, old_role):
91 90
         user_id = int(user_id)
92 91
         role_id = int(old_role)
93
-        self._add_user_with_role(user_id, role_id, _('User {} restored in workspace {} as {}'))
92
+        self._add_user_with_role(user_id, role_id, None, _('User {} restored in workspace {} as {}'))
94 93
         tg.redirect(self.parent_controller.url(tg.tmpl_context.workspace_id))
95 94
 
96 95
     @tg.expose()
97
-    def post(self, user_id, role_id):
96
+    def post(self, user_id, role_id, with_notif=False):
98 97
         user_id = int(user_id)
99 98
         role_id = int(role_id)
100
-        self._add_user_with_role(user_id, role_id, _('User {} added to workspace {} as {}'))
99
+        self._add_user_with_role(user_id, role_id, with_notif, _('User {} added to workspace {} as {}'))
101 100
         tg.redirect(self.parent_controller.url(tg.tmpl_context.workspace_id))
102 101
 
103
-    def _add_user_with_role(self, user_id: int, role_id: int, flash_msg_template)-> UserRoleInWorkspace:
102
+    def _add_user_with_role(self, user_id: int, role_id: int, with_notif: bool, flash_msg_template)-> UserRoleInWorkspace:
104 103
         user_api = UserApi(tg.tmpl_context.current_user)
105 104
         user = user_api.get_one(user_id)
106 105
 
107 106
         role_api = RoleApi(tg.tmpl_context.current_user)
108
-        role = role_api.create_one(user, tg.tmpl_context.workspace, role_id)
107
+        role = role_api.create_one(user, tg.tmpl_context.workspace, role_id, with_notif)
109 108
 
110 109
         tg.flash(flash_msg_template.format(
111 110
             role.user.get_display_name(),

+ 3 - 1
tracim/tracim/lib/userworkspace.py View File

@@ -50,11 +50,13 @@ class RoleApi(object):
50 50
     def get_one(self, user_id, workspace_id):
51 51
         return self._get_one_rsc(user_id, workspace_id).one()
52 52
 
53
-    def create_one(self, user: User, workspace: Workspace, role_level: int, flush: bool=True) -> UserRoleInWorkspace:
53
+    def create_one(self, user: User, workspace: Workspace, role_level: int, with_notif: bool, flush: bool=True) -> UserRoleInWorkspace:
54 54
         role = self.create_role()
55 55
         role.user_id = user.user_id
56 56
         role.workspace = workspace
57 57
         role.role = role_level
58
+        if with_notif is not None:
59
+            role.do_notify = with_notif
58 60
         if flush:
59 61
             DBSession.flush()
60 62
         return role

+ 8 - 3
tracim/tracim/model/serializers.py View File

@@ -62,6 +62,7 @@ class ContextConverterNotFoundException(Exception):
62 62
 
63 63
 class CTX(object):
64 64
     """ constants that are used for serialization / dictification of models"""
65
+    ADMIN_USER = 'ADMIN_USER'
65 66
     ADMIN_WORKSPACE = 'ADMIN_WORKSPACE'
66 67
     ADMIN_WORKSPACES = 'ADMIN_WORKSPACES'
67 68
     CONTENT_LIST = 'CONTENT_LIST'
@@ -785,6 +786,7 @@ def serialize_user_list_default(profile: Profile, context: Context):
785 786
 
786 787
 
787 788
 @pod_serializer(RoleType, CTX.ADMIN_WORKSPACE)
789
+@pod_serializer(RoleType, CTX.ADMIN_USER)
788 790
 def serialize_role_list_for_select_field_in_workspace(role_type: RoleType, context: Context):
789 791
     """
790 792
     Actually, roles are serialized as users (with minimal information)
@@ -838,6 +840,7 @@ def serialize_user_list_default(user: User, context: Context):
838 840
 
839 841
 
840 842
 @pod_serializer(User, CTX.USER)
843
+@pod_serializer(User, CTX.ADMIN_USER)
841 844
 @pod_serializer(User, CTX.CURRENT_USER)
842 845
 def serialize_user_for_user(user: User, context: Context):
843 846
     """
@@ -876,13 +879,14 @@ def serialize_role_in_workspace(role: UserRoleInWorkspace, context: Context):
876 879
     result['style'] = role.style
877 880
     result['role_description'] = role.role_as_label()
878 881
     result['email'] = role.user.email
879
-    result['user'] = role.user
882
+    result['user'] = context.toDict(role.user)
880 883
     result['notifications_subscribed'] = role.do_notify
881 884
     return result
882 885
 
883 886
 
884 887
 @pod_serializer(UserRoleInWorkspace, CTX.USER)
885 888
 @pod_serializer(UserRoleInWorkspace, CTX.CURRENT_USER)
889
+@pod_serializer(UserRoleInWorkspace, CTX.ADMIN_USER)
886 890
 def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context):
887 891
     """
888 892
     Actually, roles are serialized as users (with minimal information)
@@ -896,7 +900,7 @@ def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context)
896 900
     result['label'] = role.role_as_label()
897 901
     result['style'] = RoleType(role.role).css_style
898 902
     result['workspace'] =  context.toDict(role.workspace)
899
-    result['user'] = role.user
903
+    result['user'] = Context(CTX.DEFAULT).toDict(role.user)
900 904
     result['notifications_subscribed'] = role.do_notify
901 905
 
902 906
     # result['workspace_name'] = role.workspace.label
@@ -910,7 +914,8 @@ def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context)
910 914
 def serialize_workspace_default(workspace: Workspace, context: Context):
911 915
     result = DictLikeClass(
912 916
         id = workspace.workspace_id,
913
-        label = workspace.label,
917
+        label = workspace.label,  # FIXME - 2015-08-20 - remove this property
918
+        name = workspace.label,  # use name instead of label
914 919
         url = context.url('/workspaces/{}'.format(workspace.workspace_id))
915 920
     )
916 921
     return result

+ 6 - 2
tracim/tracim/templates/admin/user_getone.mak View File

@@ -61,7 +61,7 @@
61 61
                             ${ICON.FA('fa-bar-chart t-less-visible')}
62 62
                             ${_('Global profile')}
63 63
                         </h3>
64
-                        ${P.USER_PROFILE(result.user)}
64
+                        ${P.USER_PROFILE(fake_api.current_user, result.user)}
65 65
                     </div>
66 66
                     <div style="margin-top: 4em;">
67 67
                         <h3>
@@ -81,7 +81,11 @@
81 81
                                     </tr>
82 82
                                 </thead>
83 83
                                 % for role in result.user.roles:
84
-                                    ${TABLE_ROW.USER_ROLE_IN_WORKSPACE(role)}
84
+<%
85
+    enable_link = '/admin/users/{user}/workspaces/{workspace}/enable_notifications?next_url=/admin/users/{user}'
86
+    disable_link = '/admin/users/{user}/workspaces/{workspace}/disable_notifications?next_url=/admin/users/{user}'
87
+%>
88
+                                    ${TABLE_ROW.USER_ROLE_IN_WORKSPACE(fake_api.current_user, role, show_id=True, enable_link=enable_link, disable_link=disable_link)}
85 89
                                 % endfor
86 90
                             </table>
87 91
                         % endif

+ 6 - 0
tracim/tracim/templates/admin/workspace_getone.mak View File

@@ -83,6 +83,12 @@
83 83
                                             % endfor
84 84
                                         </div>
85 85
 
86
+                                        <div class="checkbox">
87
+                                            <label>
88
+                                                <input type="checkbox" id="with_notif" name="with_notif" checked="checked"/> ${_('Subscribe to mail notifications')}
89
+                                            </label>
90
+                                        </div>
91
+
86 92
                                         <span class="pull-right" style="margin-top: 0.5em;">
87 93
                                             <button id="current-document-add-comment-save-button" type="submit" class="btn btn-small btn-success" title="Add first comment"><i class=" fa fa-check"></i> ${_('Validate')}</button>
88 94
                                         </span>

+ 1 - 1
tracim/tracim/templates/home.mak View File

@@ -157,7 +157,7 @@
157 157
                                                 </tr>
158 158
                                             </thead>
159 159
                                             % for role in fake_api.current_user.roles:
160
-                                                ${TABLE_ROW.USER_ROLE_IN_WORKSPACE(role, show_id=False, enable_link='/user/me/workspaces/{workspace}/enable_notifications?next_url=/home', disable_link='/user/me/workspaces/{workspace}/disable_notifications?next_url=/home')}
160
+                                                ${TABLE_ROW.USER_ROLE_IN_WORKSPACE(fake_api.current_user, role, show_id=False, enable_link='/user/me/workspaces/{workspace}/enable_notifications?next_url=/home', disable_link='/user/me/workspaces/{workspace}/disable_notifications?next_url=/home')}
161 161
                                             % endfor
162 162
                                         </table>
163 163
                                     % endif

+ 1 - 1
tracim/tracim/templates/user_get_me.mak View File

@@ -62,7 +62,7 @@
62 62
                             </table>
63 63
                         % endif
64 64
                     </div>
65
-                    % if len(result.user.roles)>0:
65
+                    % if len(result.user.roles) > 0:
66 66
                         <p class="alert alert-info">${_('You can configure your email notifications by clicking on the email icons above')}</p>
67 67
                     % endif
68 68
                 </div>

+ 1 - 1
tracim/tracim/templates/widgets/paragraph.mak View File

@@ -1,7 +1,7 @@
1 1
 <%namespace name="ICON" file="tracim.templates.widgets.icon"/>
2 2
 <%namespace name="BUTTON" file="tracim.templates.widgets.button"/>
3 3
 
4
-<%def name="USER_PROFILE(user)">
4
+<%def name="USER_PROFILE(current_user, user)">
5 5
     % if user.profile.id >= 1:
6 6
         <p>${ICON.FA('fa-male t-green fa-lg fa-fw')}<span> ${_('This user a standard user.')}</span></p>
7 7
     %else:

+ 30 - 4
tracim/tracim/templates/widgets/table_row.mak View File

@@ -2,14 +2,27 @@
2 2
 <%namespace name="ICON" file="tracim.templates.widgets.icon"/>
3 3
 <%namespace name="SPAN" file="tracim.templates.widgets.span"/>
4 4
 
5
-<%def name="USER_ROLE_IN_WORKSPACE(role, show_id=True, enable_link=None, disable_link=None)">
5
+<%def name="USER_ROLE_IN_WORKSPACE(current_user, role, show_id=True, enable_link=None, disable_link=None, role_types=None)">
6 6
     <tr>
7 7
         % if show_id:
8 8
             <td class="text-right">${role.workspace.id}</td>
9 9
         % endif
10 10
         <td><a href="${tg.url('/admin/workspaces/{}').format(role.workspace.id)}">${role.workspace.name}</a></td>
11
-        <td><span style="${role.style}"><i class="fa ${role.icon}"></i> ${role.label}</span></td>
12
-        % if enable_link or disable_link:
11
+
12
+        % if role_types:
13
+            ## <td>${BUTTON.SECURED_ROLE_SELECTOR(fake_api.current_user, result.workspace, member, fake_api.role_types)}</td>
14
+            <td><span style="${role.style}"><i class="fa ${role.icon}"></i> ${role.label}</span></td>
15
+        % else:
16
+            <td><span style="${role.style}"><i class="fa ${role.icon}"></i> ${role.label}</span></td>
17
+        % endif
18
+
19
+        <%
20
+            user_is_himself = current_user.id == role.user.id
21
+            user_is_manager = h.user_role(current_user, role.workspace) >= 8
22
+            ## allow user to change notification status only if current user is manager on the given workspace
23
+        %>
24
+
25
+        % if (enable_link or disable_link) and (user_is_himself or user_is_manager) :
13 26
             <td>${SPAN.NOTIFICATION_SUBSCRIBED(role.user, role.workspace, role.notifications_subscribed, enable_link, disable_link)}</td>
14 27
         % else:
15 28
             <td>${SPAN.NOTIFICATION_SUBSCRIBED(role.user, role.workspace, role.notifications_subscribed)}</td>
@@ -23,7 +36,20 @@
23 36
         <td class="text-right">${member.id}</td>
24 37
         <td ><a href="${tg.url('/admin/users/{}'.format(member.id))}">${member.name}</a></td>
25 38
         <td>${BUTTON.SECURED_ROLE_SELECTOR(fake_api.current_user, result.workspace, member, fake_api.role_types)}</td>
26
-        <td>${SPAN.NOTIFICATION_SUBSCRIBED(member, workspace, member.notifications_subscribed)}</td>
39
+        <%
40
+            user_is_himself = current_user.id == member.id
41
+            user_is_manager = h.user_role(current_user, workspace) >= 8
42
+            ## allow user to change notification status only if current user is manager on the given workspace
43
+
44
+            enable_link = '/admin/users/{user}/workspaces/{workspace}/enable_notifications?next_url=/admin/workspaces/{workspace}'
45
+            disable_link = '/admin/users/{user}/workspaces/{workspace}/disable_notifications?next_url=/admin/workspaces/{workspace}'
46
+        %>
47
+        % if (enable_link or disable_link) and (user_is_himself or user_is_manager) :
48
+            <td>${SPAN.NOTIFICATION_SUBSCRIBED(member, workspace, member.notifications_subscribed, enable_link, disable_link)}</td>
49
+        % else:
50
+            <td>${SPAN.NOTIFICATION_SUBSCRIBED(member, workspace, member.notifications_subscribed)}</td>
51
+        % endif
52
+
27 53
         <td><a title="${_('Remove this user from the current workspace')}" class="t-less-visible t-red-on-hover t-red btn btn-default btn-xs" href="${tg.url('/admin/workspaces/{}/roles/{}/delete'.format(result.workspace.id, member.id))}">${ICON.FA('fa-remove fa-fw')}</a></td>
28 54
     </tr>
29 55
 </%def>