changeset 965:b6c3ee3da7ae

wsi: added test_user_features and test_list_sharing_users
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 07 Sep 2026 20:11:09 +0200
parents d038ae071934
children 7e211998c2e2
files Plugins/WSI/Annotations.py
diffstat 1 files changed, 165 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/WSI/Annotations.py	Mon Sep 07 18:23:18 2026 +0200
+++ b/Plugins/WSI/Annotations.py	Mon Sep 07 20:11:09 2026 +0200
@@ -84,6 +84,20 @@
                         restPort = args.rest)
 
 
+ALL_USERS = [
+    'admin@uclouvain.be',
+    'instructor@uclouvain.be',
+    'learner2@uclouvain.be',
+    'learner@uclouvain.be',
+]
+
+
+ALL_PROJECTS = [
+    '',
+    'hello',
+]
+
+
 def Execute(uri, args = {}, user = 'admin@uclouvain.be'):
     body = {
         'level' : 'Series',
@@ -96,6 +110,17 @@
     return DoPost(ORTHANC, uri, body, headers = { 'Mail' : user })
 
 
+CREATED_USERS = {}
+
+for user in ALL_USERS:
+    CREATED_USERS[user] = Execute('/wsi/api/create-standard-user', { 'name' : user })
+
+    for project in ALL_PROJECTS:
+        # Enforce the existence as an active user
+        layer = Execute('/wsi/api/create-user-layer', { 'project' : project }, user = user)
+        Execute('/wsi/api/delete-user-layer', { 'layer-id' : layer['id'], 'project' : project }, user = user)
+
+
 class Orthanc(unittest.TestCase):
     def setUp(self):
         if (sys.version_info >= (3, 0)):
@@ -105,13 +130,8 @@
 
         DropOrthanc(ORTHANC)
 
-        for user in [
-                'admin@uclouvain.be',
-                'instructor@uclouvain.be',
-                'learner@uclouvain.be',
-                'learner2@uclouvain.be',
-        ]:
-            for project in [ '', 'hello' ]:
+        for user in ALL_USERS:
+            for project in ALL_PROJECTS:
                 layers = Execute('/wsi/api/list-user-layers', { 'project' : project }, user = user)
 
                 for l in layers['user-layers']:
@@ -127,7 +147,6 @@
                     }, user = user)
 
 
-
     def test_permissions(self):
         info = DoPostRaw(ORTHANC, '/wsi/api/workspace-info', {})
         self.assertEqual(403, info[0].status)
@@ -314,11 +333,6 @@
                 s.append(user['name'])
             return s
 
-        a = Execute('/wsi/api/create-user-layer')  # admin@uclouvain.be
-        b = Execute('/wsi/api/create-user-layer', user = 'instructor@uclouvain.be')
-        c = Execute('/wsi/api/create-user-layer', user = 'learner@uclouvain.be')
-        d = Execute('/wsi/api/create-user-layer', user = 'learner2@uclouvain.be')
-
         v = UnpackSetOfStandardUsers(Execute('/wsi/api/search-active-users', { 'query' : '' }))
         self.assertEqual(3, len(v))
         self.assertTrue('instructor@uclouvain.be' in v)
@@ -360,6 +374,144 @@
             self.assertTrue('instructor@uclouvain.be' in v)
 
 
