Skip to content

Commit

Permalink
Merge pull request #236 from usnistgov/6.0.0.dev
Browse files Browse the repository at this point in the history
6.0.0.dev
  • Loading branch information
rptmat57 authored Jun 7, 2024
2 parents 28a476a + 9f95c83 commit 758968e
Show file tree
Hide file tree
Showing 74 changed files with 2,239 additions and 746 deletions.
33 changes: 29 additions & 4 deletions NEMO/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
TemporaryPhysicalAccess,
TemporaryPhysicalAccessRequest,
Tool,
ToolCredentials,
ToolDocuments,
ToolQualificationGroup,
ToolUsageCounter,
Expand Down Expand Up @@ -312,7 +313,7 @@ class ToolAdmin(admin.ModelAdmin):
"_grant_physical_access_level_upon_qualification",
"_grant_badge_reader_access_upon_qualification",
"_interlock",
"_allow_delayed_logoff",
"_max_delayed_logoff",
"_ask_to_leave_area_when_done_using",
)
},
Expand Down Expand Up @@ -1448,7 +1449,7 @@ def alert_preview(self, obj: Closure):
display_title = f'<span style="font-weight:bold">{obj.name}</span><br>' if obj.name else ""
return iframe_content(
f'<div style="{alert_style}">{display_title}{linebreaksbr(obj.closuretime_set.first().alert_contents())}</div>',
extra_style="padding-bottom: 20%",
extra_style="padding-bottom: 15%",
)
except Exception:
pass
Expand Down Expand Up @@ -1571,6 +1572,7 @@ class LandingPageChoiceAdmin(admin.ModelAdmin):
@register(Customization)
class CustomizationAdmin(admin.ModelAdmin):
list_display = ("name", "value")
search_fields = ["name"]


@register(ScheduledOutageCategory)
Expand Down Expand Up @@ -1836,6 +1838,29 @@ class OnboardingPhaseAdmin(admin.ModelAdmin):
list_display = ("name", "display_order")


class ToolCredentialsAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["authorized_staff"].queryset = User.objects.filter(is_staff=True)


@register(ToolCredentials)
class ToolCredentialsAdmin(ModelAdminRedirectMixin, admin.ModelAdmin):
list_display = ["get_tool_category", "tool", "is_tool_visible", "username", "comments"]
list_filter = [("tool", admin.RelatedOnlyFieldListFilter), "tool__visible"]
autocomplete_fields = ["tool"]
filter_horizontal = ["authorized_staff"]
form = ToolCredentialsAdminForm

@display(ordering="tool___category", description="Tool category")
def get_tool_category(self, obj: ToolCredentials) -> str:
return obj.tool._category

@admin.display(ordering="tool__visible", boolean=True, description="Tool visible")
def is_tool_visible(self, obj: Configuration):
return obj.tool.visible


@register(EmailLog)
class EmailLogAdmin(admin.ModelAdmin):
list_display = ["id", "category", "sender", "to", "subject", "when", "ok"]
Expand Down Expand Up @@ -1916,9 +1941,9 @@ class PermissionAdmin(admin.ModelAdmin):
form = PermissionAdminForm


