Просмотр исходного кода

Merge pull request #30 from tracim/fix/834_endpoint_enable_disable_notification

Bastien Sevajol 5 лет назад
Родитель
Сommit
26d032cbcc
Аккаунт пользователя с таким Email не найден

+ 1 - 5
backend/tracim_backend/models/context_models.py Просмотреть файл

169
     """
169
     """
170
     def __init__(self, workspace_id: int, user_id: int):
170
     def __init__(self, workspace_id: int, user_id: int):
171
         self.workspace_id = workspace_id
171
         self.workspace_id = workspace_id
172
-        self.user_id = workspace_id
172
+        self.user_id = user_id
173
 
173
 
174
 
174
 
175
 class UserWorkspaceAndContentPath(object):
175
 class UserWorkspaceAndContentPath(object):
266
     def __init__(
266
     def __init__(
267
         self,
267
         self,
268
         role: str,
268
         role: str,
269
-        do_notify: bool,
270
     ):
269
     ):
271
         self.role = role
270
         self.role = role
272
-        self.do_notify = do_notify
273
 
271
 
274
 
272
 
275
 class WorkspaceMemberInvitation(object):
273
 class WorkspaceMemberInvitation(object):
281
         user_id: int,
279
         user_id: int,
282
         user_email_or_public_name: str,
280
         user_email_or_public_name: str,
283
         role: str,
281
         role: str,
284
-        do_notify: str,
285
     ):
282
     ):
286
         self.role = role
283
         self.role = role
287
         self.user_email_or_public_name = user_email_or_public_name
284
         self.user_email_or_public_name = user_email_or_public_name
288
         self.user_id = user_id
285
         self.user_id = user_id
289
-        self.do_notify = do_notify
290
 
286
 
291
 
287
 
292
 class WorkspaceUpdate(object):
288
 class WorkspaceUpdate(object):

+ 439 - 1
backend/tracim_backend/tests/functional/test_user.py Просмотреть файл

2382
         )
2382
         )
2383
 
2383
 
2384
 
2384
 