+    def test_user_features(self):
+        Execute('/wsi/api/save-user-features', {
+            'features' : [
+                # Those are the minimal fields enforced by the plugin, the rest is managed by the JavaScript
+                { 'type' : 'a',
+                  'layer-id' : 'b' },
+                { 'type' : 'c',
+                  'layer-id' : 'd' }
+            ]
+        })
+
+        a = Execute('/wsi/api/load-user-features') ['features']
+        self.assertEqual(2, len(a))
+        self.assertEqual('a', a[0]['type'])
+        self.assertEqual('b', a[0]['layer-id'])
+        self.assertEqual('c', a[1]['type'])
+        self.assertEqual('d', a[1]['layer-id'])
+
+
+    def test_list_sharing_users(self):
+        def CheckNoSharing(viewer):
+            s = Execute('/wsi/api/list-sharing-users', user = viewer)
+            self.assertEqual(0, len(s))
+
+            for i in ALL_USERS:
+                s = Execute('/wsi/api/list-shared-layers', { 'author' : CREATED_USERS[i] }, user = viewer)
+                self.assertEqual(0, len(s))
+
+        def CheckSharingUser(expected_author, expected_layer, viewer):
+            s = Execute('/wsi/api/list-sharing-users', user = viewer)
+            self.assertEqual(1, len(s))
+            self.assertEqual(2, len(s[0]))
+            self.assertEqual(1, s[0]['type'])
+            self.assertEqual(expected_author, s[0]['name'])
+
+            for i in ALL_USERS:
+                if i == expected_author:
+                    s = Execute('/wsi/api/list-shared-layers', { 'author' : CREATED_USERS[i] }, user = viewer)
+                    self.assertEqual(1, len(s))
+                else:
+                    s = Execute('/wsi/api/list-shared-layers', { 'author' : CREATED_USERS[i] }, user = viewer)
+                    self.assertEqual(0, len(s))
+
+        instructor = CREATED_USERS['instructor@uclouvain.be']
+        learner = CREATED_USERS['learner@uclouvain.be']
+        learner2 = CREATED_USERS['learner2@uclouvain.be']
+
+        # Test sharing from instructors
+        a = Execute('/wsi/api/create-user-layer', user = 'admin@uclouvain.be')
+
+        CheckNoSharing('admin@uclouvain.be')
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+        CheckNoSharing('learner@uclouvain.be')
+
+        a['shared_with'] = []
+        a['public'] = True
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'admin@uclouvain.be')
+
+        CheckSharingUser('admin@uclouvain.be', a['id'], 'instructor@uclouvain.be')
+        CheckSharingUser('admin@uclouvain.be', a['id'], 'learner@uclouvain.be')
+        CheckSharingUser('admin@uclouvain.be', a['id'], 'learner2@uclouvain.be')
+
+        a['shared_with'] = []
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'admin@uclouvain.be')
+
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('learner@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+
+        a['shared_with'] = [ learner ]
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'admin@uclouvain.be')
+
+        CheckSharingUser('admin@uclouvain.be', a['id'], 'learner@uclouvain.be')
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+
+        a['shared_with'] = [ instructor ]
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'admin@uclouvain.be')
+
+        CheckSharingUser('admin@uclouvain.be', a['id'], 'instructor@uclouvain.be')
+        CheckNoSharing('learner@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+
+        Execute('/wsi/api/delete-user-layer', { 'layer-id' : a['id'] }, user = 'admin@uclouvain.be')
+
+
+        # Test sharing from learners
+        a = Execute('/wsi/api/create-user-layer', user = 'learner@uclouvain.be')
+
+        CheckNoSharing('admin@uclouvain.be')
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+        CheckNoSharing('learner@uclouvain.be')
+
+        a['shared_with'] = []
+        a['public'] = True
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'learner@uclouvain.be')
+
+        CheckSharingUser('learner@uclouvain.be', a['id'], 'instructor@uclouvain.be')
+        CheckSharingUser('learner@uclouvain.be', a['id'], 'admin@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')  # For learners, "public" means "shared with any instructor"
+
+        a['shared_with'] = []
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'learner@uclouvain.be')
+
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('admin@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+
+        a['shared_with'] = [ learner2 ]
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'learner@uclouvain.be')
+
+        info = Execute('/wsi/api/workspace-info')
+        if info['learner_to_learner_sharing']:
+            CheckSharingUser('learner@uclouvain.be', a['id'], 'learner2@uclouvain.be')
+        else:
+            CheckNoSharing('learner2@uclouvain.be')
+
+        CheckNoSharing('instructor@uclouvain.be')
+        CheckNoSharing('admin@uclouvain.be')
+
+        a['shared_with'] = [ instructor ]
+        a['public'] = False
+        Execute('/wsi/api/save-user-layer', { 'layer' : a }, user = 'learner@uclouvain.be')
+
+        CheckSharingUser('learner@uclouvain.be', a['id'], 'instructor@uclouvain.be')
+        CheckNoSharing('admin@uclouvain.be')
+        CheckNoSharing('learner2@uclouvain.be')
+
+        Execute('/wsi/api/delete-user-layer', { 'layer-id' : a['id'] }, user = 'learner@uclouvain.be')
+
+
 try:
     print('\nStarting the tests...')
     unittest.main(argv = [ sys.argv[0] ] + args.options)