def iframe_content(content, extra_style="padding-bottom: 75%") -> str:
def iframe_content(content, extra_style="padding-bottom: 65%") -> str:
return mark_safe(
f'<div style="position: relative; display: block; overflow: hidden; {extra_style}"><iframe style="position: absolute; width:100%; height:100%; border:none" src="data:text/html,{urlencode(content)}"></iframe></div>'
f'<div id="iframe-container" style="position: relative; display: block; overflow: hidden; width:100%; height:100%; {extra_style}"><iframe style="width:100%; height:100%; border:none" src="data:text/html,{urlencode(content)}"></iframe></div><script>django.jQuery("#iframe-container").parent(".readonly").css("flex","1");</script>'
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h2>However, a scheduled outage is in effect in the {{ scheduled_outage_in_progr
{% elif reservation_requirement_failed %}
<h2>However, you cannot enter since you don't have a current reservation for this area.</h2>
{% endif %}
<h2>Please visit the {{ facility_name }} staff if you believe this is an error.</h2>
<h2>Please contact {{ facility_name }} staff if you believe this is an error.</h2>
{% if not reservation_requirement_failed and not max_capacity_reached and not scheduled_outage_in_progress %}
<h2>What would you like to do?</h2>
<p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>$('body').removeClass().addClass('logout-error')</script>
<h1>Your badge wasn't recognized.</h1>
<h2>If you got a new one recently then we'll need to update your account.</h2>
<h2>Please visit the {{ facility_name }} staff to resolve the problem.</h2>
<h2>Please contact {{ facility_name }} staff to resolve the problem.</h2>
<audio src="{% url 'media' 'error.mp3' %}" autoplay></audio>
<script>revert(15);</script>
2 changes: 1 addition & 1 deletion NEMO/apps/area_access/templates/area_access/inactive.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<h1>Your account was deactivated.</h1>
<h2>Please visit the {{ facility_name }} staff to resolve the problem.</h2>
<h2>Please contact the {{ facility_name }} staff to resolve the problem.</h2>
<script>revert(15);</script>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1>You are not a member of any active projects.</h1>
<h2>You won't be able to use any interlocked {{ facility_name }} tools.</h2>
<h2>Please visit the {{ facility_name }} user office for more information.</h2>
<h2>Please contact {{ facility_name }} staff for more information.</h2>
<script>revert(15);</script>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>$('body').removeClass().addClass('logout-warning')</script>
<h1>According to our records, you're not logged in to any access controlled areas.</h1>
<h2>Please visit the {{ facility_name }} user office if you believe this is an error.</h2>
<h2>Please contact {{ facility_name }} staff if you believe this is an error.</h2>
<audio src="{% url 'media' 'warning.mp3' %}" autoplay></audio>
<script>revert(15);</script>
28 changes: 26 additions & 2 deletions NEMO/apps/kiosk/templates/kiosk/tool_information.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,30 @@ <h2>
{% endfor %}
</div>
{% endif %}
{% if user.is_staff and tool_credentials %}
<div class="media" style="margin-bottom: 20px">
<a onclick="toggle_details(this)"
data-toggle="collapse"
data-target="#tool_credentials"
class="pointer">
<span class="glyphicon glyphicon-lock pull-left notification-icon warning-highlight"></span><span class="glyphicon glyphicon-chevron-right pull-left chevron"></span>
</a>
<div class="media-body">
<div style="margin-bottom: 15px">Credentials</div>
<div id="tool_credentials" class="collapse">
<ul>
{% for cred in tool_credentials %}
<li>
<i class="glyphicon glyphicon-user"></i> {{ cred.username|default_if_none:"" }}
{% if cred.password %}<i class="glyphicon glyphicon-lock"></i> {{ cred.password }}{% endif %}
{% if cred.comments %}({{ cred.comments }}){% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{% if tool.problems %}
<div class="tool-problems">
{# Display all problems and shutdowns... #}
Expand Down Expand Up @@ -248,7 +272,7 @@ <h2>Configuration</h2>
<h2>Post usage questions</h2>
{{ post_usage_questions }}
{% endif %}
{% if tool.allow_delayed_logoff and not tool.delayed_logoff_in_progress %}
{% if tool.max_delayed_logoff is not None and not tool.delayed_logoff_in_progress %}
<h2>Delayed logoff</h2>
<div class="form-group">
Use the following field to prevent others from using the tool for
Expand All @@ -259,7 +283,7 @@ <h2>Delayed logoff</h2>
style="display:inline;
width:auto"
min="5"
max="120"
max="{{ tool.max_delayed_logoff }}"
inputmode="numeric"
pattern="[0-9]*"
placeholder="0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h2>
{% else %}
use
{% endif %}
any tools because you are not a member of an active project. Please visit the {{ facility_name }} staff to begin a project.
any tools because you are not a member of an active project. Please contact {{ facility_name }} staff to begin a project.
</h2>
{% elif active_projects|length == 1 %}
<h2>
Expand Down
42 changes: 29 additions & 13 deletions NEMO/apps/kiosk/views.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
from datetime import datetime, timedelta
from http import HTTPStatus

from django.conf import settings
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, redirect
from django.db.models import Q
from django.shortcuts import redirect, render
from django.utils import timezone
from django.utils.dateparse import parse_date, parse_time
from django.utils.html import format_html
from django.views.decorators.http import require_GET, require_POST

from NEMO.decorators import synchronized
from NEMO.exceptions import RequiredUnansweredQuestionsException
from NEMO.forms import CommentForm, nice_errors, TaskForm
from NEMO.forms import CommentForm, TaskForm, nice_errors
from NEMO.models import (
BadgeReader,
Project,
Reservation,
ReservationItemType,
TaskCategory,
TaskStatus,
Tool,
ToolWaitList,
UsageEvent,
User,
TaskCategory,
TaskStatus,
)
from NEMO.policy import policy_class as policy
from NEMO.utilities import localize, quiet_int
Expand All @@ -33,7 +36,6 @@
shorten_reservation,
)
from NEMO.views.customization import ApplicationCustomization, ToolCustomization
from NEMO.views.status_dashboard import create_tool_summary
from NEMO.views.tasks import save_task
from NEMO.views.tool_control import (
email_managers_required_questions_disable_tool,
Expand Down Expand Up @@ -407,7 +409,6 @@ def choices(request):
"customer": customer,
"usage_events": list(usage_events),
"upcoming_reservations": tool_reservations,
"tool_summary": create_tool_summary(),
"categories": categories,
"unqualified_categories": unqualified_categories,
}
Expand All @@ -433,7 +434,6 @@ def category_choices(request, category, user_id):
"unqualified_tools": [
tool for tool in tools if not customer.is_staff and tool not in customer.qualifications.all()
],
"tool_summary": create_tool_summary(),
}
return render(request, "kiosk/category_choices.html", dictionary)

Expand All @@ -458,9 +458,20 @@ def tool_information(request, tool_id, user_id, back):
if user_wait_list_entry
else 0
)
tool_credentials = []
if ToolCustomization.get_bool("tool_control_show_tool_credentials") and (
customer.is_staff or customer.is_facility_manager
):
if customer.is_facility_manager:
tool_credentials = tool.toolcredentials_set.all()
else:
tool_credentials = tool.toolcredentials_set.filter(
Q(authorized_staff__isnull=True) | Q(authorized_staff__in=[customer])
)
dictionary = {
"customer": customer,
"tool": tool,
"tool_credentials": tool_credentials,
"rendered_configuration_html": tool.configuration_widget(customer),
"pre_usage_questions": DynamicForm(tool.pre_usage_questions).render(
"tool_usage_group_question", tool.id, virtual_inputs=True
Expand Down Expand Up @@ -597,15 +608,20 @@ def report_problem(request):

return render(request, "kiosk/tool_report_problem.html", dictionary)

if not settings.ALLOW_CONDITIONAL_URLS and form.cleaned_data["force_shutdown"]:
site_title = ApplicationCustomization.get("site_title")
dictionary["message"] = format_html(
'<ul class="errorlist"><li>{}</li></ul>'.format(
f"Tool control is only available on campus. When creating a task, you can't force a tool shutdown while using {site_title} off campus.",
)
)
dictionary["form"] = form
return render(request, "kiosk/tool_report_problem.html", dictionary)

task = form.save()
task.estimated_resolution_time = estimated_resolution_time

save_error = save_task(request, task, customer)

if save_error:
dictionary["message"] = save_error
dictionary["form"] = form
return render(request, "kiosk/tool_report_problem.html", dictionary)
save_task(request, task, customer)

return redirect("kiosk_tool_information", tool_id=tool.id, user_id=customer.id, back=back)

Expand Down
25 changes: 14 additions & 11 deletions NEMO/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from NEMO.models import Area, Customization, Notification, PhysicalAccessLevel, Tool, User
from NEMO.models import Area, Notification, PhysicalAccessLevel, Tool, User
from NEMO.utilities import date_input_js_format, datetime_input_js_format, time_input_js_format
from NEMO.views.customization import CustomizationBase
from NEMO.views.notifications import get_notification_counts


Expand Down Expand Up @@ -63,11 +64,11 @@ def base_context(request):
facility_managers_exist = User.objects.filter(is_active=True, is_facility_manager=True).exists()
except:
facility_managers_exist = False
customization_values = {customization.name: customization.value for customization in Customization.objects.all()}
customization_values = CustomizationBase.get_all()
return {
"facility_name": customization_values.get("facility_name", "Facility"),
"recurring_charges_name": customization_values.get("recurring_charges_name", "Recurring charges"),
"site_title": customization_values.get("site_title", ""),
"facility_name": customization_values.get("facility_name"),
"recurring_charges_name": customization_values.get("recurring_charges_name"),
"site_title": customization_values.get("site_title"),
"device": getattr(request, "device", "desktop"),
"tools_exist": tools_exist,
"areas_exist": areas_exist,
Expand All @@ -84,10 +85,12 @@ def base_context(request):
"date_input_js_format": date_input_js_format,
"datetime_input_js_format": datetime_input_js_format,
"no_header": request.session.get("no_header", False),
"safety_menu_item": customization_values.get("safety_main_menu", "enabled") == "enabled",
"calendar_page_title": customization_values.get("calendar_page_title", "Calendar"),
"tool_control_page_title": customization_values.get("tool_control_page_title", "Tool control"),
"status_dashboard_page_title": customization_values.get("status_dashboard_page_title", "Status dashboard"),
"requests_page_title": customization_values.get("requests_page_title", "Requests"),
"safety_page_title": customization_values.get("safety_page_title", "Safety"),
"safety_menu_item": customization_values.get("safety_main_menu") == "enabled",
"calendar_page_title": customization_values.get("calendar_page_title"),
"tool_control_page_title": customization_values.get("tool_control_page_title"),
"status_dashboard_page_title": customization_values.get("status_dashboard_page_title"),
"requests_page_title": customization_values.get("requests_page_title"),
"safety_page_title": customization_values.get("safety_page_title"),
"calendar_first_day_of_week": customization_values.get("calendar_first_day_of_week"),
"allow_profile_view": customization_values.get("user_allow_profile_view", "") == "enabled",
}
3 changes: 3 additions & 0 deletions NEMO/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ def decorator(view_func=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url
# For example, to replace NEMO.views.policy.check_policy_to_save_reservation(arg1, arg2)
# @replace_function("NEMO.views.policy.check_policy_to_save_reservation")
# def new_function(old_function, arg1, arg2)
#
# Note: this won't be executed when running management commands. To fix that,
# in the apps.py "ready" function, import the file where the annotated function is
def replace_function(old_function_name, raise_exception=True):
try:
pkg, fun_name = old_function_name.rsplit(".", 1)
Expand Down
19 changes: 19 additions & 0 deletions NEMO/migrations/0080_version_6_0_0.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 3.2.25 on 2024-04-17 16:18

from django.db import migrations

from NEMO.migrations_utils import create_news_for_version


class Migration(migrations.Migration):

dependencies = [
("NEMO", "0079_user_active_access_expiration_verbose_names"),
]

def new_version_news(apps, schema_editor):
create_news_for_version(apps, "6.0.0", "")

operations = [
migrations.RunPython(new_version_news),
]
Loading

0 comments on commit 758968e

Please sign in to comment.