def new_area_access_record(request): dictionary = { 'customers': User.objects.filter(is_active=True) } if request.method == 'GET': try: customer = User.objects.get(id=request.GET['customer']) dictionary['customer'] = customer error_message = check_policy_for_user(customer=customer) if error_message: dictionary['error_message'] = error_message return render(request, 'area_access/new_area_access_record.html', dictionary) dictionary['user_accessible_areas'], dictionary['areas'] = load_areas_for_use_in_template(customer) return render(request, 'area_access/new_area_access_record_details.html', dictionary) except: pass return render(request, 'area_access/new_area_access_record.html', dictionary) if request.method == 'POST': try: user = User.objects.get(id=request.POST['customer']) project = Project.objects.get(id=request.POST['project']) area = Area.objects.get(id=request.POST['area']) except: dictionary['error_message'] = 'Your request contained an invalid identifier.' return render(request, 'area_access/new_area_access_record.html', dictionary) try: error_message = check_policy_for_user(customer=user) if error_message: dictionary['error_message'] = error_message return render(request, 'area_access/new_area_access_record.html', dictionary) check_policy_to_enter_this_area(area=area, user=user) except NoAccessiblePhysicalAccessUserError: dictionary['error_message'] = '{} does not have a physical access level that allows access to the {} at this time.'.format(user, area.name) return render(request, 'area_access/new_area_access_record.html', dictionary) except UnavailableResourcesUserError as error: dictionary['error_message'] = 'The {} is inaccessible because a required resource ({}) is unavailable. You must make all required resources for this area available before creating a new area access record.'.format(error.area.name, error.resources[0]) return render(request, 'area_access/new_area_access_record.html', dictionary) except MaximumCapacityReachedError as error: dictionary['error_message'] = 'The {} is inaccessible because the {} has reached its maximum capacity. Wait for somebody to exit and try again.'.format(area.name, error.area.name) return render(request, 'area_access/new_area_access_record.html', dictionary) except ScheduledOutageInProgressError as error: dictionary['error_message'] = 'The {} is inaccessible because a scheduled outage is in effect. You must wait for the outage to end before creating a new area access record.'.format(error.area.name) return render(request, 'area_access/new_area_access_record.html', dictionary) except ReservationRequiredUserError: dictionary['error_message'] = 'You do not have a current reservation for the {}. Please make a reservation before trying to access this area.'.format(area.name) return render(request, 'area_access/new_area_access_record.html', dictionary) if user.billing_to_project(): dictionary['error_message'] = '{} is already billing area access to another area. The user must log out of that area before entering another.'.format(user) return render(request, 'area_access/new_area_access_record.html', dictionary) if project not in user.active_projects(): dictionary['error_message'] = '{} is not authorized to bill that project.'.format(user) return render(request, 'area_access/new_area_access_record.html', dictionary) record = AreaAccessRecord() record.area = area record.customer = user record.project = project record.save() dictionary['success'] = '{} is now logged in to the {}.'.format(user, area.name) return render(request, 'area_access/new_area_access_record.html', dictionary)
def change_project(request, new_project=None): user: User = request.user """ For area access, allow the user to stop billing a project and start billing another project. """ if request.method == 'GET': return render(request, 'area_access/change_project.html') old_project = user.billing_to_project() if old_project is None: dictionary = { 'error': "There was a problem changing the project you're billing for area access. You must already be billing a project in order to change to another project, however you were not logged in to an area." } return render(request, 'area_access/change_project.html', dictionary) # If we're already billing the requested project then there's nothing to do. if old_project.id == new_project: return redirect(reverse('landing')) new_project = get_object_or_404(Project, id=new_project) if new_project not in user.active_projects(): dictionary = { 'error': 'You do not have permission to bill that project.' } return render(request, 'area_access/change_project.html', dictionary) # Stop billing the user's initial project record = user.area_access_record() record.end = timezone.now() record.save() area = record.area # Start billing the user's new project record = AreaAccessRecord() record.area = area record.customer = request.user record.project = new_project record.save() return redirect(reverse('landing'))
def begin_staff_area_charge(request): charge = request.user.get_staff_charge() if not charge: return HttpResponseBadRequest( 'You do not have a staff charge in progress, so you cannot begin an area access charge.' ) if AreaAccessRecord.objects.filter(staff_charge=charge, end=None).count() > 0: return HttpResponseBadRequest( 'You cannot create an area access charge when one is already in progress.' ) try: area = Area.objects.get(id=request.POST['area']) check_billing_to_project(charge.project, charge.customer, area) except ProjectChargeException as e: return HttpResponseBadRequest(e.msg) except: return HttpResponseBadRequest('Invalid area') area_access = AreaAccessRecord() area_access.area = area area_access.staff_charge = charge area_access.customer = charge.customer area_access.project = charge.project area_access.save() return redirect(reverse('staff_charges'))
def enable_tool(request, tool_id, user_id, project_id, staff_charge): """ Enable a tool for a user. The user must be qualified to do so based on the lab usage policy. """ if not settings.ALLOW_CONDITIONAL_URLS: return HttpResponseBadRequest( "Tool control is only available on campus. We're working to change that! Thanks for your patience." ) tool = get_object_or_404(Tool, id=tool_id) operator = request.user user = get_object_or_404(User, id=user_id) project = get_object_or_404(Project, id=project_id) staff_charge = staff_charge == "true" bypass_interlock = request.POST.get("bypass", 'False') == 'True' response = check_policy_to_enable_tool(tool, operator, user, project, staff_charge) if response.status_code != HTTPStatus.OK: return response # 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(user): pass else: return interlock_error("Enable", user) # Start staff charge before tool usage if staff_charge: new_staff_charge = StaffCharge() new_staff_charge.staff_member = request.user new_staff_charge.customer = user new_staff_charge.project = project new_staff_charge.save() # If the tool requires area access, start charging area access time if tool.requires_area_access: area_access = AreaAccessRecord() area_access.area = tool.requires_area_access area_access.staff_charge = new_staff_charge area_access.customer = new_staff_charge.customer area_access.project = new_staff_charge.project area_access.save() # Create a new usage event to track how long the user uses the tool. new_usage_event = UsageEvent() new_usage_event.operator = operator new_usage_event.user = user new_usage_event.project = project new_usage_event.tool = tool new_usage_event.save() return response
def new_area_access_record(request): dictionary = { 'customers': User.objects.filter(is_active=True) } if request.method == 'GET': try: customer = User.objects.get(id=request.GET['customer'], is_active=True) dictionary['customer'] = customer dictionary['areas'] = list(set([access_level.area for access_level in customer.physical_access_levels.all()])) if customer.active_project_count() == 0: dictionary['error_message'] = '{} does not have any active projects to bill area access'.format(customer) return render(request, 'area_access/new_area_access_record.html', dictionary) if not dictionary['areas']: dictionary['error_message'] = '{} does not have access to any billable NanoFab areas'.format(customer) return render(request, 'area_access/new_area_access_record.html', dictionary) return render(request, 'area_access/new_area_access_record_details.html', dictionary) except: pass return render(request, 'area_access/new_area_access_record.html', dictionary) if request.method == 'POST': try: user = User.objects.get(id=request.POST['customer'], is_active=True) project = Project.objects.get(id=request.POST['project']) area = Area.objects.get(id=request.POST['area']) except: dictionary['error_message'] = 'Your request contained an invalid identifier.' return render(request, 'area_access/new_area_access_record.html', dictionary) if user.access_expiration is not None and user.access_expiration < timezone.now().date(): dictionary['error_message'] = '{} does not have access to the {} because the user\'s physical access expired on {}. You must update the user\'s physical access expiration date before creating a new area access record.'.format(user, area.name.lower(), user.access_expiration.strftime('%B %m, %Y')) return render(request, 'area_access/new_area_access_record.html', dictionary) if not any([access_level.accessible() for access_level in user.physical_access_levels.filter(area=area)]): dictionary['error_message'] = '{} does not have a physical access level that allows access to the {} at this time.'.format(user, area.name.lower()) return render(request, 'area_access/new_area_access_record.html', dictionary) if user.billing_to_project(): dictionary['error_message'] = '{} is already billing area access to another area. The user must log out of that area before entering another.'.format(user) return render(request, 'area_access/new_area_access_record.html', dictionary) if project not in user.active_projects(): dictionary['error_message'] = '{} is not authorized to bill that project.'.format(user) return render(request, 'area_access/new_area_access_record.html', dictionary) if area.required_resources.filter(available=False).exists(): dictionary['error_message'] = 'The {} is inaccessible because a required resource is unavailable. You must make all required resources for this area available before creating a new area access record.'.format(area.name.lower()) return render(request, 'area_access/new_area_access_record.html', dictionary) record = AreaAccessRecord() record.area = area record.customer = user record.project = project record.save() dictionary['success'] = '{} is now logged in to the {}.'.format(user, area.name.lower()) return render(request, 'area_access/new_area_access_record.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', '') 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 # 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 = "Your physical access to the NanoFab 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 = "You have not been granted physical access to any NanoFab 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 # Check policy to enter this area try: check_policy_to_enter_this_area(area=door.area, user=user) except NoAccessiblePhysicalAccessUserError: log.details = "This user is not assigned to a physical access level that allows access to this door at this time." log.save() message = "You do not have access to this area of the NanoFab at this time. Please visit the User Office if you believe this is an error." return render(request, 'area_access/physical_access_denied.html', {'message': message}) except UnavailableResourcesUserError: unavailable_resources = door.area.required_resources.filter(available=False) if unavailable_resources and not user.is_staff: log.details = "The user was blocked from entering this area because a required resource was unavailable." log.save() return render(request, 'area_access/resource_unavailable.html', {'unavailable_resources': unavailable_resources}) except MaximumCapacityReachedError: # deal with this error after checking if the user is already logged in max_capacity_reached = 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}) if max_capacity_reached: log.details = f"This area has reached its maximum capacity of {door.area} people at a time." log.save() message = "This area 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}) previous_area = None 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. if user.in_area(): previous_area_access_record = user.area_access_record() previous_area_access_record.end = timezone.now() previous_area_access_record.save() previous_area = previous_area_access_record.area record = AreaAccessRecord() record.area = door.area record.customer = user record.project = project record.save() unlock_door(door.id) return render(request, 'area_access/login_success.html', {'area': door.area, 'name': user.first_name, 'project': record.project, 'previous_area': previous_area})
def login_to_area(request, door_id): door = get_object_or_404(Door, id=door_id) badge_number = request.POST.get('badge_number', '') 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 # Check if the user is active if not user.is_active: log.details = "This user is not active, preventing them from entering any access controlled areas." log.save() return render(request, 'area_access/inactive.html') # Check if the user has any physical access levels if not user.physical_access_levels.all().exists(): log.details = "This user does not belong to ANY physical access levels." log.save() message = "You have not been granted physical access to any access-controlled area. Please visit the User Office if you believe this is an error." return render(request, 'area_access/physical_access_denied.html', {'message': message}) # Check if the user normally has access to this door at the current time if not any([ access_level.accessible() for access_level in user.physical_access_levels.filter( area=door.area) ]): log.details = "This user is not assigned to a physical access level that allows access to this door at this time." log.save() message = "You do not have access to this area at this time. Please contact staff if you believe this is an error." return render(request, 'area_access/physical_access_denied.html', {'message': message}) # Check that the user's physical access has not expired if user.access_expiration is not None and user.access_expiration < date.today( ): log.details = "This user was blocked from this physical access level because their physical access has expired." log.save() message = "Your physical access has expired. Have you completed your safety training within the last year? Please contact staff to renew your access." return render(request, 'area_access/physical_access_denied.html', {'message': message}) # Users may not access an area if a required resource is unavailable. # Staff are exempt from this rule. unavailable_resources = door.area.required_resources.filter( available=False) if unavailable_resources and not user.is_staff: log.details = "The user was blocked from entering this area because a required resource was unavailable." log.save() return render(request, 'area_access/resource_unavailable.html', {'unavailable_resources': unavailable_resources}) # Users must have at least one billable project in order to enter an area. if user.active_project_count() == 0: 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') 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 }) previous_area = None if user.active_project_count() == 1: log.result = PhysicalAccessType.ALLOW log.save() # Automatically log the user out of any previous area before logging them in to the new area. if user.in_area(): previous_area_access_record = user.area_access_record() previous_area_access_record.end = timezone.now() previous_area_access_record.save() previous_area = previous_area_access_record.area record = AreaAccessRecord() record.area = door.area record.customer = user record.project = user.active_projects()[0] record.save() unlock_door(door) return render( request, 'area_access/login_success.html', { 'area': door.area, 'name': user.first_name, 'project': record.project, 'previous_area': previous_area }) elif user.active_project_count() > 1: project_id = request.POST.get('project_id') if project_id: 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. if user.in_area(): previous_area_access_record = user.area_access_record() previous_area_access_record.end = timezone.now() previous_area_access_record.save() previous_area = previous_area_access_record.area record = AreaAccessRecord() record.area = door.area record.customer = user record.project = project record.save() unlock_door(door) return render( request, 'area_access/login_success.html', { 'area': door.area, 'name': user.first_name, 'project': record.project, 'previous_area': previous_area }) else: # 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 })
def login_to_area(request, door_id): door = get_object_or_404(Door, id=door_id) badge_number = request.POST.get("badge_number", "") 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}) previous_area = None 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. if user.in_area(): previous_area_access_record = user.area_access_record() previous_area_access_record.end = timezone.now() previous_area_access_record.save() previous_area = previous_area_access_record.area record = AreaAccessRecord() record.area = door.area record.customer = user record.project = project record.save() unlock_door(door.id) return render( request, "area_access/login_success.html", { "area": door.area, "name": user.first_name, "project": record.project, "previous_area": previous_area }, )
def new_area_access_record(request): dictionary = {'customers': User.objects.filter(is_active=True)} if request.method == 'GET': try: customer = User.objects.get(id=request.GET['customer']) dictionary['customer'] = customer error_message = check_policy_for_user(customer=customer) if error_message: dictionary['error_message'] = error_message return render(request, 'area_access/new_area_access_record.html', dictionary) dictionary['areas'] = list( get_accessible_areas_for_user(user=customer)) return render(request, 'area_access/new_area_access_record_details.html', dictionary) except: pass return render(request, 'area_access/new_area_access_record.html', dictionary) if request.method == 'POST': try: user = User.objects.get(id=request.POST['customer']) project = Project.objects.get(id=request.POST['project']) area = Area.objects.get(id=request.POST['area']) except: dictionary[ 'error_message'] = 'Your request contained an invalid identifier.' return render(request, 'area_access/new_area_access_record.html', dictionary) try: error_message = check_policy_for_user(customer=user) if error_message: dictionary['error_message'] = error_message return render(request, 'area_access/new_area_access_record.html', dictionary) check_policy_to_enter_this_area(area=area, user=user) except NoAccessiblePhysicalAccessUserError: dictionary[ 'error_message'] = '{} does not have a physical access level that allows access to the {} at this time.'.format( user, area.name.lower()) return render(request, 'area_access/new_area_access_record.html', dictionary) except UnavailableResourcesUserError: dictionary[ 'error_message'] = 'The {} is inaccessible because a required resource is unavailable. You must make all required resources for this area available before creating a new area access record.'.format( area.name.lower()) return render(request, 'area_access/new_area_access_record.html', dictionary) if user.billing_to_project(): dictionary[ 'error_message'] = '{} is already billing area access to another area. The user must log out of that area before entering another.'.format( user) return render(request, 'area_access/new_area_access_record.html', dictionary) if project not in user.active_projects(): dictionary[ 'error_message'] = '{} is not authorized to bill that project.'.format( user) return render(request, 'area_access/new_area_access_record.html', dictionary) record = AreaAccessRecord() record.area = area record.customer = user record.project = project record.save() dictionary['success'] = '{} is now logged in to the {}.'.format( user, area.name.lower()) return render(request, 'area_access/new_area_access_record.html', dictionary)