2385
+class TestUserEnableWorkspaceNotification(FunctionalTest):
2386
+    """
2387
+    Tests for /api/v2/users/{user_id}/workspaces/{workspace_id}/notify
2388
+    """
2389
+    def test_api_enable_user_workspace_notification__ok__200__admin(self):
2390
+        # init DB
2391
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2392
+        admin = dbsession.query(models.User) \
2393
+            .filter(models.User.email == 'admin@admin.admin') \
2394
+            .one()
2395
+        workspace_api = WorkspaceApi(
2396
+            current_user=admin,
2397
+            session=dbsession,
2398
+            config=self.app_config
2399
+
2400
+        )
2401
+        workspace = WorkspaceApi(
2402
+            current_user=admin,
2403
+            session=dbsession,
2404
+            config=self.app_config,
2405
+        ).create_workspace(
2406
+            'test workspace',
2407
+            save_now=True
2408
+        )
2409
+        uapi = UserApi(
2410
+            current_user=admin,
2411
+            session=dbsession,
2412
+            config=self.app_config,
2413
+        )
2414
+        gapi = GroupApi(
2415
+            current_user=admin,
2416
+            session=dbsession,
2417
+            config=self.app_config,
2418
+        )
2419
+        groups = [gapi.get_one_with_name('users')]
2420
+        test_user = uapi.create_user(
2421
+            email='test@test.test',
2422
+            password='pass',
2423
+            name='bob',
2424
+            groups=groups,
2425
+            timezone='Europe/Paris',
2426
+            lang='fr',
2427
+            do_save=True,
2428
+            do_notify=False,
2429
+        )
2430
+        rapi = RoleApi(
2431
+            current_user=admin,
2432
+            session=dbsession,
2433
+            config=self.app_config,
2434
+        )
2435
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=False)  # nopep8
2436
+        transaction.commit()
2437
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2438
+        assert role.do_notify is False
2439
+        self.testapp.authorization = (
2440
+            'Basic',
2441
+            (
2442
+                'admin@admin.admin',
2443
+                'admin@admin.admin'
2444
+            )
2445
+        )
2446
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/notify'.format(  # nopep8
2447
+            user_id=test_user.user_id,
2448
+            workspace_id=workspace.workspace_id
2449
+        ), status=204)
2450
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2451
+        rapi = RoleApi(
2452
+            current_user=admin,
2453
+            session=dbsession,
2454
+            config=self.app_config,
2455
+        )
2456
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2457
+        assert role.do_notify is True
2458
+
2459
+    def test_api_enable_user_workspace_notification__ok__200__user_itself(self):
2460
+        # init DB
2461
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2462
+        admin = dbsession.query(models.User) \
2463
+            .filter(models.User.email == 'admin@admin.admin') \
2464
+            .one()
2465
+        workspace_api = WorkspaceApi(
2466
+            current_user=admin,
2467
+            session=dbsession,
2468
+            config=self.app_config
2469
+
2470
+        )
2471
+        workspace = WorkspaceApi(
2472
+            current_user=admin,
2473
+            session=dbsession,
2474
+            config=self.app_config,
2475
+        ).create_workspace(
2476
+            'test workspace',
2477
+            save_now=True
2478
+        )
2479
+        uapi = UserApi(
2480
+            current_user=admin,
2481
+            session=dbsession,
2482
+            config=self.app_config,
2483
+        )
2484
+        gapi = GroupApi(
2485
+            current_user=admin,
2486
+            session=dbsession,
2487
+            config=self.app_config,
2488
+        )
2489
+        groups = [gapi.get_one_with_name('users')]
2490
+        test_user = uapi.create_user(
2491
+            email='test@test.test',
2492
+            password='pass',
2493
+            name='bob',
2494
+            groups=groups,
2495
+            timezone='Europe/Paris',
2496
+            lang='fr',
2497
+            do_save=True,
2498
+            do_notify=False,
2499
+        )
2500
+        rapi = RoleApi(
2501
+            current_user=admin,
2502
+            session=dbsession,
2503
+            config=self.app_config,
2504
+        )
2505
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=False)  # nopep8
2506
+        transaction.commit()
2507
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2508
+        assert role.do_notify is False
2509
+        self.testapp.authorization = (
2510
+            'Basic',
2511
+            (
2512
+                'test@test.test',
2513
+                'pass',
2514
+            )
2515
+        )
2516
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/notify'.format(  # nopep8
2517
+            user_id=test_user.user_id,
2518
+            workspace_id=workspace.workspace_id
2519
+        ), status=204)
2520
+
2521
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2522
+        rapi = RoleApi(
2523
+            current_user=admin,
2524
+            session=dbsession,
2525
+            config=self.app_config,
2526
+        )
2527
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2528
+        assert role.do_notify is True
2529
+
2530
+    def test_api_enable_user_workspace_notification__err__403__other_user(self):
2531
+        # init DB
2532
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2533
+        admin = dbsession.query(models.User) \
2534
+            .filter(models.User.email == 'admin@admin.admin') \
2535
+            .one()
2536
+        workspace_api = WorkspaceApi(
2537
+            current_user=admin,
2538
+            session=dbsession,
2539
+            config=self.app_config
2540
+
2541
+        )
2542
+        workspace = WorkspaceApi(
2543
+            current_user=admin,
2544
+            session=dbsession,
2545
+            config=self.app_config,
2546
+        ).create_workspace(
2547
+            'test workspace',
2548
+            save_now=True
2549
+        )
2550
+        uapi = UserApi(
2551
+            current_user=admin,
2552
+            session=dbsession,
2553
+            config=self.app_config,
2554
+        )
2555
+        gapi = GroupApi(
2556
+            current_user=admin,
2557
+            session=dbsession,
2558
+            config=self.app_config,
2559
+        )
2560
+        groups = [gapi.get_one_with_name('users')]
2561
+        test_user = uapi.create_user(
2562
+            email='test@test.test',
2563
+            password='pass',
2564
+            name='bob',
2565
+            groups=groups,
2566
+            timezone='Europe/Paris',
2567
+            lang='fr',
2568
+            do_save=True,
2569
+            do_notify=False,
2570
+        )
2571
+        test_user2 = uapi.create_user(
2572
+            email='test2@test2.test2',
2573
+            password='pass',
2574
+            name='boby',
2575
+            groups=groups,
2576
+            timezone='Europe/Paris',
2577
+            lang='fr',
2578
+            do_save=True,
2579
+            do_notify=False,
2580
+        )
2581
+        rapi = RoleApi(
2582
+            current_user=admin,
2583
+            session=dbsession,
2584
+            config=self.app_config,
2585
+        )
2586
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=False)  # nopep8
2587
+        rapi.create_one(test_user2, workspace, UserRoleInWorkspace.READER, with_notif=False)  # nopep8
2588
+        transaction.commit()
2589
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2590
+        assert role.do_notify is False
2591
+        self.testapp.authorization = (
2592
+            'Basic',
2593
+            (
2594
+                'test2@test2.test2',
2595
+                'pass',
2596
+            )
2597
+        )
2598
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/notify'.format(  # nopep8
2599
+            user_id=test_user.user_id,
2600
+            workspace_id=workspace.workspace_id
2601
+        ), status=403)
2602
+
2603
+
2604
+class TestUserDisableWorkspaceNotification(FunctionalTest):
2605
+    """
2606
+    Tests for /api/v2/users/{user_id}/workspaces/{workspace_id}/unnotify
2607
+    """
2608
+    def test_api_disable_user_workspace_notification__ok__200__admin(self):
2609
+        # init DB
2610
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2611
+        admin = dbsession.query(models.User) \
2612
+            .filter(models.User.email == 'admin@admin.admin') \
2613
+            .one()
2614
+        workspace_api = WorkspaceApi(
2615
+            current_user=admin,
2616
+            session=dbsession,
2617
+            config=self.app_config
2618
+
2619
+        )
2620
+        workspace = WorkspaceApi(
2621
+            current_user=admin,
2622
+            session=dbsession,
2623
+            config=self.app_config,
2624
+        ).create_workspace(
2625
+            'test workspace',
2626
+            save_now=True
2627
+        )
2628
+        uapi = UserApi(
2629
+            current_user=admin,
2630
+            session=dbsession,
2631
+            config=self.app_config,
2632
+        )
2633
+        gapi = GroupApi(
2634
+            current_user=admin,
2635
+            session=dbsession,
2636
+            config=self.app_config,
2637
+        )
2638
+        groups = [gapi.get_one_with_name('users')]
2639
+        test_user = uapi.create_user(
2640
+            email='test@test.test',
2641
+            password='pass',
2642
+            name='bob',
2643
+            groups=groups,
2644
+            timezone='Europe/Paris',
2645
+            lang='fr',
2646
+            do_save=True,
2647
+            do_notify=True,
2648
+        )
2649
+        rapi = RoleApi(
2650
+            current_user=admin,
2651
+            session=dbsession,
2652
+            config=self.app_config,
2653
+        )
2654
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=True)  # nopep8
2655
+        transaction.commit()
2656
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2657
+        assert role.do_notify is True
2658
+        self.testapp.authorization = (
2659
+            'Basic',
2660
+            (
2661
+                'admin@admin.admin',
2662
+                'admin@admin.admin'
2663
+            )
2664
+        )
2665
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/unnotify'.format(  # nopep8
2666
+            user_id=test_user.user_id,
2667
+            workspace_id=workspace.workspace_id
2668
+        ), status=204)
2669
+
2670
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2671
+        rapi = RoleApi(
2672
+            current_user=admin,
2673
+            session=dbsession,
2674
+            config=self.app_config,
2675
+        )
2676
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2677
+        assert role.do_notify is False
2678
+
2679
+    def test_api_enable_user_workspace_notification__ok__200__user_itself(self):
2680
+        # init DB
2681
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2682
+        admin = dbsession.query(models.User) \
2683
+            .filter(models.User.email == 'admin@admin.admin') \
2684
+            .one()
2685
+        workspace_api = WorkspaceApi(
2686
+            current_user=admin,
2687
+            session=dbsession,
2688
+            config=self.app_config
2689
+
2690
+        )
2691
+        workspace = WorkspaceApi(
2692
+            current_user=admin,
2693
+            session=dbsession,
2694
+            config=self.app_config,
2695
+        ).create_workspace(
2696
+            'test workspace',
2697
+            save_now=True
2698
+        )
2699
+        uapi = UserApi(
2700
+            current_user=admin,
2701
+            session=dbsession,
2702
+            config=self.app_config,
2703
+        )
2704
+        gapi = GroupApi(
2705
+            current_user=admin,
2706
+            session=dbsession,
2707
+            config=self.app_config,
2708
+        )
2709
+        groups = [gapi.get_one_with_name('users')]
2710
+        test_user = uapi.create_user(
2711
+            email='test@test.test',
2712
+            password='pass',
2713
+            name='bob',
2714
+            groups=groups,
2715
+            timezone='Europe/Paris',
2716
+            lang='fr',
2717
+            do_save=True,
2718
+            do_notify=False,
2719
+        )
2720
+        rapi = RoleApi(
2721
+            current_user=admin,
2722
+            session=dbsession,
2723
+            config=self.app_config,
2724
+        )
2725
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=True)  # nopep8
2726
+        transaction.commit()
2727
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2728
+        assert role.do_notify is True
2729
+        self.testapp.authorization = (
2730
+            'Basic',
2731
+            (
2732
+                'test@test.test',
2733
+                'pass',
2734
+            )
2735
+        )
2736
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/unnotify'.format(  # nopep8
2737
+            user_id=test_user.user_id,
2738
+            workspace_id=workspace.workspace_id
2739
+        ), status=204)
2740
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2741
+        rapi = RoleApi(
2742
+            current_user=admin,
2743
+            session=dbsession,
2744
+            config=self.app_config,
2745
+        )
2746
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2747
+        assert role.do_notify is False
2748
+
2749
+    def test_api_disable_user_workspace_notification__err__403__other_user(self):
2750
+        # init DB
2751
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2752
+        admin = dbsession.query(models.User) \
2753
+            .filter(models.User.email == 'admin@admin.admin') \
2754
+            .one()
2755
+        workspace_api = WorkspaceApi(
2756
+            current_user=admin,
2757
+            session=dbsession,
2758
+            config=self.app_config
2759
+
2760
+        )
2761
+        workspace = WorkspaceApi(
2762
+            current_user=admin,
2763
+            session=dbsession,
2764
+            config=self.app_config,
2765
+        ).create_workspace(
2766
+            'test workspace',
2767
+            save_now=True
2768
+        )
2769
+        uapi = UserApi(
2770
+            current_user=admin,
2771
+            session=dbsession,
2772
+            config=self.app_config,
2773
+        )
2774
+        gapi = GroupApi(
2775
+            current_user=admin,
2776
+            session=dbsession,
2777
+            config=self.app_config,
2778
+        )
2779
+        groups = [gapi.get_one_with_name('users')]
2780
+        test_user = uapi.create_user(
2781
+            email='test@test.test',
2782
+            password='pass',
2783
+            name='bob',
2784
+            groups=groups,
2785
+            timezone='Europe/Paris',
2786
+            lang='fr',
2787
+            do_save=True,
2788
+            do_notify=False,
2789
+        )
2790
+        test_user2 = uapi.create_user(
2791
+            email='test2@test2.test2',
2792
+            password='pass',
2793
+            name='boby',
2794
+            groups=groups,
2795
+            timezone='Europe/Paris',
2796
+            lang='fr',
2797
+            do_save=True,
2798
+            do_notify=False,
2799
+        )
2800
+        rapi = RoleApi(
2801
+            current_user=admin,
2802
+            session=dbsession,
2803
+            config=self.app_config,
2804
+        )
2805
+        rapi.create_one(test_user, workspace, UserRoleInWorkspace.READER, with_notif=True)  # nopep8
2806
+        rapi.create_one(test_user2, workspace, UserRoleInWorkspace.READER, with_notif=False)  # nopep8
2807
+        transaction.commit()
2808
+        role = rapi.get_one(test_user.user_id, workspace.workspace_id)
2809
+        assert role.do_notify is True
2810
+        self.testapp.authorization = (
2811
+            'Basic',
2812
+            (
2813
+                'test2@test2.test2',
2814
+                'pass',
2815
+            )
2816
+        )
2817
+        self.testapp.put_json('/api/v2/users/{user_id}/workspaces/{workspace_id}/unnotify'.format(  # nopep8
2818
+            user_id=test_user.user_id,
2819
+            workspace_id=workspace.workspace_id
2820
+        ), status=403)
2821
+
2822
+
2385
 class TestUserWorkspaceEndpoint(FunctionalTest):
