def get_tool_rate(self, tool: Tool) -> str: full_cost_rate = self._get_rate_by_table_id_and_class(tool, self.tool_rate_class, self.full_cost_rate_class) shared_cost_rate = self._get_rate_by_table_id_and_class(tool, self.tool_rate_class, self.shared_cost_rate_class) if full_cost_rate or shared_cost_rate: result = "Tool rates:" if tool.is_parent_tool(): result += "<br> " + tool.name + ":" if full_cost_rate: result += " Full Cost <b>${:0,.2f}</b>".format(full_cost_rate) if shared_cost_rate: result += " Shared Cost <b>${:0,.2f}</b>".format(shared_cost_rate) if tool.is_parent_tool(): for child_tool in tool.tool_children_set.all(): child_full_cost_rate = self._get_rate_by_table_id_and_class(child_tool, self.tool_rate_class, self.full_cost_rate_class) child_shared_cost_rate = self._get_rate_by_table_id_and_class(child_tool, self.tool_rate_class, self.shared_cost_rate_class) if child_full_cost_rate or child_shared_cost_rate: result += "<br> " + child_tool.name + ":" if child_full_cost_rate: result += " Full Cost <b>${:0,.2f}</b>".format(child_full_cost_rate) if child_shared_cost_rate: result += " Shared Cost <b>${:0,.2f}</b>".format(child_shared_cost_rate) training_rate = self._get_rate_by_table_id_and_class(tool, self.tool_training_rate_class, self.full_cost_rate_class) training_group_rate = self._get_rate_by_table_id_and_class(tool, self.tool_training_group_rate_class, self.full_cost_rate_class) if training_rate or training_group_rate: result += "<br>Training rates:" if training_rate: result += " Individual <b>${:0,.2f}</b>".format(training_rate) if training_group_rate: result += " Group <b>${:0,.2f}</b>".format(training_group_rate) return result
def save_model(self, request, obj, form, change): """ Explicitly record any project membership changes. """ if obj.parent_tool: if obj.pk: # if this is an update (from regular to child tool), we want to make sure we are creating a clean version. In case the previous tool had fields that are now irrelevant clean_alt_tool = Tool(**form.cleaned_data) clean_alt_tool.pk = obj.pk obj = clean_alt_tool super(ToolAdmin, self).save_model(request, obj, form, change) else: record_remote_many_to_many_changes_and_save(request, obj, form, change, 'qualified_users', super(ToolAdmin, self).save_model) if 'required_resources' in form.changed_data: obj.required_resource_set.set(form.cleaned_data['required_resources']) if 'nonrequired_resources' in form.changed_data: obj.nonrequired_resource_set.set(form.cleaned_data['nonrequired_resources'])
def get_tool_full_config_history(tool: Tool): # tool config by user and tool and time configs = [] config_history = ConfigurationHistory.objects.filter( configuration__tool_id=tool.id).order_by("-modification_time")[:20] configurations = tool.current_ordered_configurations() for c in config_history: for co in configurations: if co == c.configuration: current_settings = co.current_settings_as_list() current_settings[c.slot] = c.setting co.current_settings = ", ".join(current_settings) config_input = { "configurations": configurations, "render_as_form": False } configuration = ConfigurationEditor() configs.append({ "modification_time": c.modification_time, "user": c.user, "html": configuration.render(None, config_input) }) return configs
def get_tool_full_config_history(tool: Tool): # tool config by user and tool and time configs = [] config_history = ConfigurationHistory.objects.filter( configuration__tool_id=tool.id).order_by('-modification_time')[:20] configurations = tool.current_ordered_configurations() for c in config_history: for co in configurations: if co == c.configuration: current_settings = co.current_settings_as_list() current_settings[c.slot] = c.setting co.current_settings = ', '.join(current_settings) config_input = { 'configurations': configurations, 'render_as_form': False, } configuration = ConfigurationEditor() configs.append({ 'modification_time': c.modification_time, 'user': c.user, 'html': configuration.render(None, config_input), }) return configs
def check_policy_to_enable_tool(tool: Tool, operator: User, user: User, project: Project, staff_charge: bool): """ Check that the user is allowed to enable the tool. Enable the tool if the policy checks pass. """ facility_name = get_customization('facility_name') # The tool must be visible (or the parent if it's a child tool) to users. visible = tool.parent_tool.visible if tool.is_child_tool( ) else tool.visible if not visible: return HttpResponseBadRequest( "This tool is currently hidden from users.") # The tool must be operational. # If the tool is non-operational then it may only be accessed by staff members. if not tool.operational and not operator.is_staff: return HttpResponseBadRequest( "This tool is currently non-operational.") # The tool must not be in use. current_usage_event = tool.get_current_usage_event() if current_usage_event: return HttpResponseBadRequest("The tool is currently being used by " + str(current_usage_event.user) + ".") # The user must be qualified to use the tool itself, or the parent tool in case of alternate tool. tool_to_check_qualifications = tool.parent_tool if tool.is_child_tool( ) else tool if tool_to_check_qualifications not in operator.qualifications.all( ) and not operator.is_staff: return HttpResponseBadRequest( "You are not qualified to use this tool.") # Only staff members can operate a tool on behalf of another user. if (user and operator.pk != user.pk) and not operator.is_staff: return HttpResponseBadRequest( "You must be a staff member to use a tool on another user's behalf." ) # All required resources must be available to operate a tool except for staff. if tool.required_resource_set.filter( available=False).exists() and not operator.is_staff: return HttpResponseBadRequest( "A resource that is required to operate this tool is unavailable.") # The tool operator may not activate tools in a particular area unless they are logged in to the area. # Staff are exempt from this rule. if tool.requires_area_access and AreaAccessRecord.objects.filter( area=tool.requires_area_access, customer=operator, staff_charge=None, end=None).count() == 0 and not operator.is_staff: dictionary = {'operator': operator, 'tool': tool, 'type': 'access'} abuse_email_address = get_customization('abuse_email_address') message = get_media_file_contents( 'unauthorized_tool_access_email.html') if abuse_email_address and message: rendered_message = Template(message).render(Context(dictionary)) send_mail("Area access requirement", rendered_message, abuse_email_address, [abuse_email_address]) return HttpResponseBadRequest( "You must be logged in to the {} to operate this tool.".format( tool.requires_area_access.name)) # The tool operator may not activate tools in a particular area unless they are still within that area reservation window if not operator.is_staff and tool.requires_area_reservation(): if not tool.requires_area_access.get_current_reservation_for_user( operator): dictionary = { 'operator': operator, 'tool': tool, 'type': 'reservation', } abuse_email_address = get_customization('abuse_email_address') message = get_media_file_contents( 'unauthorized_tool_access_email.html') if abuse_email_address and message: rendered_message = Template(message).render( Context(dictionary)) send_mail("Area reservation requirement", rendered_message, abuse_email_address, [abuse_email_address]) return HttpResponseBadRequest( "You must have a current reservation for the {} to operate this tool." .format(tool.requires_area_access.name)) # Staff may only charge staff time for one user at a time. if staff_charge and operator.charging_staff_time(): return HttpResponseBadRequest( 'You are already charging staff time. You must end the current staff charge before you being another.' ) # Staff may not bill staff time to the themselves. if staff_charge and operator == user: return HttpResponseBadRequest( 'You cannot charge staff time to yourself.') # Users may only charge to projects they are members of. if project not in user.active_projects(): return HttpResponseBadRequest( 'The designated user is not assigned to the selected project.') # The tool operator must not have a lock on usage if operator.training_required: return HttpResponseBadRequest( f"You are blocked from using all tools in the {facility_name}. Please complete the {facility_name} rules tutorial in order to use tools." ) # Users may only use a tool when delayed logoff is not in effect. Staff are exempt from this rule. if tool.delayed_logoff_in_progress() and not operator.is_staff: return HttpResponseBadRequest( "Delayed tool logoff is in effect. You must wait for the delayed logoff to expire before you can use the tool." ) # Users may not enable a tool during a scheduled outage. Staff are exempt from this rule. if tool.scheduled_outage_in_progress() and not operator.is_staff: return HttpResponseBadRequest( "A scheduled outage is in effect. You must wait for the outage to end before you can use the tool." ) return HttpResponse()
def check_policy_to_enable_tool(tool: Tool, operator: User, user: User, project: Project, staff_charge: bool): """ Check that the user is allowed to enable the tool. Enable the tool if the policy checks pass. """ facility_name = get_customization('facility_name') # The tool must be visible (or the parent if it's a child tool) to users. visible = tool.parent_tool.visible if tool.is_child_tool() else tool.visible if not visible: return HttpResponseBadRequest("This tool is currently hidden from users.") # The tool must be operational. # If the tool is non-operational then it may only be accessed by staff members or service personnel. if not tool.operational and not operator.is_staff and not operator.is_service_personnel: return HttpResponseBadRequest("This tool is currently non-operational.") # The tool must not be in use. current_usage_event = tool.get_current_usage_event() if current_usage_event: return HttpResponseBadRequest("The tool is currently being used by " + str(current_usage_event.user) + ".") # The user must be qualified to use the tool itself, or the parent tool in case of alternate tool. tool_to_check_qualifications = tool.parent_tool if tool.is_child_tool() else tool if tool_to_check_qualifications not in operator.qualifications.all() and not operator.is_staff: return HttpResponseBadRequest("You are not qualified to use this tool.") # Only staff members can operate a tool on behalf of another user. if (user and operator.pk != user.pk) and not operator.is_staff: return HttpResponseBadRequest("You must be a staff member to use a tool on another user's behalf.") # All required resources must be available to operate a tool except for staff or service personnel. if tool.required_resource_set.filter(available=False).exists() and not operator.is_staff and not operator.is_service_personnel: return HttpResponseBadRequest("A resource that is required to operate this tool is unavailable.") # The tool operator may not activate tools in a particular area unless they are logged in to the area. # Staff are exempt from this rule. if tool.requires_area_access and AreaAccessRecord.objects.filter(area=tool.requires_area_access, customer=operator, staff_charge=None, end=None).count() == 0 and not operator.is_staff: abuse_email_address = get_customization('abuse_email_address') message = get_media_file_contents('unauthorized_tool_access_email.html') if abuse_email_address and message: dictionary = { 'operator': operator, 'tool': tool, 'type': 'access' } rendered_message = Template(message).render(Context(dictionary)) send_mail(subject="Area access requirement", content=rendered_message, from_email=abuse_email_address, to=[abuse_email_address], email_category=EmailCategory.ABUSE) return HttpResponseBadRequest("You must be logged in to the {} to operate this tool.".format(tool.requires_area_access.name)) # The tool operator may not activate tools in a particular area unless they are still within that area reservation window # Staff and service personnel are exempt from this rule. if not operator.is_staff and not operator.is_service_personnel and tool.requires_area_reservation(): if not tool.requires_area_access.get_current_reservation_for_user(operator): abuse_email_address = get_customization('abuse_email_address') message = get_media_file_contents('unauthorized_tool_access_email.html') if abuse_email_address and message: dictionary = { 'operator': operator, 'tool': tool, 'type': 'reservation', } rendered_message = Template(message).render(Context(dictionary)) send_mail(subject="Area reservation requirement", content=rendered_message, from_email=abuse_email_address, to=[abuse_email_address], email_category=EmailCategory.ABUSE) return HttpResponseBadRequest("You must have a current reservation for the {} to operate this tool.".format(tool.requires_area_access.name)) # Staff may only charge staff time for one user at a time. if staff_charge and operator.charging_staff_time(): return HttpResponseBadRequest('You are already charging staff time. You must end the current staff charge before you being another.') # Staff may not bill staff time to themselves. if staff_charge and operator == user: return HttpResponseBadRequest('You cannot charge staff time to yourself.') # Users may only charge to projects they are members of. if project not in user.active_projects(): return HttpResponseBadRequest('The designated user is not assigned to the selected project.') # The tool operator must not have a lock on usage if operator.training_required: return HttpResponseBadRequest(f"You are blocked from using all tools in the {facility_name}. Please complete the {facility_name} rules tutorial in order to use tools.") # Users may only use a tool when delayed logoff is not in effect. Staff and service personnel are exempt from this rule. if tool.delayed_logoff_in_progress() and not operator.is_staff and not operator.is_service_personnel: return HttpResponseBadRequest("Delayed tool logoff is in effect. You must wait for the delayed logoff to expire before you can use the tool.") # Users may not enable a tool during a scheduled outage. Staff and service personnel are exempt from this rule. if tool.scheduled_outage_in_progress() and not operator.is_staff and not operator.is_service_personnel: return HttpResponseBadRequest("A scheduled outage is in effect. You must wait for the outage to end before you can use the tool.") #Refuses all tool logins if user is logged in using an excluded project (i.e. one reserved for buddy system or observation) if not operator.is_staff: projects_to_exclude = [] exclude=get_customization('exclude_from_usage') if exclude: projects_to_exclude = [int(s) for s in exclude.split() if s.isdigit()] try: if tool.requires_area_access: current_access = AreaAccessRecord.objects.filter(area=tool.requires_area_access, customer=operator, staff_charge=None, end=None) if current_access[0].project.id in projects_to_exclude: return HttpResponseBadRequest("You may not use tools while logged in with this project.") except: return HttpResponseBadRequest("There was a problem enabling this tool. Please see staff.") if tool.reservation_required and not operator.is_staff: td=timedelta(minutes=15) if not Reservation.objects.filter(start__lt=timezone.now()+td, end__gt=timezone.now(), cancelled=False, missed=False, shortened=False, user=operator, tool=tool).exists(): return HttpResponseBadRequest("A reservation is required to enable this tool.") return HttpResponse()