Exemple #1
0
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'))
Exemple #2
0
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")
Exemple #3
0
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'))
Exemple #4
0
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)
Exemple #5
0
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'))
Exemple #6
0
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'))
Exemple #7
0
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)
Exemple #8
0
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
            },
        )
Exemple #9
0
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})