2823
 class TestUserWorkspaceEndpoint(FunctionalTest):
2386
     """
2824
     """
2387
     Tests for /api/v2/users/{user_id}/workspaces
2825
     Tests for /api/v2/users/{user_id}/workspaces
4235
         params = {
4673
         params = {
4236
             'public_name': 'updated',
4674
             'public_name': 'updated',
4237
             'timezone': 'Europe/London',
4675
             'timezone': 'Europe/London',
4238
-            'lang' : 'en',
4676
+            'lang': 'en',
4239
         }
4677
         }
4240
         self.testapp.put_json(
4678
         self.testapp.put_json(
4241
             '/api/v2/users/{}'.format(user_id),
4679
             '/api/v2/users/{}'.format(user_id),

+ 243 - 14
backend/tracim_backend/tests/functional/test_workspaces.py Просмотреть файл

875
         assert 'details' in res.json.keys()
875
         assert 'details' in res.json.keys()
876
 
876
 
877
 
877
 
878
+class TestWorkspacesEndpoints(FunctionalTest):
879
+    """
880
+    Tests for /api/v2/workspaces
881
+    """
882
+    fixtures = [BaseFixture]
883
+
884
+    def test_api__get_workspaces__ok_200__nominal_case(self):
885
+        """
886
+        Check obtain all workspaces reachables for user with user auth.
887
+        """
888
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
889
+        admin = dbsession.query(models.User) \
890
+            .filter(models.User.email == 'admin@admin.admin') \
891
+            .one()
892
+
893
+        workspace_api = WorkspaceApi(
894
+            session=dbsession,
895
+            current_user=admin,
896
+            config=self.app_config,
897
+        )
898
+        workspace_api.create_workspace('test', save_now=True)  # nopep8
899
+        workspace_api.create_workspace('test2', save_now=True)  # nopep8
900
+        workspace_api.create_workspace('test3', save_now=True)  # nopep8
901
+        transaction.commit()
902
+        self.testapp.authorization = (
903
+            'Basic',
904
+            (
905
+                'admin@admin.admin',
906
+                'admin@admin.admin'
907
+            )
908
+        )
909
+        res = self.testapp.get('/api/v2/workspaces', status=200)
910
+        res = res.json_body
911
+        assert len(res) == 3
912
+        workspace = res[0]
913
+        assert workspace['label'] == 'test'
914
+        assert workspace['slug'] == 'test'
915
+        workspace = res[1]
916
+        assert workspace['label'] == 'test2'
917
+        assert workspace['slug'] == 'test2'
918
+        workspace = res[2]
919
+        assert workspace['label'] == 'test3'
920
+        assert workspace['slug'] == 'test3'
921
+
922
+    def test_api__get_workspaces__err_403__unallowed_user(self):
923
+        """
924
+        Check obtain all workspaces reachables for one user
925
+        with another non-admin user auth.
926
+        """
927
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
928
+        admin = dbsession.query(models.User) \
929
+            .filter(models.User.email == 'admin@admin.admin') \
930
+            .one()
931
+        uapi = UserApi(
932
+            current_user=admin,
933
+            session=dbsession,
934
+            config=self.app_config,
935
+        )
936
+        gapi = GroupApi(
937
+            current_user=admin,
938
+            session=dbsession,
939
+            config=self.app_config,
940
+        )
941
+        groups = [gapi.get_one_with_name('users')]
942
+        user = uapi.create_user('test@test.test', password='test@test.test',
943
+                                do_save=True, do_notify=False,
944
+                                groups=groups)  # nopep8
945
+        transaction.commit()
946
+        self.testapp.authorization = (
947
+            'Basic',
948
+            (
949
+                'test@test.test',
950
+                'test@test.test'
951
+            )
952
+        )
953
+        res = self.testapp.get('/api/v2/workspaces', status=403)
954
+        assert isinstance(res.json, dict)
955
+        assert 'code' in res.json.keys()
956
+        assert 'message' in res.json.keys()
957
+        assert 'details' in res.json.keys()
958
+
959
+    def test_api__get_workspaces__err_401__unregistered_user(self):
960
+        """
961
+        Check obtain all workspaces reachables for one user
962
+        without correct user auth (user unregistered).
963
+        """
964
+        self.testapp.authorization = (
965
+            'Basic',
966
+            (
967
+                'john@doe.doe',
968
+                'lapin'
969
+            )
970
+        )
971
+        res = self.testapp.get('/api/v2/workspaces', status=401)
972
+        assert isinstance(res.json, dict)
973
+        assert 'code' in res.json.keys()
974
+        assert 'message' in res.json.keys()
975
+        assert 'details' in res.json.keys()
976
+
977
+
878
 class TestWorkspaceMembersEndpoint(FunctionalTest):
978
 class TestWorkspaceMembersEndpoint(FunctionalTest):
879
     """
979
     """
880
     Tests for /api/v2/workspaces/{workspace_id}/members endpoint
980
     Tests for /api/v2/workspaces/{workspace_id}/members endpoint
945
         assert 'message' in res.json.keys()
1045
         assert 'message' in res.json.keys()
946
         assert 'details' in res.json.keys()
1046
         assert 'details' in res.json.keys()
947
 
1047
 
1048
+    def test_api__get_workspace_member__ok_200__self(self):
1049
+        """
1050
+        Check obtain workspace members list with a reachable workspace for user
1051
+        """
1052
+        self.testapp.authorization = (
1053
+            'Basic',
1054
+            (
1055
+                'admin@admin.admin',
1056
+                'admin@admin.admin'
1057
+            )
1058
+        )
1059
+        res = self.testapp.get('/api/v2/workspaces/1/members/1', status=200).json_body   # nopep8
1060
+        user_role = res
1061
+        assert user_role['role'] == 'workspace-manager'
1062
+        assert user_role['user_id'] == 1
1063
+        assert user_role['workspace_id'] == 1
1064
+        assert user_role['workspace']['workspace_id'] == 1
1065
+        assert user_role['workspace']['label'] == 'Business'
1066
+        assert user_role['workspace']['slug'] == 'business'
1067
+        assert user_role['user']['public_name'] == 'Global manager'
1068
+        assert user_role['user']['user_id'] == 1
1069
+        assert user_role['is_active'] is True
1070
+        assert user_role['do_notify'] is True
1071
+        # TODO - G.M - 24-05-2018 - [Avatar] Replace
1072
+        # by correct value when avatar feature will be enabled
1073
+        assert user_role['user']['avatar_url'] is None
1074
+
1075
+    def test_api__get_workspace_member__ok_200__other_user(self):
1076
+        """
1077
+        Check obtain workspace members list with a reachable workspace for user
1078
+        """
1079
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
1080
+        admin = dbsession.query(models.User) \
1081
+            .filter(models.User.email == 'admin@admin.admin') \
1082
+            .one()
1083
+        uapi = UserApi(
1084
+            current_user=admin,
1085
+            session=dbsession,
1086
+            config=self.app_config,
1087
+        )
1088
+        gapi = GroupApi(
1089
+            current_user=admin,
1090
+            session=dbsession,
1091
+            config=self.app_config,
1092
+        )
1093
+        groups = [gapi.get_one_with_name('managers')]
1094
+        user = uapi.create_user('test@test.test', password='test@test.test', do_save=True, do_notify=False, groups=groups)  # nopep8
1095
+        workspace_api = WorkspaceApi(
1096
+            current_user=admin,
1097
+            session=dbsession,
1098
+            config=self.app_config,
1099
+        )
1100
+        workspace = workspace_api.create_workspace('test_2', save_now=True)  # nopep8
1101
+        rapi = RoleApi(
1102
+            current_user=admin,
1103
+            session=dbsession,
1104
+            config=self.app_config,
1105
+        )
1106
+        rapi.create_one(user, workspace, UserRoleInWorkspace.READER, False)  # nopep8
1107
+        transaction.commit()
1108
+        user_id = user.user_id
1109
+        workspace_id = workspace.workspace_id
1110
+        admin_id = admin.user_id
1111
+        self.testapp.authorization = (
1112
+            'Basic',
1113
+            (
1114
+                'admin@admin.admin',
1115
+                'admin@admin.admin'
1116
+            )
1117
+        )
1118
+        print(str(user_id) + '##' + str(workspace_id))
1119
+        res = self.testapp.get('/api/v2/workspaces/{}/members/{}'.format(
1120
+            workspace_id,
1121
+            user_id
1122
+        ), status=200).json_body
1123
+        user_role = res
1124
+        assert user_role['role'] == 'reader'
1125
+        assert user_role['user_id'] == user_id
1126
+        assert user_role['workspace_id'] == workspace_id
1127
+        assert user_role['is_active'] is True
1128
+        assert user_role['do_notify'] is False
1129
+
1130
+        self.testapp.authorization = (
1131
+            'Basic',
1132
+            (
1133
+                'test@test.test',
1134
+                'test@test.test'
1135
+            )
1136
+        )
1137
+        res = self.testapp.get('/api/v2/workspaces/{}/members/{}'.format(
1138
+            workspace_id,
1139
+            admin_id
1140
+        ), status=200).json_body
1141
+        user_role = res
1142
+        assert user_role['role'] == 'workspace-manager'
1143
+        assert user_role['user_id'] == admin_id
1144
+        assert user_role['workspace_id'] == workspace_id
1145
+        assert user_role['is_active'] is True
1146
+        assert user_role['do_notify'] is True
1147
+
1148
+
1149
+    def test_api__get_workspace_member__err_400__unallowed_user(self):
1150
+        """
1151
+        Check obtain workspace members info with an unreachable workspace for
1152
+        user
1153
+        """
1154
+        self.testapp.authorization = (
1155
+            'Basic',
1156
+            (
1157
+                'lawrence-not-real-email@fsf.local',
1158
+                'foobarbaz'
1159
+            )
1160
+        )
1161
+        res = self.testapp.get('/api/v2/workspaces/3/members/1', status=400)
1162
+        assert isinstance(res.json, dict)
1163
+        assert 'code' in res.json.keys()
1164
+        assert 'message' in res.json.keys()
1165
+        assert 'details' in res.json.keys()
1166
+
1167
+    def test_api__get_workspace_member__err_401__unregistered_user(self):
1168
+        """
1169
+        Check obtain workspace member info with an unregistered user
1170
+        """
1171
+        self.testapp.authorization = (
1172
+            'Basic',
1173
+            (
1174
+                'john@doe.doe',
1175
+                'lapin'
1176
+            )
1177
+        )
1178
+        res = self.testapp.get('/api/v2/workspaces/1/members/1', status=401)
1179
+        assert isinstance(res.json, dict)
1180
+        assert 'code' in res.json.keys()
1181
+        assert 'message' in res.json.keys()
1182
+        assert 'details' in res.json.keys()
1183
+
1184
+
948
     def test_api__get_workspace_members__err_400__workspace_does_not_exist(self):  # nopep8
1185
     def test_api__get_workspace_members__err_400__workspace_does_not_exist(self):  # nopep8
949
         """
1186
         """
950
         Check obtain workspace members list with an existing user but
1187
         Check obtain workspace members list with an existing user but
980
             'user_id': 2,
1217
             'user_id': 2,
981
             'user_email_or_public_name': None,
1218
             'user_email_or_public_name': None,
982
             'role': 'content-manager',
1219
             'role': 'content-manager',
983
-            'do_notify': False,
984
         }
1220
         }
