def do_disable_tool(request, tool_id): tool = Tool.objects.get(id=tool_id) customer = User.objects.get(id=request.POST["customer_id"]) downtime = timedelta(minutes=quiet_int(request.POST.get("downtime"))) bypass_interlock = request.POST.get("bypass", "False") == "True" response = check_policy_to_disable_tool(tool, customer, downtime) if response.status_code != HTTPStatus.OK: dictionary = {"message": response.content, "delay": 10} return render(request, "kiosk/acknowledgement.html", dictionary) # All policy checks passed so try to disable the tool for the user. if tool.interlock and not tool.interlock.lock(): if bypass_interlock and interlock_bypass_allowed(customer): pass else: return interlock_error("Disable", customer) # Shorten the user's tool reservation since we are now done using the tool shorten_reservation(user=customer, item=tool, new_end=timezone.now() + downtime) # End the current usage event for the tool and save it. current_usage_event = tool.get_current_usage_event() current_usage_event.end = timezone.now() + downtime # Collect post-usage questions dynamic_form = DynamicForm(tool.post_usage_questions) try: current_usage_event.run_data = dynamic_form.extract(request) except RequiredUnansweredQuestionsException as e: if customer.is_staff and customer != current_usage_event.operator and current_usage_event.user != customer: # if a staff is forcing somebody off the tool and there are required questions, send an email and proceed current_usage_event.run_data = e.run_data email_managers_required_questions_disable_tool( current_usage_event.operator, customer, tool, e.questions) else: dictionary = {"message": str(e), "delay": 10} return render(request, "kiosk/acknowledgement.html", dictionary) dynamic_form.charge_for_consumables( current_usage_event.user, current_usage_event.operator, current_usage_event.project, current_usage_event.run_data, request, ) dynamic_form.update_tool_counters(current_usage_event.run_data, tool.id) current_usage_event.save() dictionary = { "message": "You are no longer using the {}".format(tool), "badge_number": customer.badge_number } return render(request, "kiosk/acknowledgement.html", dictionary)
def interlock_error(action: str = None, user: User = None, bypass_allowed: bool = None): error_message = get_customization('door_interlock_failure_message') bypass_allowed = interlock_bypass_allowed( user) if bypass_allowed is None else bypass_allowed dictionary = { "message": linebreaksbr(error_message), "bypass_allowed": bypass_allowed, "action": action } return JsonResponse(dictionary, status=501)
def do_enable_tool(request, tool_id): tool = Tool.objects.get(id=tool_id) customer = User.objects.get(id=request.POST["customer_id"]) project = Project.objects.get(id=request.POST["project_id"]) bypass_interlock = request.POST.get("bypass", 'False') == 'True' response = check_policy_to_enable_tool(tool, operator=customer, user=customer, project=project, staff_charge=False) if response.status_code != HTTPStatus.OK: dictionary = { "message": "You are not authorized to enable this tool. {}".format( response.content.decode()), "delay": 10, } return render(request, "kiosk/acknowledgement.html", dictionary) # All policy checks passed so enable the tool for the user. if tool.interlock and not tool.interlock.unlock(): if bypass_interlock and interlock_bypass_allowed(customer): pass else: return interlock_error("Enable", customer) # Create a new usage event to track how long the user uses the tool. new_usage_event = UsageEvent() new_usage_event.operator = customer new_usage_event.user = customer new_usage_event.project = project new_usage_event.tool = tool new_usage_event.save() dictionary = { "message": "You can now use the {}".format(tool), "badge_number": customer.badge_number } return render(request, "kiosk/acknowledgement.html", dictionary)
def login_to_area(request, door_id): door = get_object_or_404(Door, id=door_id) badge_number = request.POST.get("badge_number", "") bypass_interlock = request.POST.get("bypass", 'False') == 'True' if badge_number == "": return render(request, "area_access/badge_not_found.html") try: badge_number = int(badge_number) user = User.objects.get(badge_number=badge_number) except (User.DoesNotExist, ValueError): return render(request, "area_access/badge_not_found.html") log = PhysicalAccessLog() log.user = user log.door = door log.time = timezone.now() log.result = PhysicalAccessType.DENY # Assume the user does not have access facility_name = get_customization("facility_name") # Check policy for entering an area try: check_policy_to_enter_any_area(user=user) except InactiveUserError: log.details = "This user is not active, preventing them from entering any access controlled areas." log.save() return render(request, "area_access/inactive.html") except NoActiveProjectsForUserError: log.details = "The user has no active projects, preventing them from entering an access controlled area." log.save() return render(request, "area_access/no_active_projects.html") except PhysicalAccessExpiredUserError: log.details = "This user was blocked from this physical access level because their physical access has expired." log.save() message = f"Your physical access to the {facility_name} has expired. Have you completed your safety training within the last year? Please visit the User Office to renew your access." return render(request, "area_access/physical_access_denied.html", {"message": message}) except NoPhysicalAccessUserError: log.details = "This user does not belong to ANY physical access levels." log.save() message = f"You have not been granted physical access to any {facility_name} area. Please visit the User Office if you believe this is an error." return render(request, "area_access/physical_access_denied.html", {"message": message}) max_capacity_reached = False reservation_requirement_failed = False scheduled_outage_in_progress = False # Check policy to enter this area try: check_policy_to_enter_this_area(area=door.area, user=user) except NoAccessiblePhysicalAccessUserError as error: if error.access_exception: log.details = ( f"The user was blocked from entering this area because of an exception: {error.access_exception.name}." ) message = f"You do not have access to this area of the {facility_name} due to the following exception: {error.access_exception}. The exception ends on {localize(error.access_exception.end_time.astimezone(timezone.get_current_timezone()))}" else: log.details = ( "This user is not assigned to a physical access level that allows access to this door at this time." ) message = f"You do not have access to this area of the {facility_name} at this time. Please visit the User Office if you believe this is an error." log.save() return render(request, "area_access/physical_access_denied.html", {"message": message}) except UnavailableResourcesUserError as error: log.details = f"The user was blocked from entering this area because a required resource was unavailable [{', '.join(str(resource) for resource in error.resources)}]." log.save() return render(request, "area_access/resource_unavailable.html", {"unavailable_resources": error.resources}) except MaximumCapacityReachedError as error: # deal with this error after checking if the user is already logged in max_capacity_reached = error except ScheduledOutageInProgressError as error: # deal with this error after checking if the user is already logged in scheduled_outage_in_progress = error except ReservationRequiredUserError: # deal with this error after checking if the user is already logged in reservation_requirement_failed = True current_area_access_record = user.area_access_record() if current_area_access_record and current_area_access_record.area == door.area: # No log entry necessary here because all validation checks passed. # The log entry is captured when the subsequent choice is made by the user. return render( request, "area_access/already_logged_in.html", { "area": door.area, "project": current_area_access_record.project, "badge_number": user.badge_number, "reservation_requirement_failed": reservation_requirement_failed, "max_capacity_reached": max_capacity_reached, "scheduled_outage_in_progress": scheduled_outage_in_progress, }, ) if scheduled_outage_in_progress: log.details = f"The user was blocked from entering this area because the {scheduled_outage_in_progress.area.name} has a scheduled outage in progress." log.save() message = ( f"The {scheduled_outage_in_progress.area.name} is inaccessible because a scheduled outage is in progress." ) return render(request, "area_access/physical_access_denied.html", {"message": message}) if max_capacity_reached: log.details = f"The user was blocked from entering this area because the {max_capacity_reached.area.name} has reached its maximum capacity of {max_capacity_reached.area.maximum_capacity} people at a time." log.save() message = f"The {max_capacity_reached.area.name} has reached its maximum capacity. Please wait for somebody to leave and try again." return render(request, "area_access/physical_access_denied.html", {"message": message}) if reservation_requirement_failed: log.details = f"The user was blocked from entering this area because the user does not have a current reservation for the {door.area}." log.save() message = "You do not have a current reservation for this area. Please make a reservation before trying to access this area." return render(request, "area_access/physical_access_denied.html", {"message": message}) if user.active_project_count() >= 1: if user.active_project_count() == 1: project = user.active_projects()[0] else: project_id = request.POST.get("project_id") if not project_id: # No log entry necessary here because all validation checks passed, and the user must indicate which project # the wish to login under. The log entry is captured when the subsequent choice is made by the user. return render(request, "area_access/choose_project.html", { "area": door.area, "user": user }) else: project = get_object_or_404(Project, id=project_id) if project not in user.active_projects(): log.details = "The user attempted to bill the project named {}, but they are not a member of that project.".format( project.name) log.save() message = "You are not authorized to bill this project." return render(request, "area_access/physical_access_denied.html", {"message": message}) log.result = PhysicalAccessType.ALLOW log.save() # Automatically log the user out of any previous area before logging them in to the new area. previous_area = None if user.in_area(): previous_area = user.area_access_record().area log_out_user(user) # All policy checks passed so open the door for the user. if not door.interlock.unlock(): if bypass_interlock and interlock_bypass_allowed(user): pass else: return interlock_error("Login", user) delay_lock_door(door.id) log_in_user_to_area(door.area, user, project) occupants = AreaAccessRecord.objects.filter(area__name=door.area, end=None, staff_charge=None).count() if door.area.buddy_required(): if occupants == 1: return render( request, 'area_access/buddy_login_warning.html', { 'area': door.area, 'name': user.first_name, 'project': project, 'previous_area': previous_area }, ) elif occupants <= 3: return render( request, 'area_access/buddy_login_reminder.html', { 'area': door.area, 'name': user.first_name, 'project': project, 'previous_area': previous_area, 'occupants': occupants }, ) return render( request, 'area_access/login_success.html', { 'area': door.area, 'name': user.first_name, 'project': project, 'previous_area': previous_area }, )