Skip to content
47 changes: 46 additions & 1 deletion coldfront/core/portal/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
from coldfront.core.test_helpers import utils
from coldfront.core.test_helpers.factories import setup_models
from coldfront.core.allocation.models import AllocationChangeRequest, AllocationChangeStatusChoice
from coldfront.core.test_helpers.factories import setup_models, AttributeTypeFactory, ProjectFactory, ResourceFactory, ResourceTypeFactory, ResourceAttributeTypeFactory, ResourceAttributeFactory
from coldfront.core.project.models import Project
from coldfront.core.resource.models import AttributeType, ResourceType

UTIL_FIXTURES = ['coldfront/core/test_helpers/test_data/test_fixtures/ifx.json']

RESOURCE_FIXTURES = [
"coldfront/core/test_helpers/test_data/test_fixtures/resource.json",
]

class PortalViewTest(TestCase):
"""Base class for portal view tests
Expand All @@ -29,6 +34,7 @@ def test_center_summary(self):


class HomePageTest(PortalViewTest):
fixtures = RESOURCE_FIXTURES

def test_pi_home_page(self):
"""check that the pi home page displays properly with the existing database
Expand Down Expand Up @@ -85,3 +91,42 @@ def test_home_page_projects_display(self):
# allocationuser not belonging to project cannot see project
response = utils.login_and_get_page(self.client, self.nonproj_allocationuser, '')
self.assertEqual(response.context['project_list'].count(), 0)

def test_home_page_managed_resources_display(self):
"""check that managed resources display properly on the home page
"""
ProjectFactory(pi=self.pi_user, title="managed_lab")
ProjectFactory(pi=self.admin_user, title="admin_lab")
text_attribute_type = AttributeType.objects.get(name="Text")
managed_resource = ResourceFactory(name="managed_lab", resource_type__name='Compute Node')
managed_resource2 = ResourceFactory(name="managed_lab2", resource_type__name='Compute Node')
admin_resource = ResourceFactory(name="admin_lab", resource_type__name='Compute Node')
owner_resourcer_attr_type = ResourceAttributeTypeFactory(name="Owner", attribute_type=text_attribute_type)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab",
resource=managed_resource)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab",
resource=managed_resource2)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="admin_lab",
resource=admin_resource)
utils.page_contains_for_user(self, self.pi_user, '', 'Managed Resources')
utils.page_contains_for_user(self, self.admin_user, '', 'Managed Resources')
utils.page_contains_for_user(self, self.pi_user, '', 'managed_lab')
utils.page_contains_for_user(self, self.pi_user, '', 'managed_lab2')
utils.page_does_not_contain_for_user(self, self.pi_user, '', 'admin_lab')
utils.page_contains_for_user(self, self.admin_user, '', 'admin_lab')
utils.page_does_not_contain_for_user(self, self.admin_user, '', 'managed_lab')
utils.page_does_not_contain_for_user(self, self.admin_user, '', 'managed_lab2')

def test_home_page_archive_resources_dont_show(self):
ProjectFactory(pi=self.pi_user, title="managed_lab")
text_attribute_type = AttributeType.objects.get(name="Text")
owner_resourcer_attr_type = ResourceAttributeTypeFactory(name="Owner", attribute_type=text_attribute_type)
archived_resource = ResourceFactory(name="archived_resource", resource_type__name='Compute Node', is_available=False)
archived_resource2 = ResourceFactory(name="archived_resource2", resource_type__name='Compute Node', is_available=False)
active_resource = ResourceFactory(name="active_resource", resource_type__name='Compute Node')
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab", resource=archived_resource)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab", resource=archived_resource2)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab", resource=active_resource)
utils.page_contains_for_user(self, self.pi_user, '', 'active_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, '', 'archived_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, '', 'archived_resource2')
13 changes: 8 additions & 5 deletions coldfront/core/portal/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
)
from coldfront.core.project.models import Project
from coldfront.core.publication.models import Publication
from coldfront.core.resource.models import Resource
from coldfront.core.resource.models import Resource, ResourceAttribute
from coldfront.config.env import ENV
from coldfront.core.department.models import Department, DepartmentMember
from coldfront.core.utils.common import import_from_settings
from pandas.io.clipboard import is_available

if ENV.bool('PLUGIN_SFTOCF', default=False):
from coldfront.plugins.sftocf.utils import StarFishRedash, STARFISH_SERVER
Expand Down Expand Up @@ -82,10 +83,12 @@ def home(request):
department_list = Department.objects.filter(
id__in=user_depts.values_list('organization_id')
)

resource_list = Resource.objects.filter(
allowed_users=request.user)

project_title_list = [project.title for project in project_list]
owned_resources = [attribute.resource.pk for attribute in ResourceAttribute.objects.filter(
resource_attribute_type__name='Owner',
value__in=project_title_list
)]
resource_list = Resource.objects.filter(Q(allowed_users=request.user) | Q(pk__in=owned_resources)).filter(is_available=True).distinct()
context['resource_list'] = resource_list
context['department_list'] = department_list
context['project_list'] = project_list
Expand Down
63 changes: 63 additions & 0 deletions coldfront/core/resource/templates/resource_archived_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% extends "list_view.html" %}