985
         res = self.testapp.post_json(
1221
         res = self.testapp.post_json(
986
             '/api/v2/workspaces/1/members',
1222
             '/api/v2/workspaces/1/members',
1023
             'user_id': None,
1259
             'user_id': None,
1024
             'user_email_or_public_name': 'lawrence-not-real-email@fsf.local',
1260
             'user_email_or_public_name': 'lawrence-not-real-email@fsf.local',
1025
             'role': 'content-manager',
1261
             'role': 'content-manager',
1026
-            'do_notify': 'True',
1027
         }
1262
         }
1028
         res = self.testapp.post_json(
1263
         res = self.testapp.post_json(
1029
             '/api/v2/workspaces/1/members',
1264
             '/api/v2/workspaces/1/members',
1036
         assert user_role_found['workspace_id'] == 1
1271
         assert user_role_found['workspace_id'] == 1
1037
         assert user_role_found['newly_created'] is False
1272
         assert user_role_found['newly_created'] is False
1038
         assert user_role_found['email_sent'] is False
1273
         assert user_role_found['email_sent'] is False
1039
-        assert user_role_found['do_notify'] is True
1274
+        assert user_role_found['do_notify'] is False
1040
 
1275
 
1041
         res = self.testapp.get('/api/v2/workspaces/1/members', status=200).json_body   # nopep8
1276
         res = self.testapp.get('/api/v2/workspaces/1/members', status=200).json_body   # nopep8
1042
         assert len(res) == 2
1277
         assert len(res) == 2
1066
             'user_id': None,
1301
             'user_id': None,
1067
             'user_email_or_public_name': 'Lawrence L.',
1302
             'user_email_or_public_name': 'Lawrence L.',
1068
             'role': 'content-manager',
1303
             'role': 'content-manager',
1069
-            'do_notify': True,
1070
         }
1304
         }
