From 8fa35f268a71420ac40d390d51d0f448407b2436 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Tue, 17 Sep 2024 14:34:24 -0400 Subject: [PATCH 01/10] Added sort users by last name. Added tooltip with email address. --- pybossa/cache/users.py | 6 ++---- pybossa/view/projects.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pybossa/cache/users.py b/pybossa/cache/users.py index a1dcc3e0c..766a20ee8 100644 --- a/pybossa/cache/users.py +++ b/pybossa/cache/users.py @@ -519,11 +519,9 @@ def get_announcements_cached(user, announcement_levels): def get_users_for_data_access(data_access): from pybossa.data_access import get_user_data_access_db_clause + sql = '''select id::text, fullname, email_addr, enabled from "user"''' clause = get_user_data_access_db_clause(data_access) - if not clause: - sql = text('''select id::text, fullname from "user"''') - else: - sql = text('''select id::text, fullname from "user" where {}'''.format(clause)) + sql = sql + '''where {}'''.format(clause) if clause else sql results = session.execute(sql).fetchall() return [dict(row) for row in results] diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index 62bb78a56..3900cb9f5 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -1737,6 +1737,10 @@ def tasks_browse(short_name, page=1, records_per_page=None): args["regular_user"] = regular_user # default page size for worker view is 100 per_page = records_per_page if records_per_page in allowed_records_per_page else task_list_default_records_per_page + elif view_type == 'tasklist' and n_available_tasks_for_user(project, current_user.id) == 0: + # When no tasks are available, redirect to browse all tasks view. + new_path = '/project/{}/tasks/browse'.format(project.short_name) + return redirect_content_type(new_path) else: abort(403) except (ValueError, TypeError) as err: @@ -3853,6 +3857,12 @@ def assign_users(short_name): 'Project id {} no user matching data access level {} for this project.'.format(project.id, access_levels)) flash('Cannot assign users. There is no user matching data access level for this project', 'warning') return redirect_content_type(url_for('.settings', short_name=project.short_name)) + else: + # Update users with last_name for sorting. + users_with_name = [] + for user in users: + full_name_parts = user.get('fullname').split(' ') + user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') form = DataAccessForm(request.body) project_users = json.loads(request.data).get("select_users", []) if request.data else request.form.getlist('select_users') From ac23e7f7705956fd4b92c48031a8b3bb132b0709 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Tue, 17 Sep 2024 16:38:31 -0400 Subject: [PATCH 02/10] Added unit test for GET request. --- test/test_web.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/test_web.py b/test/test_web.py index bb5925914..f78a765d7 100644 --- a/test/test_web.py +++ b/test/test_web.py @@ -9917,6 +9917,41 @@ def test_assign_users_to_project(self): assert data.get('status') == 'success', data assert "Users unassigned or no user assigned to project" in data.get('flash'), data + @with_context + def test_get_assign_users_to_project(self): + """Test GET assign users to project based on data access levels with successful load of users matching data access""" + + from pybossa.view.projects import data_access_levels + + user1 = UserFactory.create(id=999, subadmin=False, admin=True, name="adminuser") + user1.set_password('1234') + user1.info['data_access'] = ["L1", "L2", "L3", "L4"] + user_repo.save(user1) + + user2 = UserFactory.create(id=998, subadmin=False, admin=False, name="workeruser") + user2.set_password('1234') + user2.info['data_access'] = ["L1", "L2", "L3", "L4"] + user_repo.save(user2) + + project = ProjectFactory.create(info={ + 'sched': 'user_pref_scheduler', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'data_access': ["L1", "L2", "L3", "L4"] + }) + project_repo.save(project) + + # Sign-in as an admin user. + csrf = self.get_csrf('/account/signin') + res = self.signin(email=user1.email_addr, password='1234', csrf=csrf) + + with patch.dict(data_access_levels, self.patch_data_access_levels): + # Fetch assign-users page with selection of users for project. + res = self.app.get('/project/{}/assign-users'.format(project.short_name)) + + # Confirm users exist in the page. + assert user1.fullname in str(res.data), 'User 1 not found on assign-users page.' + assert user2.fullname in str(res.data), 'User 2 not found on assign-users page.' + @with_context @patch('pybossa.view.account.send_mail', autospec=True) @patch('pybossa.view.account.mail_queue', autospec=True) From a1d8567da7935835c0a5446b24d48174a16d2e0f Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Tue, 17 Sep 2024 16:42:37 -0400 Subject: [PATCH 03/10] cleanup --- pybossa/view/projects.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index 92631d4aa..a2451e1fc 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -1737,10 +1737,6 @@ def tasks_browse(short_name, page=1, records_per_page=None): args["regular_user"] = regular_user # default page size for worker view is 100 per_page = records_per_page if records_per_page in allowed_records_per_page else task_list_default_records_per_page - elif view_type == 'tasklist' and n_available_tasks_for_user(project, current_user.id) == 0: - # When no tasks are available, redirect to browse all tasks view. - new_path = '/project/{}/tasks/browse'.format(project.short_name) - return redirect_content_type(new_path) else: abort(403) except (ValueError, TypeError) as err: From c1ab66b8f82663f769bdecb834d0059442bb4b55 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 14:09:21 -0400 Subject: [PATCH 04/10] Cleanup. --- pybossa/view/projects.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index 93b5dab47..c3308ff63 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -3862,12 +3862,12 @@ def assign_users(short_name): 'Project id {} no user matching data access level {} for this project.'.format(project.id, access_levels)) flash('Cannot assign users. There is no user matching data access level for this project', 'warning') return redirect_content_type(url_for('.settings', short_name=project.short_name)) - else: - # Update users with last_name for sorting. - users_with_name = [] - for user in users: - full_name_parts = user.get('fullname').split(' ') - user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') + + # Update users with last_name for sorting. + users_with_name = [] + for user in users: + full_name_parts = user.get('fullname').split(' ') + user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') form = DataAccessForm(request.body) project_users = json.loads(request.data).get("select_users", []) if request.data else request.form.getlist('select_users') From 78ed2b169dd479b42338dac4e10bb326f44b0c96 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 14:10:25 -0400 Subject: [PATCH 05/10] Update themes. --- pybossa/themes/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybossa/themes/default b/pybossa/themes/default index 377c59447..c8376e679 160000 --- a/pybossa/themes/default +++ b/pybossa/themes/default @@ -1 +1 @@ -Subproject commit 377c5944701c31a85e4283a5525b28fa169f1028 +Subproject commit c8376e67917dce4f2ee106dd113822b363515b9c From 3ea6358d2424759db6cc3f804b6abc29f6c76ff7 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 14:12:05 -0400 Subject: [PATCH 06/10] Removed unused variable users_with_name. --- pybossa/view/projects.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index c3308ff63..da2ae5e7c 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -3864,7 +3864,6 @@ def assign_users(short_name): return redirect_content_type(url_for('.settings', short_name=project.short_name)) # Update users with last_name for sorting. - users_with_name = [] for user in users: full_name_parts = user.get('fullname').split(' ') user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') From 3695111c43c911b48821c83ee1e7c8ac63efe4a7 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 14:15:46 -0400 Subject: [PATCH 07/10] Handle case for no fullname. --- pybossa/view/projects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index da2ae5e7c..0b4e92913 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -3865,7 +3865,7 @@ def assign_users(short_name): # Update users with last_name for sorting. for user in users: - full_name_parts = user.get('fullname').split(' ') + full_name_parts = user.get('fullname', '').split(' ') user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') form = DataAccessForm(request.body) From 7f74c58542cee240f1e7c54bcc653c0c3975fc47 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 14:40:58 -0400 Subject: [PATCH 08/10] Added test for disabled users to not appear in page. --- test/test_web.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/test_web.py b/test/test_web.py index 7ec6b1cd9..affba4ea8 100644 --- a/test/test_web.py +++ b/test/test_web.py @@ -9928,11 +9928,16 @@ def test_get_assign_users_to_project(self): user1.info['data_access'] = ["L1", "L2", "L3", "L4"] user_repo.save(user1) - user2 = UserFactory.create(id=998, subadmin=False, admin=False, name="workeruser") + user2 = UserFactory.create(id=998, subadmin=False, admin=False, name="workeruser1") user2.set_password('1234') user2.info['data_access'] = ["L1", "L2", "L3", "L4"] user_repo.save(user2) + user3 = UserFactory.create(id=997, subadmin=False, admin=False, name="workeruser2", enabled=False) + user3.set_password('1234') + user3.info['data_access'] = ["L1", "L2", "L3", "L4"] + user_repo.save(user3) + project = ProjectFactory.create(info={ 'sched': 'user_pref_scheduler', 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), @@ -9948,9 +9953,10 @@ def test_get_assign_users_to_project(self): # Fetch assign-users page with selection of users for project. res = self.app.get('/project/{}/assign-users'.format(project.short_name)) - # Confirm users exist in the page. + # Confirm users exist in the page and disables users do not. assert user1.fullname in str(res.data), 'User 1 not found on assign-users page.' assert user2.fullname in str(res.data), 'User 2 not found on assign-users page.' + assert user3.fullname not in str(res.data), 'User 3 is disabled and should not be found on assign-users page.' @with_context @patch('pybossa.view.account.send_mail', autospec=True) From aa346194a1a95c037112476e29573973de656b1a Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 18 Sep 2024 16:38:47 -0400 Subject: [PATCH 09/10] Removed digits from parsing of last name to correct sorting. Updated unit test. --- pybossa/view/projects.py | 4 +++- test/test_web.py | 12 +++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pybossa/view/projects.py b/pybossa/view/projects.py index 0b4e92913..5d835bd32 100644 --- a/pybossa/view/projects.py +++ b/pybossa/view/projects.py @@ -3865,7 +3865,9 @@ def assign_users(short_name): # Update users with last_name for sorting. for user in users: - full_name_parts = user.get('fullname', '').split(' ') + # Remove content within parentheses and digits in name: Jane Doe (ai) + cleaned_name = re.sub(r'\s*\(.*?\)|\d+', '', user.get('fullname', '')) + full_name_parts = cleaned_name.split(' ') user['last_name'] = full_name_parts[-1] if len(full_name_parts) > 1 else user.get('fullname') form = DataAccessForm(request.body) diff --git a/test/test_web.py b/test/test_web.py index affba4ea8..73e490486 100644 --- a/test/test_web.py +++ b/test/test_web.py @@ -9928,14 +9928,16 @@ def test_get_assign_users_to_project(self): user1.info['data_access'] = ["L1", "L2", "L3", "L4"] user_repo.save(user1) - user2 = UserFactory.create(id=998, subadmin=False, admin=False, name="workeruser1") + user2 = UserFactory.create(id=998, subadmin=False, admin=False, name="workeruser_one") user2.set_password('1234') user2.info['data_access'] = ["L1", "L2", "L3", "L4"] + user2.fullname = 'workeruser one' user_repo.save(user2) - user3 = UserFactory.create(id=997, subadmin=False, admin=False, name="workeruser2", enabled=False) + user3 = UserFactory.create(id=997, subadmin=False, admin=False, name="workeruser_two", enabled=False) user3.set_password('1234') user3.info['data_access'] = ["L1", "L2", "L3", "L4"] + user3.fullname = 'workeruser two' user_repo.save(user3) project = ProjectFactory.create(info={ @@ -9954,9 +9956,9 @@ def test_get_assign_users_to_project(self): res = self.app.get('/project/{}/assign-users'.format(project.short_name)) # Confirm users exist in the page and disables users do not. - assert user1.fullname in str(res.data), 'User 1 not found on assign-users page.' - assert user2.fullname in str(res.data), 'User 2 not found on assign-users page.' - assert user3.fullname not in str(res.data), 'User 3 is disabled and should not be found on assign-users page.' + assert user1.fullname in str(res.data), user1.fullname + ' not found on assign-users page.' + assert user2.fullname in str(res.data), user2.fullname + ' not found on assign-users page.' + assert user3.fullname not in str(res.data), user3.fullname + ' is disabled and should not be found on assign-users page.' @with_context @patch('pybossa.view.account.send_mail', autospec=True) From 931e9f3ad8ac289a46199f5c13e81c7ae30ab495 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Thu, 19 Sep 2024 10:31:06 -0400 Subject: [PATCH 10/10] Update themes. --- pybossa/themes/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybossa/themes/default b/pybossa/themes/default index c8376e679..2381ff7b3 160000 --- a/pybossa/themes/default +++ b/pybossa/themes/default @@ -1 +1 @@ -Subproject commit c8376e67917dce4f2ee106dd113822b363515b9c +Subproject commit 2381ff7b3c8b2657da1bfca787850e087ff4a911