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) try: check_billing_to_project(new_project, user, user.area_access_record().area) except ProjectChargeException as e: dictionary = {'error': e.msg} 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 consumables(request): if request.method == "GET": rate_dict = rates.rate_class.get_consumable_rates( Consumable.objects.all()) dictionary = { 'users': User.objects.filter(is_active=True), 'consumables': Consumable.objects.filter(visible=True).order_by( 'category', 'name'), 'rates': rate_dict, } return render(request, 'consumables/consumables.html', dictionary) elif request.method == "POST": form = ConsumableWithdrawForm(request.POST) if form.is_valid(): withdraw = form.save(commit=False) try: check_billing_to_project(withdraw.project, withdraw.customer, withdraw.consumable) except ProjectChargeException as e: return HttpResponseBadRequest(e.msg) add_withdraw_to_session(request, withdraw) else: return HttpResponseBadRequest(form.errors.as_ul()) return render(request, "consumables/consumables_order.html")
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 charge_training(request): trainer: User = request.user try: charges = {} for key, value in request.POST.items(): if is_valid_field(key): attribute, separator, index = key.partition("__") index = int(index) if index not in charges: charges[index] = TrainingSession() charges[index].trainer = trainer if attribute == "chosen_user": charges[index].trainee = User.objects.get(id=to_int_or_negative(value)) if attribute == "chosen_tool": charges[index].tool = Tool.objects.get(id=to_int_or_negative(value)) if not trainer.is_staff and trainer.is_tool_superuser and charges[index].tool not in trainer.superuser_for_tools.all(): raise Exception("The trainer is not authorized to train on this tool") if attribute == "chosen_project": charges[index].project = Project.objects.get(id=to_int_or_negative(value)) if attribute == "duration": charges[index].duration = int(value) if attribute == "charge_type": charges[index].type = int(value) if attribute == "qualify": charges[index].qualified = (value == "on") for c in charges.values(): c.full_clean() check_billing_to_project(c.project, c.trainee, c.tool) except ProjectChargeException as e: return HttpResponseBadRequest(e.msg) except User.DoesNotExist: return HttpResponseBadRequest("Please select a trainee from the list") except Tool.DoesNotExist: return HttpResponseBadRequest("Please select a tool from the list") except Project.DoesNotExist: return HttpResponseBadRequest("Please select a project from the list") except Exception as e: training_logger.exception(e) return HttpResponseBadRequest('An error occurred while processing the training charges. None of the charges were committed to the database. Please review the form for errors and omissions then submit the form again.') else: for c in charges.values(): if c.qualified: qualify(c.trainer, c.trainee, c.tool) c.save() dictionary = { 'title': 'Success!', 'content': 'Training charges were successfully saved.', 'redirect': reverse('landing'), } return render(request, 'display_success_and_redirect.html', dictionary)
def begin_staff_charge(request): if request.user.charging_staff_time(): return HttpResponseBadRequest( 'You cannot create a new staff charge when one is already in progress.' ) charge = StaffCharge() charge.customer = User.objects.get(id=request.POST['customer']) charge.project = Project.objects.get(id=request.POST['project']) # Check if we are allowed to bill to project try: check_billing_to_project(charge.project, charge.customer, charge) except ProjectChargeException as e: return HttpResponseBadRequest(e.msg) charge.staff_member = request.user charge.save() return redirect(reverse('staff_charges'))
def self_log_in(request, load_areas=True): user: User = request.user if not able_to_self_log_in_to_area(user): return redirect(reverse('landing')) dictionary = { 'projects': user.active_projects(), } if request.GET.get('area_id'): dictionary['area_id'] = quiet_int(request.GET['area_id']) facility_name = get_customization('facility_name') try: check_policy_to_enter_any_area(user) except InactiveUserError: dictionary[ 'error_message'] = f'Your account has been deactivated. Please visit the {facility_name} staff to resolve the problem.' return render(request, 'area_access/self_login.html', dictionary) except NoActiveProjectsForUserError: dictionary[ 'error_message'] = f"You are not a member of any active projects. You won't be able to use any interlocked {facility_name} tools. Please visit the {facility_name} user office for more information." return render(request, 'area_access/self_login.html', dictionary) except PhysicalAccessExpiredUserError: dictionary[ 'error_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/self_login.html', dictionary) except NoPhysicalAccessUserError: dictionary[ 'error_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/self_login.html', dictionary) if load_areas: dictionary['user_accessible_areas'], dictionary[ 'areas'] = load_areas_for_use_in_template(user) else: dictionary['user_accessible_areas'] = [] dictionary['areas'] = [] if request.method == 'GET': return render(request, 'area_access/self_login.html', dictionary) if request.method == 'POST': try: a = Area.objects.get(id=request.POST['area']) p = Project.objects.get(id=request.POST['project']) check_policy_to_enter_this_area(a, request.user) check_billing_to_project(p, user, a) log_in_user_to_area(a, request.user, p) except ProjectChargeException as e: dictionary['area_error_message'] = e.msg return render(request, 'area_access/self_login.html', dictionary) except NoAccessiblePhysicalAccessUserError as error: if error.access_exception: dictionary[ 'area_error_message'] = f"You do not have access to the {error.area.name} at this time due to the following exception: {error.access_exception.name}. The exception ends on {localize(error.access_exception.end_time.astimezone(timezone.get_current_timezone()))}" else: dictionary[ 'area_error_message'] = f"You do not have access to the {error.area.name} at this time. Please visit the User Office if you believe this is an error." return render(request, 'area_access/self_login.html', dictionary) except UnavailableResourcesUserError as error: dictionary[ 'area_error_message'] = f'The {error.area.name} is inaccessible because a required resource is unavailable ({error.resources[0]}).' return render(request, 'area_access/self_login.html', dictionary) except ScheduledOutageInProgressError as error: dictionary[ 'area_error_message'] = f'The {error.area.name} is inaccessible because a scheduled outage is in progress.' return render(request, 'area_access/self_login.html', dictionary) except MaximumCapacityReachedError as error: dictionary[ 'area_error_message'] = f'The {error.area.name} is inaccessible because it has reached its maximum capacity. Wait for somebody to exit and try again.' return render(request, 'area_access/self_login.html', dictionary) except ReservationRequiredUserError as error: dictionary[ 'area_error_message'] = f'You do not have a current reservation for the {error.area.name}. Please make a reservation before trying to access this area.' return render(request, 'area_access/self_login.html', dictionary) except Exception as error: area_access_logger.exception(error) dictionary['area_error_message'] = "unexpected error" return render(request, 'area_access/self_login.html', dictionary) return redirect(reverse('landing'))
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_billing_to_project(project, user, area) check_policy_to_enter_this_area(area=area, user=user) except ProjectChargeException as e: dictionary['error_message'] = e.msg return render(request, 'area_access/new_area_access_record.html', dictionary) except NoAccessiblePhysicalAccessUserError as error: if error.access_exception: dictionary[ 'error_message'] = '{} does not have access to the {} at this time due to the following exception: {}.'.format( user, area.name, error.access_exception.name) else: 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 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 not badge_number: return render(request, "area_access/badge_not_found.html") try: user = User.objects.get(badge_number=badge_number) except User.DoesNotExist: 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) try: check_billing_to_project(project, user, door.area) except ProjectChargeException as e: log.details = "The user attempted to bill the project named {} but got error: {}".format( project.name, e.msg) log.save() return render(request, "area_access/physical_access_denied.html", {"message": e.msg}) 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) return render( request, "area_access/login_success.html", { "area": door.area, "name": user.first_name, "project": project, "previous_area": previous_area }, )
def make_reservation(request): """ Create a reservation for a user. """ try: date = parse_date(request.POST['date']) start = localize( datetime.combine(date, parse_time(request.POST['start']))) end = localize(datetime.combine(date, parse_time(request.POST['end']))) except: return render( request, 'mobile/error.html', { 'message': 'Please enter a valid date, start time, and end time for the reservation.' }) item_type = ReservationItemType(request.POST['item_type']) item = get_object_or_404(item_type.get_object_class(), id=request.POST.get('item_id')) # Create the new reservation: reservation = Reservation() reservation.user = request.user reservation.creator = request.user reservation.reservation_item = item reservation.start = start reservation.end = end if item_type == ReservationItemType.TOOL: reservation.short_notice = determine_insufficient_notice(item, start) else: reservation.short_notice = False policy_problems, overridable = check_policy_to_save_reservation( cancelled_reservation=None, new_reservation=reservation, user_creating_reservation=request.user, explicit_policy_override=False) # If there was a problem in saving the reservation then return the error... if policy_problems: return render(request, 'mobile/error.html', {'message': policy_problems[0]}) # All policy checks have passed. try: reservation.project = Project.objects.get( id=request.POST['project_id']) # Check if we are allowed to bill to project check_billing_to_project(reservation.project, request.user, reservation.reservation_item) except ProjectChargeException as e: return render(request, 'mobile/error.html', {'message': e.msg}) except: if not request.user.is_staff: return render( request, 'mobile/error.html', {'message': 'You must specify a project for your reservation'}) reservation.additional_information, reservation.self_configuration = extract_configuration( request) # Reservation can't be short notice if the user is configuring the tool themselves. if reservation.self_configuration: reservation.short_notice = False reservation.save_and_notify() return render(request, 'mobile/reservation_success.html', {'new_reservation': reservation})