1071
         res = self.testapp.post_json(
1305
         res = self.testapp.post_json(
1072
             '/api/v2/workspaces/1/members',
1306
             '/api/v2/workspaces/1/members',
1079
         assert user_role_found['workspace_id'] == 1
1313
         assert user_role_found['workspace_id'] == 1
1080
         assert user_role_found['newly_created'] is False
1314
         assert user_role_found['newly_created'] is False
1081
         assert user_role_found['email_sent'] is False
1315
         assert user_role_found['email_sent'] is False
1082
-        assert user_role_found['do_notify'] is True
1316
+        assert user_role_found['do_notify'] is False
1083
 
1317
 
1084
         res = self.testapp.get('/api/v2/workspaces/1/members', status=200).json_body   # nopep8
1318
         res = self.testapp.get('/api/v2/workspaces/1/members', status=200).json_body   # nopep8
1085
         assert len(res) == 2
1319
         assert len(res) == 2
1109
             'user_id': None,
1343
             'user_id': None,
1110
             'user_email_or_public_name': None,
1344
             'user_email_or_public_name': None,
1111
             'role': 'content-manager',
1345
             'role': 'content-manager',
1112
-            'do_notify': True,
1113
         }
1346
         }
1114
         res = self.testapp.post_json(
1347
         res = self.testapp.post_json(
1115
             '/api/v2/workspaces/1/members',
1348
             '/api/v2/workspaces/1/members',
1134
             'user_id': 47,
1367
             'user_id': 47,
1135
             'user_email_or_public_name': None,
1368
             'user_email_or_public_name': None,
1136
             'role': 'content-manager',
1369
             'role': 'content-manager',
1137
-            'do_notify': True,
1138
         }
1370
         }