{% block title %}
Project List
{% endblock %}

{% block page_title%}Archived Resources{% endblock %}

{% block presearch %}
<div class="card mb-3 bg-light">
<div class="card-body">
<div class="float-left">
<a class="btn btn-primary" href="{% url 'resource-list' %}?{{filter_parameters}}" role="button"><i class="fas fa-arrow-left" aria-hidden="true"></i> Back to active resources</a>
</div>
</div>
</div>
{% endblock %}


{% block list_title %}Resource{{count|pluralize}}: {{count}}{% endblock %}

{% block table_contents %}
<thead>
<tr>
<th scope="col" class="text-nowrap">
ID
<a href="?order_by=id&direction=asc&{{filter_parameters}}"><i class="fas fa-sort-up" aria-hidden="true"></i><span class="sr-only">Sort ID asc</span></a>
<a href="?order_by=id&direction=des&{{filter_parameters}}"><i class="fas fa-sort-down" aria-hidden="true"></i><span class="sr-only">Sort ID desc</span></a>
</th>
<th scope="col" class="text-nowrap">
Resource Name
<a href="?order_by=name&direction=asc&{{filter_parameters}}"><i class="fas fa-sort-up" aria-hidden="true"></i><span class="sr-only">Sort Resource Name asc</span></a>
<a href="?order_by=name&direction=des&{{filter_parameters}}"><i class="fas fa-sort-down" aria-hidden="true"></i><span class="sr-only">Sort Resource Name desc</span></a>
</th>
<th scope="col" class="text-nowrap">
Parent Resource
<a href="?order_by=parent_resource&direction=asc&{{filter_parameters}}"><i class="fas fa-sort-up" aria-hidden="true"></i><span class="sr-only">Sort Parent Resource asc</span></a>
<a href="?order_by=parent_resource&direction=des&{{filter_parameters}}"><i class="fas fa-sort-down" aria-hidden="true"></i><span class="sr-only">Sort Parent Resource desc</span></a>
</th>
<th scope="col" class="text-nowrap">
Resource Type
<a href="?order_by=resource_type__name&direction=asc&{{filter_parameters}}"><i class="fas fa-sort-up" aria-hidden="true"></i><span class="sr-only">Sort Resource Type asc</span></a>
<a href="?order_by=resource_type__name&direction=des&{{filter_parameters}}"><i class="fas fa-sort-down" aria-hidden="true"></i><span class="sr-only">Sort Resource Type desc</span></a>
</th>
</tr>
</thead>
<tbody>
{% for resource in item_list %}
<tr>
<td><a href="/resource/{{resource.id}}/">{{ resource.id }}</a></td>
<td>{{ resource }}</td>
<td>{{ resource.parent_resource }}</td>
<td>{{ resource.resource_type.name }}</td>
</tr>
{% endfor %}
</tbody>
{% endblock %}

{% block activelink %}
$("#navbar-project-menu").addClass("active");
$("#navbar-resource").addClass("active");

{% endblock %}
6 changes: 5 additions & 1 deletion coldfront/core/resource/templates/resource_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

{% block content %}


{% if resource.is_available == False %}
<div class="alert alert-warning" role="alert">
This is a retired resource! You cannot make any changes.
</div>
{% endif %}
<div class="mb-3">
<h2>Resource Detail</h2>
<hr>
Expand Down
10 changes: 10 additions & 0 deletions coldfront/core/resource/templates/resource_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
{% block title %}Resource List{% endblock %}

{% block page_title %}Resources{% endblock %}
{% block presearch %}
<div class="card mb-3 bg-light">
<div class="card-body">
<div class="float-right">
<a class="btn btn-primary" href="{% url 'resource-archived-list' %}?{{filter_parameters}}" role="button"><i class="fas fa-archive" aria-hidden="true"></i> View retired resources</a>
</div>
</div>
</div>
{% endblock %}

{% block list_title %}Resource{{count|pluralize}}: {{count}}{% endblock %}

Expand Down Expand Up @@ -46,4 +55,5 @@
{% block activelink %}
$("#navbar-project-menu").addClass("active");
$("#navbar-resource").addClass("active");

{% endblock %}
74 changes: 72 additions & 2 deletions coldfront/core/resource/tests.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
from boto3 import resource
from django.db.models import Q
from django.test import TestCase

from coldfront.core.test_helpers import utils
from coldfront.core.test_helpers.factories import setup_models
from coldfront.core.test_helpers.factories import setup_models, AttributeTypeFactory, ProjectFactory, ResourceFactory, ResourceTypeFactory, ResourceAttributeTypeFactory, ResourceAttributeFactory
from coldfront.core.project.models import Project
from coldfront.core.resource.models import AttributeType, ResourceType


