diff --git a/coldfront/config/core.py b/coldfront/config/core.py
index 34dc95f06..4d94def95 100644
--- a/coldfront/config/core.py
+++ b/coldfront/config/core.py
@@ -35,6 +35,11 @@
PENDING_ACTIVE_ALLOCATION_STATUSES = PENDING_ALLOCATION_STATUSES + ACTIVE_ALLOCATION_STATUSES
INACTIVE_ALLOCATION_STATUSES = ['Denied', 'Expired', 'Inactive', 'Pending Deactivation']
+# Categorization of project manager permissions
+MANAGERS = ['General Manager', 'Access Manager', 'Data Manager']
+ACCESS_MANAGERS = ['General Manager', 'Access Manager']
+DATA_MANAGERS = ['General Manager', 'Data Manager']
+
#------------------------------------------------------------------------------
# DjangoQ settings
#------------------------------------------------------------------------------
diff --git a/coldfront/core/allocation/models.py b/coldfront/core/allocation/models.py
index f1530b173..68992463f 100644
--- a/coldfront/core/allocation/models.py
+++ b/coldfront/core/allocation/models.py
@@ -467,10 +467,12 @@ def user_permissions(self, user):
project_perms = self.project.user_permissions(user)
- if ProjectPermission.PI in project_perms or ProjectPermission.MANAGER in project_perms:
+ if ProjectPermission.PI in project_perms or ProjectPermission.DATA_MANAGER in project_perms:
return [AllocationPermission.USER, AllocationPermission.MANAGER]
- if self.allocationuser_set.filter(user=user, status__name__in=['Active', 'New', ]).exists():
+ if self.project.projectuser_set.filter(user=user, status__name='Active').exists():
+ return [AllocationPermission.USER]
+ if self.allocationuser_set.filter(user=user, status__name__in=['Active', 'New']).exists():
return [AllocationPermission.USER]
return []
diff --git a/coldfront/core/allocation/templates/allocation/allocation_detail.html b/coldfront/core/allocation/templates/allocation/allocation_detail.html
index 5178ddfb2..b79348917 100644
--- a/coldfront/core/allocation/templates/allocation/allocation_detail.html
+++ b/coldfront/core/allocation/templates/allocation/allocation_detail.html
@@ -50,13 +50,13 @@
Allocation Detail
Allocation Information
- {% if allocation.is_changeable and not allocation.is_locked and is_allowed_to_update_project and allocation.status.name in 'Active, Renewal Requested, Payment Pending, Payment Requested, Paid' %}
+ {% if allocation.is_changeable and not allocation.is_locked and is_allowed_to_update_project and allocation.status.name in 'Active, Renewal Requested, Payment Pending, Payment Requested, Paid' %}
+ Users can view information about their project and the project's related allocations.
+ Access Managers have the permissions to manage group membership and permissions.
+ Data Managers have the permissions to make allocation requests.
+ General Managers have all the permissions of a PI.
+ PIs have permissions to manage the project and its related allocations, regardless of their assigned projectuser role.
+
Notifications On:
diff --git a/coldfront/core/project/test_views.py b/coldfront/core/project/test_views.py
index d70297a69..5bc6bbb4c 100644
--- a/coldfront/core/project/test_views.py
+++ b/coldfront/core/project/test_views.py
@@ -1,6 +1,7 @@
import logging
from django.test import TestCase, tag
+from django.urls import reverse
from coldfront.core.test_helpers import utils
from coldfront.core.test_helpers.factories import (
@@ -11,12 +12,14 @@
ProjectStatusChoiceFactory,
ProjectAttributeTypeFactory,
)
-from coldfront.core.project.models import ProjectUserStatusChoice, Project
+from coldfront.core.project.models import (
+ Project,
+ ProjectStatusChoice,
+ ProjectUserStatusChoice,
+)
logging.disable(logging.CRITICAL)
-
-
UTIL_FIXTURES = [
"coldfront/core/test_helpers/test_data/test_fixtures/ifx.json",
]
@@ -96,7 +99,7 @@ def test_projectdetail_access(self):
utils.test_user_cannot_access(self, self.nonproject_user, self.url)
def test_projectdetail_permissions(self):
- """Test project detail page access permissions"""
+ """Test ProjectDetail page access permissions"""
# admin has is_allowed_to_update_project set to True
response = utils.login_and_get_page(self.client, self.admin_user, self.url)
self.assertEqual(response.context['is_allowed_to_update_project'], True)
@@ -110,37 +113,65 @@ def test_projectdetail_permissions(self):
self.assertEqual(response.context['is_allowed_to_update_project'], False)
def test_projectdetail_request_allocation_button_visibility(self):
- """Test visibility of project detail request allocation button to different projectuser levels"""
- utils.page_contains_for_user(self, self.admin_user, self.url, 'Request New Storage Allocation') # admin can see request allocation button
+ """Test ProjectDetail request allocation button visibility to different projectuser roles"""
+ button_text = 'Request New Storage Allocation'
+ utils.page_contains_for_user(self, self.admin_user, self.url, button_text) # admin can see request allocation button
- utils.page_contains_for_user(self, self.pi_user, self.url, 'Request New Storage Allocation') # pi can see request allocation button
+ utils.page_contains_for_user(self, self.pi_user, self.url, button_text) # pi can see request allocation button
- response = utils.login_and_get_page(self.client, self.project_user, self.url)
- self.assertNotContains(response, 'Request New Storage Allocation') # non-manager user cannot see request allocation button
+ # data manager can see request allocation button
+ utils.page_contains_for_user(self, self.proj_datamanager, self.url, button_text)
+ # access manager cannot see request allocation button
+ utils.page_does_not_contain_for_user(self, self.proj_accessmanager, self.url, button_text)
+
+ utils.page_does_not_contain_for_user(self, self.project_user, self.url, button_text) # non-manager user cannot see request allocation button
def test_projectdetail_edituser_button_visibility(self):
- """Test visibility of project detail edit button to different projectuser levels"""
+ """Test ProjectDetail edit button visibility to different projectuser roles"""
utils.page_contains_for_user(self, self.admin_user, self.url, 'fa-user-edit') # admin can see edit button
-
utils.page_contains_for_user(self, self.pi_user, self.url, 'fa-user-edit') # pi can see edit button
-
utils.page_does_not_contain_for_user(self, self.project_user, self.url, 'fa-user-edit') # non-manager user cannot see edit button
-
- # def test_projectdetail_addattribute_button_visibility(self):
- # """Test visibility of project detail add attribute button to different projectuser levels"""
- # utils.page_contains_for_user(self, self.admin_user, self.url, 'Add Attribute') # admin can see add attribute button
- #
- # utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'Add Attribute') # pi cannot see add attribute button
- #
- # utils.page_does_not_contain_for_user(self, self.project_user, self.url, 'Add Attribute') # non-manager user cannot see add attribute button
+ # access manager can see edit button
+ utils.page_contains_for_user(self, self.proj_accessmanager, self.url, 'fa-user-edit')
+ # data manager cannot see edit button
+ utils.page_does_not_contain_for_user(self, self.proj_datamanager, self.url, 'fa-user-edit')
+
+ def test_projectdetail_addattribute_button_visibility(self):
+ """Test ProjectDetail add attribute button visibility to different projectuser roles"""
+ search_text = 'Add Attribute'
+ utils.page_contains_for_user(self, self.admin_user, self.url, search_text) # admin can see add attribute button
+ utils.page_does_not_contain_for_user(self, self.pi_user, self.url, search_text) # pi cannot see add attribute button
+ utils.page_does_not_contain_for_user(self, self.project_user, self.url, search_text) # non-manager user cannot see add attribute button
def test_projectdetail_addnotification_button_visibility(self):
- """Test visibility of project detail add notification button to different projectuser levels"""
- utils.page_contains_for_user(self, self.admin_user, self.url, 'Add Notification') # admin can see add notification button
+ """Test ProjectDetail add notification button visibility to different projectuser roles"""
+ search_text = 'Add Notification'
+ utils.page_contains_for_user(self, self.admin_user, self.url, search_text) # admin can see add notification button
+ utils.page_does_not_contain_for_user(self, self.pi_user, self.url, search_text) # pi cannot see add notification button
+ utils.page_does_not_contain_for_user(self, self.project_user, self.url, search_text) # non-manager user cannot see add notification button
+ # access manager cannot see add notification button
+ utils.page_does_not_contain_for_user(self, self.proj_accessmanager, self.url, search_text)
+ # data manager cannot see add notification button
+ utils.page_does_not_contain_for_user(self, self.proj_datamanager, self.url, search_text)
- utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'Add Notification') # pi cannot see add notification button
- utils.page_does_not_contain_for_user(self, self.project_user, self.url, 'Add Notification') # non-manager user cannot see add notification button
+class ProjectArchiveProjectViewTest(ProjectViewTestBase):
+ """Tests for project archive project view"""
+
+ @classmethod
+ def setUpTestData(cls):
+ """Set up users and project for testing"""
+ super(ProjectArchiveProjectViewTest, cls).setUpTestData()
+ cls.url = f'/project/{cls.project.pk}/archive'
+
+ def test_project_archive_project_access(self):
+ """Test access to project archive project page"""
+ # logged-out user gets redirected, admin can access archive project page
+ self.project_access_tstbase(self.url)
+ # pi, projectuser and nonproject user cannot access archive project page
+ utils.test_user_cannot_access(self, self.pi_user, self.url)
+ utils.test_user_cannot_access(self, self.project_user, self.url)
+ utils.test_user_cannot_access(self, self.nonproject_user, self.url)
class ProjectCreateTest(ProjectViewTestBase):
@@ -177,8 +208,8 @@ def test_project_access(self):
"""Test access to project attribute create page"""
# logged-out user gets redirected, admin can access create page
self.project_access_tstbase(self.url)
- # pi can access create page
- utils.test_user_can_access(self, self.pi_user, self.url)
+ # pi cannot access create page
+ utils.test_user_cannot_access(self, self.pi_user, self.url)
# project user and nonproject user cannot access create page
utils.test_user_cannot_access(self, self.project_user, self.url)
utils.test_user_cannot_access(self, self.nonproject_user, self.url)
@@ -239,8 +270,8 @@ def setUpTestData(cls):
def test_project_attribute_update_access(self):
"""Test access to project attribute update page"""
self.project_access_tstbase(self.url)
- utils.test_user_can_access(self, self.pi_user, self.url)
# project user, pi, and nonproject user cannot access update page
+ utils.test_user_cannot_access(self, self.pi_user, self.url)
utils.test_user_cannot_access(self, self.project_user, self.url)
utils.test_user_cannot_access(self, self.nonproject_user, self.url)
@@ -259,9 +290,8 @@ def test_project_attribute_delete_access(self):
"""test access to project attribute delete page"""
# logged-out user gets redirected, admin can access delete page
self.project_access_tstbase(self.url)
- # pi can access delete page
- utils.test_user_can_access(self, self.pi_user, self.url)
- # project user and nonproject user cannot access delete page
+ # pi, project user and nonproject user cannot access delete page
+ utils.test_user_cannot_access(self, self.pi_user, self.url)
utils.test_user_cannot_access(self, self.project_user, self.url)
utils.test_user_cannot_access(self, self.nonproject_user, self.url)
@@ -316,7 +346,6 @@ def test_project_list_displayall_permission_project_user(self):
response = utils.login_and_get_page(self.client, self.project_user, url)
self.assertEqual(len(response.context['object_list']), 1)
-
### ProjectListView search tests ###
def test_project_list_search(self):
@@ -333,18 +362,33 @@ def test_project_list_search_pagination(self):
response = utils.login_and_get_page(self.client, self.admin_user, url)
-
class ProjectRemoveUsersViewTest(ProjectViewTestBase):
"""Tests for ProjectRemoveUsersView"""
+
def setUp(self):
- """set up users and project for testing"""
- self.url = f'/project/{self.project.pk}/remove-users/'
+ """Set up users and project for testing"""
+ super().setUp()
+ self.url = reverse('project-remove-users', kwargs={'pk': self.project.pk})
+ self.project_user = self.proj_allocation_user
+ self.nonproject_user = self.nonproj_allocation_user
@tag('net')
def test_projectremoveusersview_access(self):
"""test access to project remove users page"""
self.project_access_tstbase(self.url)
+ @tag('net')
+ def test_pi_user_cannot_be_removed(self):
+ """Test that the project PI cannot be removed"""
+ self.client.force_login(self.pi_user)
+
+ response = self.client.get(self.url)
+ self.assertEqual(response.status_code, 200)
+ context = response.context
+
+ users_to_remove = context['formset'].initial
+ self.assertNotIn(self.pi_user.username, [u['username'] for u in users_to_remove])
+
class ProjectUpdateViewTest(ProjectViewTestBase):
"""Tests for ProjectUpdateView"""
@@ -399,6 +443,10 @@ def setUp(self):
def test_projectadduserssearchview_access(self):
"""test access to project add users search page"""
self.project_access_tstbase(self.url)
+ utils.test_user_can_access(self, self.pi_user, self.url)# pi can access
+ utils.test_user_can_access(self, self.proj_accessmanager, self.url)# access manager can access
+ utils.test_user_cannot_access(self, self.proj_datamanager, self.url)# data manager cannot access
+ utils.test_user_cannot_access(self, self.proj_allocation_user, self.url)# user cannot access
class ProjectUserDetailViewTest(ProjectViewTestBase):
diff --git a/coldfront/core/project/utils.py b/coldfront/core/project/utils.py
index 95441e683..836787f77 100644
--- a/coldfront/core/project/utils.py
+++ b/coldfront/core/project/utils.py
@@ -16,7 +16,7 @@ def add_project_status_choices(apps, schema_editor):
def add_project_user_role_choices(apps, schema_editor):
ProjectUserRoleChoice = apps.get_model('project', 'ProjectUserRoleChoice')
- for choice in ['User', 'Manager', ]:
+ for choice in ['User', 'Data Manager', 'General Manager', 'Access Manager']:
ProjectUserRoleChoice.objects.get_or_create(name=choice)
diff --git a/coldfront/core/project/views.py b/coldfront/core/project/views.py
index eafc85fea..b6bfc4369 100644
--- a/coldfront/core/project/views.py
+++ b/coldfront/core/project/views.py
@@ -134,7 +134,10 @@ def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Can the user update the project?
context['is_allowed_to_update_project'] = self.object.has_perm(
- self.request.user, ProjectPermission.MANAGER
+ self.request.user, ProjectPermission.DATA_MANAGER
+ )
+ context['is_allowed_to_update_users'] = self.object.has_perm(
+ self.request.user, ProjectPermission.ACCESS_MANAGER
)
if self.request.user.is_superuser:
@@ -189,7 +192,7 @@ def get_context_data(self, **kwargs):
allocations = allocations.filter(
Q(project__projectuser__user=self.request.user)
)
- if not self.object.has_perm(self.request.user, ProjectPermission.MANAGER):
+ if not self.object.has_perm(self.request.user, ProjectPermission.DATA_MANAGER):
allocations = allocations.filter(
Q(allocationuser__user=self.request.user)
)
@@ -351,10 +354,10 @@ class ProjectArchiveProjectView(LoginRequiredMixin, UserPassesTestMixin, Templat
def test_func(self):
"""UserPassesTestMixin Tests"""
- # project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- # if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
if self.request.user.is_superuser:
return True
+ error_message = 'You do not have permission to archive a project.'
+ messages.error(self.request, error_message)
return False
def get_context_data(self, **kwargs):
@@ -438,7 +441,7 @@ class ProjectUpdateView(
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
+ if project_obj.has_perm(self.request.user, ProjectPermission.DATA_MANAGER):
return True
return False
@@ -460,8 +463,7 @@ class ProjectAddUsersSearchView(LoginRequiredMixin, UserPassesTestMixin, Templat
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- # if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
- if self.request.user.is_superuser or self.request.user == project_obj.pi:
+ if project_obj.has_perm(self.request.user, ProjectPermission.ACCESS_MANAGER):
return True
return False
@@ -489,8 +491,7 @@ class ProjectAddUsersSearchResultsView(
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- # if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
- if self.request.user.is_superuser or self.request.user == project_obj.pi:
+ if project_obj.has_perm(self.request.user, ProjectPermission.ACCESS_MANAGER):
return True
return False
@@ -562,8 +563,7 @@ class ProjectAddUsersView(LoginRequiredMixin, UserPassesTestMixin, View):
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- # if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
- if self.request.user.is_superuser or self.request.user == project_obj.pi:
+ if project_obj.has_perm(self.request.user, ProjectPermission.ACCESS_MANAGER):
return True
err = 'You do not have permission to add users to the project.'
messages.error(self.request, err)
@@ -721,9 +721,10 @@ class ProjectRemoveUsersView(LoginRequiredMixin, UserPassesTestMixin, TemplateVi
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- # if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
- if self.request.user.is_superuser or self.request.user == project_obj.pi:
+ if project_obj.has_perm(self.request.user, ProjectPermission.ACCESS_MANAGER):
return True
+ err = 'You do not have permission to remove users from the project.'
+ messages.error(self.request, err)
return False
def dispatch(self, request, *args, **kwargs):
@@ -878,8 +879,10 @@ class ProjectUserDetail(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
+ if project_obj.has_perm(self.request.user, ProjectPermission.ACCESS_MANAGER):
return True
+ err = 'You do not have permission to edit project users.'
+ messages.error(self.request, err)
return False
def get(self, request, *args, **kwargs):
@@ -962,7 +965,7 @@ def project_update_email_notification(request):
allowed = False
- if project_obj.has_perm(request.user, ProjectPermission.UPDATE):
+ if project_obj.has_perm(request.user, ProjectPermission.ACCESS_MANAGER):
allowed = True
if project_user_obj.user == request.user:
allowed = True
@@ -989,7 +992,7 @@ class ProjectReviewView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
def test_func(self):
"""UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
- if project_obj.has_perm(self.request.user, ProjectPermission.UPDATE):
+ if project_obj.has_perm(self.request.user, ProjectPermission.DATA_MANAGER):
return True
messages.error(
self.request, 'You do not have permissions to review this project.'
@@ -1226,20 +1229,10 @@ class ProjectAttributeCreateView(LoginRequiredMixin, UserPassesTestMixin, Create
def test_func(self):
"""UserPassesTestMixin Tests"""
- project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
-
if self.request.user.is_superuser:
return True
- if project_obj.pi == self.request.user:
- return True
- if project_obj.projectuser_set.filter(
- user=self.request.user, role__name='Manager', status__name='Active'
- ).exists():
- return True
-
- messages.error(
- self.request, 'You do not have permission to add project attributes.'
- )
+ err = 'You do not have permission to add project attributes.'
+ messages.error(self.request, err)
return False
def get_initial(self):
@@ -1272,21 +1265,9 @@ class ProjectAttributeDeleteView(LoginRequiredMixin, UserPassesTestMixin, Templa
def test_func(self):
"""UserPassesTestMixin Tests"""
-
- project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
-
if self.request.user.is_superuser:
return True
-
- if project_obj.pi == self.request.user:
- return True
-
- if project_obj.projectuser_set.filter(
- user=self.request.user, role__name='Manager', status__name='Active'
- ).exists():
- return True
-
- err = 'You do not have permission to add project attributes.'
+ err = 'You do not have permission to remove project attributes.'
messages.error(self.request, err)
def get_avail_attrs(self, project_obj):
@@ -1358,18 +1339,11 @@ class ProjectAttributeUpdateView(LoginRequiredMixin, UserPassesTestMixin, Templa
def test_func(self):
"""UserPassesTestMixin Tests"""
- project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
-
if self.request.user.is_superuser:
return True
-
- if project_obj.pi == self.request.user:
- return True
-
- if project_obj.projectuser_set.filter(
- user=self.request.user, role__name='Manager', status__name='Active'
- ).exists():
- return True
+ err = 'You do not have permission to update project attributes.'
+ messages.error(self.request, err)
+ return False
def get(self, request, *args, **kwargs):
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
@@ -1392,7 +1366,6 @@ def get(self, request, *args, **kwargs):
context['project_obj'] = project_obj
context['project_attribute_update_form'] = project_attribute_update_form
context['project_attribute_obj'] = project_attribute_obj
-
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
diff --git a/coldfront/core/test_helpers/factories.py b/coldfront/core/test_helpers/factories.py
index ce689e1ba..ffb336ea8 100644
--- a/coldfront/core/test_helpers/factories.py
+++ b/coldfront/core/test_helpers/factories.py
@@ -40,7 +40,7 @@
### Default values and Faker provider setup ###
project_status_choice_names = ['New', 'Active', 'Archived']
-project_user_role_choice_names = ['User', 'Manager']
+project_user_role_choice_names = ['User', 'Access Manager', 'General Manager', 'Data Manager']
field_of_science_names = ['Physics', 'Chemistry', 'Economics', 'Biology', 'Sociology']
attr_types = ['Date', 'Int', 'Float', 'Text', 'Boolean']
@@ -83,6 +83,7 @@ class Meta:
is_superuser = False
+
### Field of Science factories ###
class FieldOfScienceFactory(DjangoModelFactory):
@@ -367,6 +368,8 @@ def setup_models(test_case):
# pi is a project admin but not an AllocationUser.
test_case.pi_user = UserFactory(username='sdpoisson')
test_case.proj_allocation_user = UserFactory(username='ljbortkiewicz')
+ test_case.proj_datamanager = UserFactory(username='ajayer')
+ test_case.proj_accessmanager = UserFactory(username='mdavis')
test_case.proj_nonallocation_user = UserFactory(username='wkohn')
test_case.nonproj_allocation_user = UserFactory(username='jsaul')
test_case.project = ProjectFactory(pi=test_case.pi_user, title="poisson_lab")
@@ -394,13 +397,15 @@ def setup_models(test_case):
for user in [test_case.proj_allocation_user, test_case.nonproj_allocation_user]:
AllocationUserFactory(user=user, allocation=test_case.proj_allocation)
- manager_role = ProjectUserRoleChoiceFactory(name='Manager')
+ for user, role in {
+ test_case.pi_user:'General Manager',
+ test_case.proj_datamanager: 'Data Manager',
+ test_case.proj_accessmanager: 'Access Manager',
+ test_case.proj_nonallocation_user: 'User',
+ }.items():
+ ProjectUserFactory(
+ user=user, project=test_case.project, role=ProjectUserRoleChoiceFactory(name=role)
+ )
- ProjectUserFactory(
- user=test_case.pi_user, project=test_case.project, role=manager_role
- )
test_case.npu = ProjectUserFactory(user=test_case.proj_allocation_user, project=test_case.project)
test_case.normal_projuser = test_case.npu.user
- ProjectUserFactory(
- user=test_case.proj_nonallocation_user, project=test_case.project
- )
diff --git a/coldfront/core/test_helpers/fasrc_factories.py b/coldfront/core/test_helpers/fasrc_factories.py
index a003cd693..07f6e7ca1 100644
--- a/coldfront/core/test_helpers/fasrc_factories.py
+++ b/coldfront/core/test_helpers/fasrc_factories.py
@@ -89,6 +89,12 @@ def setup_departments(test_case):
last_name='Ostrom',
full_name='Elinor Ostrom',
)
+ test_case.dept_member_user = UserFactory(
+ username='jdewey',
+ first_name='John',
+ last_name='Dewey',
+ full_name='John Dewey',
+ )
test_case.school = OrganizationFactory(
name='School of Maths and Sciences',
@@ -101,13 +107,6 @@ def setup_departments(test_case):
org_tree='Research Computing Storage Billing',
)
-
- test_case.dept_member_user = UserFactory(
- username='jdoe',
- first_name='John',
- last_name='Doe',
- full_name='John Doe',
- )
ProjectFactory()
for project in Project.objects.all():
project_title = project.title
diff --git a/coldfront/core/user/templates/user/user_projects_managers.html b/coldfront/core/user/templates/user/user_projects_managers.html
index 951a2ffdc..a4bf7a94e 100644
--- a/coldfront/core/user/templates/user/user_projects_managers.html
+++ b/coldfront/core/user/templates/user/user_projects_managers.html
@@ -54,7 +54,7 @@
{{ project.title }}
Additional Managers
{{ project.project_managers | length }}
{% if association.is_project_manager and not association.is_project_pi %}
-
{{ user_pronounish }} {{user_verbform_be}} a manager of this project.
+
{{ user_pronounish }} {{user_verbform_be}} a {{association.role.name}} of this project.