1139
         res = self.testapp.post_json(
1371
         res = self.testapp.post_json(
1140
             '/api/v2/workspaces/1/members',
1372
             '/api/v2/workspaces/1/members',
1159
             'user_id': None,
1391
             'user_id': None,
1160
             'user_email_or_public_name': 'nothing@nothing.nothing',
1392
             'user_email_or_public_name': 'nothing@nothing.nothing',
1161
             'role': 'content-manager',
1393
             'role': 'content-manager',
1162
-            'do_notify': True,
1163
         }
1394
         }
1164
         res = self.testapp.post_json(
1395
         res = self.testapp.post_json(
1165
             '/api/v2/workspaces/1/members',
1396
             '/api/v2/workspaces/1/members',
1173
         assert user_role_found['workspace_id'] == 1
1404
         assert user_role_found['workspace_id'] == 1
1174
         assert user_role_found['newly_created'] is True
1405
         assert user_role_found['newly_created'] is True
1175
         assert user_role_found['email_sent'] is False
1406
         assert user_role_found['email_sent'] is False
1176
-        assert user_role_found['do_notify'] is True
1407
+        assert user_role_found['do_notify'] is False
1177
 
1408
 
1178
         res = self.testapp.get('/api/v2/workspaces/1/members',
1409
         res = self.testapp.get('/api/v2/workspaces/1/members',
1179
                                status=200).json_body  # nopep8
1410
                                status=200).json_body  # nopep8
1205
         assert user_role['role'] == 'workspace-manager'
1436
         assert user_role['role'] == 'workspace-manager'
1206
         assert user_role['user_id'] == 1
1437
         assert user_role['user_id'] == 1
1207
         assert user_role['workspace_id'] == 1
1438
         assert user_role['workspace_id'] == 1
1439
+        assert user_role['do_notify'] is True
1208
         # update workspace role
1440
         # update workspace role
1209
         params = {
1441
         params = {
1210
             'role': 'content-manager',
1442
             'role': 'content-manager',
1211
-            'do_notify': False,
1212
         }
1443
         }
1213
         res = self.testapp.put_json(
1444
         res = self.testapp.put_json(
1214
             '/api/v2/workspaces/1/members/1',
1445
             '/api/v2/workspaces/1/members/1',
1224
         assert len(res) == 1
1455
         assert len(res) == 1
1225
         user_role = res[0]
1456
         user_role = res[0]
1226
         assert user_role['role'] == 'content-manager'
1457
         assert user_role['role'] == 'content-manager'
1227
-        assert user_role['do_notify'] is False
1458
+        assert user_role['do_notify'] is True
1228
         assert user_role['user_id'] == 1
1459
         assert user_role['user_id'] == 1
1229
         assert user_role['workspace_id'] == 1
1460
         assert user_role['workspace_id'] == 1
1230
 
1461
 
1367
             'user_id': None,
1598
             'user_id': None,
1368
             'user_email_or_public_name': 'bob@bob.bob',
1599
             'user_email_or_public_name': 'bob@bob.bob',
1369
             'role': 'content-manager',
1600
             'role': 'content-manager',
1370
-            'do_notify': True,
1371
         }
1601
         }
1372
         res = self.testapp.post_json(
1602
         res = self.testapp.post_json(
1373
             '/api/v2/workspaces/1/members',
1603
             '/api/v2/workspaces/1/members',
1381
         assert user_role_found['workspace_id'] == 1
1611
         assert user_role_found['workspace_id'] == 1
1382
         assert user_role_found['newly_created'] is True
1612
         assert user_role_found['newly_created'] is True
1383
         assert user_role_found['email_sent'] is True
1613
         assert user_role_found['email_sent'] is True
1384
-        assert user_role_found['do_notify'] is True
1614
+        assert user_role_found['do_notify'] is False
1385
 
1615
 
1386
         # check mail received
1616
         # check mail received
1387
         response = requests.get('http://127.0.0.1:8025/api/v1/messages')
1617
         response = requests.get('http://127.0.0.1:8025/api/v1/messages')
1418
             'user_id': None,
1648
             'user_id': None,
1419
             'user_email_or_public_name': 'bob@bob.bob',
1649
             'user_email_or_public_name': 'bob@bob.bob',
1420
             'role': 'content-manager',
1650
             'role': 'content-manager',
1421
-            'do_notify': True,
1422
         }
1651
         }
1423
         res = self.testapp.post_json(
1652
         res = self.testapp.post_json(
1424
             '/api/v2/workspaces/1/members',
1653
             '/api/v2/workspaces/1/members',

+ 0 - 6
backend/tracim_backend/views/core_api/schemas.py Просмотреть файл

466
         example='contributor',
466
         example='contributor',
467
         validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
467
         validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
468
     )
468
     )
469
-    do_notify = marshmallow.fields.Bool(
470
-        description='has user enabled notification for this workspace',
471
-        example=True,
472
-        default=None,
473
-        allow_none=True,
474
-    )
475
 
469
 
476
     @post_load
470
     @post_load
477
     def make_role(self, data):
471
     def make_role(self, data):

+ 63 - 0
backend/tracim_backend/views/core_api/user_controller.py Просмотреть файл

1
 from pyramid.config import Configurator
1
 from pyramid.config import Configurator
2
+from tracim_backend.lib.core.userworkspace import RoleApi
2
 from tracim_backend.lib.utils.utils import password_generator
3
 from tracim_backend.lib.utils.utils import password_generator
3
 
4
 
4
 try:  # Python 3.5+
5
 try:  # Python 3.5+
458
         api.mark_read__workspace(request.current_workspace)
459
         api.mark_read__workspace(request.current_workspace)
459
         return
460
         return
460
 
461
 
462
+    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
463
+    @require_same_user_or_profile(Group.TIM_ADMIN)
464
+    @hapic.input_path(UserWorkspaceIdPathSchema())
465
+    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
466
+    def enable_workspace_notification(self, context, request: TracimRequest, hapic_data=None):  # nopep8
467
+        """
468
+        enable workspace notification
469
+        """
470
+        app_config = request.registry.settings['CFG']
471
+        api = ContentApi(
472
+            current_user=request.candidate_user,  # User
473
+            session=request.dbsession,
474
+            config=app_config,
475
+        )
476
+        wapi = WorkspaceApi(
477
+            current_user=request.candidate_user,  # User
478
+            session=request.dbsession,
479
+            config=app_config,
480
+        )
481
+        workspace = wapi.get_one(hapic_data.path.workspace_id)
482
+        wapi.enable_notifications(request.candidate_user, workspace)
483
+        rapi = RoleApi(
484
+            current_user=request.candidate_user,  # User
485
+            session=request.dbsession,
486
+            config=app_config,
487
+        )
488
+        role = rapi.get_one(request.candidate_user.user_id, workspace.workspace_id)
489
+        wapi.save(workspace)
490
+        return
491
+
492
+    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
493
+    @require_same_user_or_profile(Group.TIM_ADMIN)
494
+    @hapic.input_path(UserWorkspaceIdPathSchema())
495
+    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
496
+    def disable_workspace_notification(self, context, request: TracimRequest, hapic_data=None):  # nopep8
497
+        """
498
+        disable workspace notification
499
+        """
500
+        app_config = request.registry.settings['CFG']
501
+        api = ContentApi(
502
+            current_user=request.candidate_user,  # User
503
+            session=request.dbsession,
504
+            config=app_config,
505
+        )
506
+        wapi = WorkspaceApi(
507
+            current_user=request.candidate_user,  # User
508
+            session=request.dbsession,
509
+            config=app_config,
510
+        )
511
+        workspace = wapi.get_one(hapic_data.path.workspace_id)
512
+        wapi.disable_notifications(request.candidate_user, workspace)
513
+        wapi.save(workspace)
514
+        return
515
+
461
     def bind(self, configurator: Configurator) -> None:
516
     def bind(self, configurator: Configurator) -> None:
462
         """
517
         """
463
         Create all routes and views using pyramid configurator
518
         Create all routes and views using pyramid configurator
532
         # set workspace as read
587
         # set workspace as read
533
         configurator.add_route('read_workspace', '/users/{user_id}/workspaces/{workspace_id}/read', request_method='PUT')  # nopep8
588
         configurator.add_route('read_workspace', '/users/{user_id}/workspaces/{workspace_id}/read', request_method='PUT')  # nopep8
534
         configurator.add_view(self.set_workspace_as_read, route_name='read_workspace')  # nopep8
589
         configurator.add_view(self.set_workspace_as_read, route_name='read_workspace')  # nopep8
590
+
591
+        # enable workspace notification
592
+        configurator.add_route('enable_workspace_notification', '/users/{user_id}/workspaces/{workspace_id}/notify', request_method='PUT')  # nopep8
593
+        configurator.add_view(self.enable_workspace_notification, route_name='enable_workspace_notification')  # nopep8
594
+
595
+        # enable workspace notification
596
+        configurator.add_route('disable_workspace_notification', '/users/{user_id}/workspaces/{workspace_id}/unnotify', request_method='PUT')  # nopep8
597
+        configurator.add_view(self.disable_workspace_notification, route_name='disable_workspace_notification')  # nopep8

+ 55 - 3
backend/tracim_backend/views/core_api/workspace_controller.py Просмотреть файл

18
 from tracim_backend.lib.core.content import ContentApi
18
 from tracim_backend.lib.core.content import ContentApi
19
 from tracim_backend.lib.core.userworkspace import RoleApi
19
 from tracim_backend.lib.core.userworkspace import RoleApi
20
 from tracim_backend.lib.utils.authorization import require_workspace_role
20
 from tracim_backend.lib.utils.authorization import require_workspace_role
21
+from tracim_backend.lib.utils.authorization import require_same_user_or_profile
21
 from tracim_backend.lib.utils.authorization import require_profile_or_other_profile_with_workspace_role
22
 from tracim_backend.lib.utils.authorization import require_profile_or_other_profile_with_workspace_role
22
 from tracim_backend.lib.utils.authorization import require_profile
23
 from tracim_backend.lib.utils.authorization import require_profile
23
 from tracim_backend.models import Group
24
 from tracim_backend.models import Group
77
         return wapi.get_workspace_with_context(request.current_workspace)
78
         return wapi.get_workspace_with_context(request.current_workspace)
78
 
79
 
79
     @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
80
     @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
81
+    @require_profile(Group.TIM_ADMIN)
82
+    @hapic.output_body(WorkspaceSchema(many=True), )
83
+    def workspaces(self, context, request: TracimRequest, hapic_data=None):
84
+        """
85
+        Get list of all workspaces
86
+        """
87
+        app_config = request.registry.settings['CFG']
88
+        wapi = WorkspaceApi(
89
+            current_user=request.current_user,  # User
90
+            session=request.dbsession,
91
+            config=app_config,
92
+        )
93
+
94
+        workspaces = wapi.get_all()
95
+        return [
96
+            wapi.get_workspace_with_context(workspace)
97
+            for workspace in workspaces
98
+        ]
99
+
100
+    @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
80
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
101
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
81
     @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
102
     @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
82
     @hapic.input_path(WorkspaceIdPathSchema())
103
     @hapic.input_path(WorkspaceIdPathSchema())
194
         ]
215
         ]