UTIL_FIXTURES = [
"coldfront/core/test_helpers/test_data/test_fixtures/ifx.json",
]
RESOURCE_FIXTURES = [
"coldfront/core/test_helpers/test_data/test_fixtures/resource.json",
]


BACKEND = "django.contrib.auth.backends.ModelBackend"

Expand All @@ -27,11 +35,72 @@ def resource_access_tstbase(self, url):
utils.test_logged_out_redirect_to_login(self, url)
utils.test_user_can_access(self, self.admin_user, url) # admin can access


class ResourceListViewTest(ResourceViewBaseTest):
"""Tests for ResourceListView"""
fixtures = RESOURCE_FIXTURES

def setUp(self):
self.client.force_login(self.admin_user, backend=BACKEND)
self.client.force_login(self.pi_user, backend=BACKEND)
self.url = f'/resource/'

def test_only_user_managed_compute_nodes_show(self):
ProjectFactory(pi=self.pi_user, title="managed_lab")
ProjectFactory(pi=self.admin_user, title="admin_lab")
text_attribute_type = AttributeType.objects.get(name="Text")
managed_resource = ResourceFactory(name="managed_lab", resource_type__name='Compute Node')
admin_resource = ResourceFactory(name="admin_lab", resource_type__name='Compute Node')
owner_resourcer_attr_type = ResourceAttributeTypeFactory(name="Owner", attribute_type=text_attribute_type)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="managed_lab", resource=managed_resource)
ResourceAttributeFactory(resource_attribute_type=owner_resourcer_attr_type, value="admin_lab", resource=admin_resource)
utils.page_contains_for_user(self, self.pi_user, self.url, 'managed_lab')
utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'admin_lab')
utils.page_contains_for_user(self, self.admin_user, self.url, 'admin_lab')
utils.page_contains_for_user(self, self.admin_user, self.url, 'managed_lab')

def test_retired_resources_filter_shows(self):
utils.page_contains_for_user(self, self.pi_user, self.url, 'View retired resources')
utils.page_contains_for_user(self, self.admin_user, self.url, 'View retired resources')

def test_archive_resources_dont_show(self):
ResourceFactory(name="archived_resource", resource_type__name='Compute Node', is_available=False)
ResourceFactory(name="archived_resource2", resource_type__name='Compute Node', is_available=False)
ResourceFactory(name="active_resource", resource_type__name='Compute Node')
utils.page_contains_for_user(self, self.pi_user, self.url, 'active_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'archived_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'archived_resource2')



class ResourceArchivedListViewTest(ResourceViewBaseTest):
"""Tests for ResourceArchivedListView"""
fixtures = RESOURCE_FIXTURES

def setUp(self):
self.client.force_login(self.pi_user, backend=BACKEND)
self.url = f'/resource/archived/'

def test_archive_resources_show(self):
ResourceFactory(name="archived_resource", resource_type__name='Compute Node', is_available=False)
ResourceFactory(name="active_resource", resource_type__name='Compute Node')
utils.page_contains_for_user(self, self.pi_user, self.url, 'archived_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, self.url, 'active_resource')
utils.page_contains_for_user(self, self.admin_user, self.url, 'archived_resource')
utils.page_does_not_contain_for_user(self, self.admin_user, self.url, 'active_resource')

def test_can_filter_by_name(self):
AttributeType.objects.get(name="Text")
ResourceFactory(name="archived_resource", resource_type__name='Compute Node', is_available=False)
ResourceFactory(name="archived_resource2", resource_type__name='Compute Node', is_available=False)
ResourceFactory(name="active_resource", resource_type__name='Compute Node')
search_url = f'{self.url}?resource_name=archived_resource'
utils.page_contains_for_user(self, self.pi_user, search_url, 'archived_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, search_url, 'archived_resource2')
utils.page_does_not_contain_for_user(self, self.pi_user, search_url, 'active_resource')
search_url = f'{self.url}?resource_name=archived_resource2'
utils.page_contains_for_user(self, self.pi_user, search_url, 'archived_resource2')
utils.page_does_not_contain_for_user(self, self.pi_user, search_url, 'archived_resource')
utils.page_does_not_contain_for_user(self, self.pi_user, search_url, 'active_resource')


class ClusterResourceDetailViewTest(ResourceViewBaseTest):
Expand Down Expand Up @@ -146,6 +215,7 @@ def test_resource_attribute_create_access(self):
utils.test_user_cannot_access(self, self.resource_allowed_user, self.url)
utils.test_user_cannot_access(self, self.pi_user, self.url)


class ClusterResourceAttributeDeleteViewTest(ResourceViewBaseTest):
"""Tests for ResourceAttributeDeleteView"""

Expand Down
1 change: 1 addition & 0 deletions coldfront/core/resource/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
urlpatterns = [
path('', resource_views.ResourceListView.as_view(),
name='resource-list'),
path('archived/', resource_views.ResourceArchivedListView.as_view(), name='resource-archived-list'),
path('<int:pk>/', resource_views.ResourceDetailView.as_view(),
name='resource-detail'),
path('<int:pk>/resourceattribute/add',
Expand Down
Loading