195
 
216
 
196
     @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
217
     @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
218
+    @require_workspace_role(UserRoleInWorkspace.READER)
219
+    @hapic.input_path(WorkspaceAndUserIdPathSchema())
220
+    @hapic.output_body(WorkspaceMemberSchema())
221
+    def workspaces_member_role(
222
+            self,
223
+            context,
224
+            request: TracimRequest,
225
+            hapic_data=None
226
+    ) -> UserRoleWorkspaceInContext:
227
+        """
228
+        Get role of user in workspace
229
+        """
230
+        app_config = request.registry.settings['CFG']
231
+        rapi = RoleApi(
232
+            current_user=request.current_user,
233
+            session=request.dbsession,
234
+            config=app_config,
235
+        )
236
+
237
+        role = rapi.get_one(
238
+            user_id=hapic_data.path.user_id,
239
+            workspace_id=hapic_data.path.workspace_id,
240
+        )
241
+        return rapi.get_user_role_workspace_with_context(role)
242
+
243
+    @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
197
     @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
244
     @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
198
     @hapic.input_path(WorkspaceAndUserIdPathSchema())
245
     @hapic.input_path(WorkspaceAndUserIdPathSchema())
199
     @hapic.input_body(RoleUpdateSchema())
246
     @hapic.input_body(RoleUpdateSchema())
221
         workspace_role = WorkspaceRoles.get_role_from_slug(hapic_data.body.role)
268
         workspace_role = WorkspaceRoles.get_role_from_slug(hapic_data.body.role)
222
         role = rapi.update_role(
269
         role = rapi.update_role(
223
             role,
270
             role,
224
-            role_level=workspace_role.level,
225
-            with_notif=hapic_data.body.do_notify
271
+            role_level=workspace_role.level
226
         )
272
         )
227
         return rapi.get_user_role_workspace_with_context(role)
273
         return rapi.get_user_role_workspace_with_context(role)
228
 
274
 
303
             user=user,
349
             user=user,
304
             workspace=request.current_workspace,
350
             workspace=request.current_workspace,
305
             role_level=WorkspaceRoles.get_role_from_slug(hapic_data.body.role).level,  # nopep8
351
             role_level=WorkspaceRoles.get_role_from_slug(hapic_data.body.role).level,  # nopep8
306
-            with_notif=hapic_data.body.do_notify or False,  # nopep8, default value as false
352
+            with_notif=False,
307
             flush=True,
353
             flush=True,
308
         )
354
         )
309
         return rapi.get_user_role_workspace_with_context(
355
         return rapi.get_user_role_workspace_with_context(
639
         pyramid configurator for this controller
685
         pyramid configurator for this controller
640
         """
686
         """
641
 
687
 
688
+        # Workspaces
689
+        configurator.add_route('workspaces', '/workspaces', request_method='GET')  # nopep8
690
+        configurator.add_view(self.workspaces, route_name='workspaces')
642
         # Workspace
691
         # Workspace
643
         configurator.add_route('workspace', '/workspaces/{workspace_id}', request_method='GET')  # nopep8
692
         configurator.add_route('workspace', '/workspaces/{workspace_id}', request_method='GET')  # nopep8
644
         configurator.add_view(self.workspace, route_name='workspace')
693
         configurator.add_view(self.workspace, route_name='workspace')
656
         # Workspace Members (Roles)
705
         # Workspace Members (Roles)
657
         configurator.add_route('workspace_members', '/workspaces/{workspace_id}/members', request_method='GET')  # nopep8
706
         configurator.add_route('workspace_members', '/workspaces/{workspace_id}/members', request_method='GET')  # nopep8
658
         configurator.add_view(self.workspaces_members, route_name='workspace_members')  # nopep8
707
         configurator.add_view(self.workspaces_members, route_name='workspace_members')  # nopep8
708
+        # Workspace Members (Role) Individual
709
+        configurator.add_route('workspace_member_role', '/workspaces/{workspace_id}/members/{user_id}', request_method='GET')  # nopep8
710
+        configurator.add_view(self.workspaces_member_role, route_name='workspace_member_role')  # nopep8
659
         # Update Workspace Members roles
711
         # Update Workspace Members roles
660
         configurator.add_route('update_workspace_member', '/workspaces/{workspace_id}/members/{user_id}', request_method='PUT')  # nopep8
712
         configurator.add_route('update_workspace_member', '/workspaces/{workspace_id}/members/{user_id}', request_method='PUT')  # nopep8
661
         configurator.add_view(self.update_workspaces_members_role, route_name='update_workspace_member')  # nopep8
713
         configurator.add_view(self.update_workspaces_members_role, route_name='update_workspace_member')  # nopep8