Beispiel #1
0
def cancel_the_reservation(reservation: Reservation, user_cancelling_reservation: User, reason: Optional[str]):
	response = check_policy_to_cancel_reservation(reservation, user_cancelling_reservation)
	# Staff must provide a reason when cancelling a reservation they do not own.
	if reservation.user != user_cancelling_reservation and not reason:
		response = HttpResponseBadRequest("You must provide a reason when cancelling someone else's reservation.")

	if response.status_code == HTTPStatus.OK:
		# All policy checks passed, so cancel the reservation.
		reservation.cancelled = True
		reservation.cancellation_time = timezone.now()
		reservation.cancelled_by = user_cancelling_reservation

		if reason:
			''' don't notify in this case since we are sending a specific email for the cancellation '''
			reservation.save()
			dictionary = {
				'staff_member': user_cancelling_reservation,
				'reservation': reservation,
				'reason': reason,
				'template_color': bootstrap_primary_color('info')
			}
			email_contents = get_media_file_contents('cancellation_email.html')
			if email_contents:
				cancellation_email = Template(email_contents).render(Context(dictionary))
				if getattr(reservation.user.preferences, 'attach_cancelled_reservation', False):
					attachment = create_ics_for_reservation(reservation, cancelled=True)
					reservation.user.email_user('Your reservation was cancelled', cancellation_email, user_cancelling_reservation.email, [attachment])
				else:
					reservation.user.email_user('Your reservation was cancelled', cancellation_email, user_cancelling_reservation.email)

		else:
			''' here the user cancelled his own reservation so notify him '''
			reservation.save_and_notify()

	return response
Beispiel #2
0
def check_policy_rules_for_item(cancelled_reservation: Optional[Reservation],
                                new_reservation: Reservation,
                                user_creating_reservation: User):
    item_policy_problems = []
    # Calculate the duration of the reservation:
    duration = new_reservation.end - new_reservation.start

    # The reservation must be at least as long as the minimum block time for this item.
    # Staff may break this rule.
    # An explicit policy override allows this rule to be broken.
    item = new_reservation.reservation_item
    item_type = new_reservation.reservation_item_type
    if item.minimum_usage_block_time:
        minimum_block_time = timedelta(minutes=item.minimum_usage_block_time)
        if duration < minimum_block_time:
            item_policy_problems.append(
                f"Your reservation has a duration of {str(int(duration.total_seconds() / 60))} minutes. This {item_type.value} requires a minimum reservation duration of {str(int(minimum_block_time.total_seconds() / 60))} minutes."
            )

    # The reservation may not exceed the maximum block time for this tool.
    # Staff may break this rule.
    # An explicit policy override allows this rule to be broken.
    if item.maximum_usage_block_time:
        maximum_block_time = timedelta(minutes=item.maximum_usage_block_time)
        if duration > maximum_block_time:
            item_policy_problems.append(
                f"Your reservation has a duration of {str(int(duration.total_seconds() / 60))} minutes. Reservations for this {item_type.value} may not exceed {str(int(maximum_block_time.total_seconds() / 60))} minutes."
            )

    user = new_reservation.user

    # If there is a limit on number of reservations per user per day then verify that the user has not exceeded it.
    # Staff may break this rule.
    # An explicit policy override allows this rule to be broken.
    if item.maximum_reservations_per_day:
        start_of_day = new_reservation.start
        start_of_day = start_of_day.replace(hour=0,
                                            minute=0,
                                            second=0,
                                            microsecond=0)
        end_of_day = start_of_day + timedelta(days=1)
        reservations_for_that_day = Reservation.objects.filter(
            cancelled=False,
            shortened=False,
            start__gte=start_of_day,
            end__lte=end_of_day,
            user=user)
        reservations_for_that_day = reservations_for_that_day.filter(
            **new_reservation.reservation_item_filter)
        # Exclude any reservation that is being cancelled.
        if cancelled_reservation and cancelled_reservation.id:
            reservations_for_that_day = reservations_for_that_day.exclude(
                id=cancelled_reservation.id)
        if reservations_for_that_day.count(
        ) >= item.maximum_reservations_per_day:
            if user == user_creating_reservation:
                item_policy_problems.append(
                    f"You may only have {str(item.maximum_reservations_per_day)} reservations for this {item_type.value} per day. Missed reservations are included when counting the number of reservations per day."
                )
            else:
                item_policy_problems.append(
                    f"{str(user)} may only have {str(item.maximum_reservations_per_day)} reservations for this {item_type.value} per day. Missed reservations are included when counting the number of reservations per day."
                )

    # A minimum amount of time between reservations for the same user & same tool can be enforced.
    # Staff may break this rule.
    # An explicit policy override allows this rule to be broken.
    if item.minimum_time_between_reservations:
        buffer_time = timedelta(minutes=item.minimum_time_between_reservations)
        must_end_before = new_reservation.start - buffer_time
        too_close = Reservation.objects.filter(cancelled=False,
                                               shortened=False,
                                               user=user,
                                               end__gt=must_end_before,
                                               start__lt=new_reservation.start)
        too_close = too_close.filter(**new_reservation.reservation_item_filter)
        if cancelled_reservation and cancelled_reservation.id:
            too_close = too_close.exclude(id=cancelled_reservation.id)
        if too_close.exists():
            if user == user_creating_reservation:
                item_policy_problems.append(
                    f"Separate reservations for this {item_type.value} that belong to you must be at least {str(item.minimum_time_between_reservations)} minutes apart from each other. The proposed reservation ends too close to another reservation."
                )
            else:
                item_policy_problems.append(
                    f"Separate reservations for this {item_type.value} that belong to {str(user)} must be at least {str(item.minimum_time_between_reservations)} minutes apart from each other. The proposed reservation ends too close to another reservation."
                )
        must_start_after = new_reservation.end + buffer_time
        too_close = Reservation.objects.filter(cancelled=False,
                                               shortened=False,
                                               user=user,
                                               start__lt=must_start_after,
                                               end__gt=new_reservation.start)
        too_close = too_close.filter(**new_reservation.reservation_item_filter)
        if cancelled_reservation and cancelled_reservation.id:
            too_close = too_close.exclude(id=cancelled_reservation.id)
        if too_close.exists():
            if user == user_creating_reservation:
                item_policy_problems.append(
                    f"Separate reservations for this {item_type.value} that belong to you must be at least {str(item.minimum_time_between_reservations)} minutes apart from each other. The proposed reservation begins too close to another reservation."
                )
            else:
                item_policy_problems.append(
                    f"Separate reservations for this {item_type.value} that belong to {str(user)} must be at least {str(item.minimum_time_between_reservations)} minutes apart from each other. The proposed reservation begins too close to another reservation."
                )

    # Check that the user is not exceeding the maximum amount of time they may reserve in the future.
    # Staff may break this rule.
    # An explicit policy override allows this rule to be broken.
    if item.maximum_future_reservation_time:
        reservations_after_now = Reservation.objects.filter(
            cancelled=False, user=user, start__gte=timezone.now())
        reservations_after_now = reservations_after_now.filter(
            **new_reservation.reservation_item_filter)
        if cancelled_reservation and cancelled_reservation.id:
            reservations_after_now = reservations_after_now.exclude(
                id=cancelled_reservation.id)
        amount_reserved_in_the_future = new_reservation.duration()
        for r in reservations_after_now:
            amount_reserved_in_the_future += r.duration()
        if amount_reserved_in_the_future.total_seconds(
        ) / 60 > item.maximum_future_reservation_time:
            if user == user_creating_reservation:
                item_policy_problems.append(
                    f"You may only reserve up to {str(item.maximum_future_reservation_time)} minutes of time on this {item_type.value}, starting from the current time onward."
                )
            else:
                item_policy_problems.append(
                    f"{str(user)} may only reserve up to {str(item.maximum_future_reservation_time)} minutes of time on this {item_type.value}, starting from the current time onward."
                )

    return item_policy_problems
Beispiel #3
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'])
    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})
Beispiel #4
0
def modify_reservation(request, start_delta, end_delta):
    """
	Cancel the user's old reservation and create a new one. Reservations are cancelled and recreated so that
	reservation abuse can be tracked if necessary. This function should be called by other views and should
	not be tied directly to a URL.
	"""
    try:
        reservation_to_cancel = Reservation.objects.get(pk=request.POST['id'])
    except Reservation.DoesNotExist:
        return HttpResponseNotFound(
            "The reservation that you wish to modify doesn't exist!")
    response = check_policy_to_cancel_reservation(reservation_to_cancel,
                                                  request.user)
    # Do not move the reservation if the user was not authorized to cancel it.
    if response.status_code != HTTPStatus.OK:
        return response
    # Record the current time so that the timestamp of the cancelled reservation and the new reservation match exactly.
    now = timezone.now()
    # Cancel the user's original reservation.
    reservation_to_cancel.cancelled = True
    reservation_to_cancel.cancellation_time = now
    reservation_to_cancel.cancelled_by = request.user
    # Create a new reservation for the user.
    new_reservation = Reservation()
    new_reservation.title = reservation_to_cancel.title
    new_reservation.creator = request.user
    new_reservation.additional_information = reservation_to_cancel.additional_information
    # A change in start time will only be provided if the reservation is being moved.
    new_reservation.start = reservation_to_cancel.start
    new_reservation.self_configuration = reservation_to_cancel.self_configuration
    new_reservation.short_notice = False
    if start_delta:
        new_reservation.start += start_delta
    if new_reservation.self_configuration:
        # Reservation can't be short notice since the user is configuring the tool themselves.
        new_reservation.short_notice = False
    else:
        new_reservation.short_notice = determine_insufficient_notice(
            reservation_to_cancel.tool, new_reservation.start)
    # A change in end time will always be provided for reservation move and resize operations.
    new_reservation.end = reservation_to_cancel.end + end_delta
    new_reservation.tool = reservation_to_cancel.tool
    new_reservation.project = reservation_to_cancel.project
    new_reservation.user = reservation_to_cancel.user
    new_reservation.creation_time = now
    policy_problems, overridable = check_policy_to_save_reservation(
        reservation_to_cancel, new_reservation, request.user, False)
    if policy_problems:
        return HttpResponseBadRequest(policy_problems[0])
    else:
        # All policy checks passed, so save the reservation.
        new_reservation.save()
        reservation_to_cancel.descendant = new_reservation
        reservation_to_cancel.save()
    return response
Beispiel #5
0
def create_reservation(request):
    """ Create a reservation for a user. """
    try:
        start, end = extract_times(request.POST)
    except Exception as e:
        return HttpResponseBadRequest(str(e))
    tool = get_object_or_404(Tool, name=request.POST.get('tool_name'))
    explicit_policy_override = False
    if request.user.is_staff:
        try:
            user = User.objects.get(id=request.POST['impersonate'])
        except:
            user = request.user
        try:
            explicit_policy_override = request.POST[
                'explicit_policy_override'] == 'true'
        except:
            pass
    else:
        user = request.user
    # Create the new reservation:
    new_reservation = Reservation()
    new_reservation.user = user
    new_reservation.creator = request.user
    new_reservation.tool = tool
    new_reservation.start = start
    new_reservation.end = end
    new_reservation.short_notice = determine_insufficient_notice(tool, start)
    policy_problems, overridable = check_policy_to_save_reservation(
        None, new_reservation, user, explicit_policy_override)

    # If there was a problem in saving the reservation then return the error...
    if policy_problems:
        return render(
            request, 'calendar/policy_dialog.html', {
                'policy_problems': policy_problems,
                'overridable': overridable and request.user.is_staff
            })

    # All policy checks have passed.

    # If the user only has one project then associate it with the reservation.
    # Otherwise, present a dialog box for the user to choose which project to associate.
    active_projects = user.active_projects()
    if len(active_projects) == 1:
        new_reservation.project = active_projects[0]
    else:
        try:
            new_reservation.project = Project.objects.get(
                id=request.POST['project_id'])
        except:
            return render(request, 'calendar/project_choice.html',
                          {'active_projects': active_projects})

    # Make sure the user is actually enrolled on the project. We wouldn't want someone
    # forging a request to reserve against a project they don't belong to.
    if new_reservation.project not in new_reservation.user.active_projects():
        return render(request, 'calendar/project_choice.html',
                      {'active_projects': active_projects()})

    configured = (request.POST.get('configured') == "true")
    # If a reservation is requested and the tool does not require configuration...
    if not tool.is_configurable():
        new_reservation.save()
        return HttpResponse()

    # If a reservation is requested and the tool requires configuration that has not been submitted...
    elif tool.is_configurable() and not configured:
        configuration_information = tool.get_configuration_information(
            user=user, start=start)
        return render(request, 'calendar/configuration.html',
                      configuration_information)

    # If a reservation is requested and configuration information is present also...
    elif tool.is_configurable() and configured:
        new_reservation.additional_information, new_reservation.self_configuration = extract_configuration(
            request)
        # Reservation can't be short notice if the user is configuring the tool themselves.
        if new_reservation.self_configuration:
            new_reservation.short_notice = False
        new_reservation.save()
        return HttpResponse()

    return HttpResponseBadRequest(
        "Reservation creation failed because invalid parameters were sent to the server."
    )
Beispiel #6
0
def reserve_tool(request):
    tool = Tool.objects.get(id=request.POST['tool_id'])
    customer = User.objects.get(id=request.POST['customer_id'])
    project = Project.objects.get(id=request.POST['project_id'])
    back = request.POST['back']

    error_dictionary = {
        'back': back,
        'tool': tool,
        'project': project,
        'customer': customer,
    }
    """ 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:
        error_dictionary[
            'message'] = 'Please enter a valid date, start time, and end time for the reservation.'
        return render(request, 'kiosk/error.html', error_dictionary)
    # Create the new reservation:
    reservation = Reservation()
    reservation.project = project
    reservation.user = customer
    reservation.creator = customer
    reservation.reservation_item = tool
    reservation.start = start
    reservation.end = end
    reservation.short_notice = determine_insufficient_notice(tool, start)
    policy_problems, overridable = check_policy_to_save_reservation(
        cancelled_reservation=None,
        new_reservation=reservation,
        user_creating_reservation=customer,
        explicit_policy_override=False)

    # If there was a problem in saving the reservation then return the error...
    if policy_problems:
        error_dictionary['message'] = policy_problems[0]
        return render(request, 'kiosk/error.html', error_dictionary)

    # All policy checks have passed.
    if project is None and not customer.is_staff:
        error_dictionary[
            'message'] = 'You must specify a project for your reservation'
        return render(request, 'kiosk/error.html', error_dictionary)

    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, 'kiosk/success.html', {
        'new_reservation': reservation,
        'customer': customer
    })
Beispiel #7
0
def reserve_tool(request):
    tool = Tool.objects.get(id=request.POST["tool_id"])
    customer = User.objects.get(id=request.POST["customer_id"])
    project = Project.objects.get(id=request.POST["project_id"])
    back = request.POST["back"]

    error_dictionary = {
        "back": back,
        "tool": tool,
        "project": project,
        "customer": customer
    }
    """ 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:
        error_dictionary[
            "message"] = "Please enter a valid date, start time, and end time for the reservation."
        return render(request, "kiosk/error.html", error_dictionary)
    # Create the new reservation:
    reservation = Reservation()
    reservation.project = project
    reservation.user = customer
    reservation.creator = customer
    reservation.reservation_item = tool
    reservation.start = start
    reservation.end = end
    reservation.short_notice = determine_insufficient_notice(tool, start)
    policy_problems, overridable = check_policy_to_save_reservation(
        cancelled_reservation=None,
        new_reservation=reservation,
        user_creating_reservation=customer,
        explicit_policy_override=False,
    )

    # If there was a problem in saving the reservation then return the error...
    if policy_problems:
        error_dictionary["message"] = policy_problems[0]
        return render(request, "kiosk/error.html", error_dictionary)

    # All policy checks have passed.
    if project is None and not customer.is_staff:
        error_dictionary[
            "message"] = "You must specify a project for your reservation"
        return render(request, "kiosk/error.html", error_dictionary)

    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 questions if applicable
    try:
        reservation.question_data = extract_reservation_questions(
            request, ReservationItemType.TOOL, tool.id, reservation.project)
    except RequiredUnansweredQuestionsException as e:
        error_dictionary["message"] = str(e)
        return render(request, "kiosk/error.html", error_dictionary)

    reservation.save_and_notify()
    return render(request, "kiosk/success.html", {
        "new_reservation": reservation,
        "customer": customer
    })
Beispiel #8
0
def create_item_reservation(request, start, end, item_type: ReservationItemType, item_id):
	item = get_object_or_404(item_type.get_object_class(), id=item_id)
	explicit_policy_override = False
	if request.user.is_staff:
		try:
			user = User.objects.get(id=request.POST['impersonate'])
		except:
			user = request.user
		try:
			explicit_policy_override = request.POST['explicit_policy_override'] == 'true'
		except:
			pass
	else:
		user = request.user
	# Create the new reservation:
	new_reservation = Reservation()
	new_reservation.user = user
	new_reservation.creator = request.user
	# set tool or area
	setattr(new_reservation, item_type.value, item)
	new_reservation.start = start
	new_reservation.end = end
	new_reservation.short_notice = determine_insufficient_notice(item, start) if item_type == ReservationItemType.TOOL else False
	policy_problems, overridable = check_policy_to_save_reservation(cancelled_reservation=None, new_reservation=new_reservation, user_creating_reservation=request.user, explicit_policy_override=explicit_policy_override)

	# If there was a problem in saving the reservation then return the error...
	if policy_problems:
		return render(request, 'calendar/policy_dialog.html', {'policy_problems': policy_problems, 'overridable': overridable and request.user.is_staff, 'reservation_action': 'create'})

	# All policy checks have passed.

	# If the user only has one project then associate it with the reservation.
	# Otherwise, present a dialog box for the user to choose which project to associate.
	if not user.is_staff:
		active_projects = user.active_projects()
		if len(active_projects) == 1:
			new_reservation.project = active_projects[0]
		else:
			try:
				new_reservation.project = Project.objects.get(id=request.POST['project_id'])
			except:
				return render(request, 'calendar/project_choice.html', {'active_projects': active_projects})

		# Make sure the user is actually enrolled on the project. We wouldn't want someone
		# forging a request to reserve against a project they don't belong to.
		if new_reservation.project not in new_reservation.user.active_projects():
			return render(request, 'calendar/project_choice.html', {'active_projects': active_projects})

	# Configuration rules only apply to tools
	if item_type == ReservationItemType.TOOL:
		configured = (request.POST.get('configured') == "true")
		# If a reservation is requested and the tool does not require configuration...
		if not item.is_configurable():
			new_reservation.save_and_notify()
			return reservation_success(request, new_reservation)

		# If a reservation is requested and the tool requires configuration that has not been submitted...
		elif item.is_configurable() and not configured:
			configuration_information = item.get_configuration_information(user=user, start=start)
			return render(request, 'calendar/configuration.html', configuration_information)

		# If a reservation is requested and configuration information is present also...
		elif item.is_configurable() and configured:
			new_reservation.additional_information, new_reservation.self_configuration = extract_configuration(request)
			# Reservation can't be short notice if the user is configuring the tool themselves.
			if new_reservation.self_configuration:
				new_reservation.short_notice = False
			new_reservation.save_and_notify()
			return reservation_success(request, new_reservation)

	elif item_type == ReservationItemType.AREA:
		new_reservation.save_and_notify()
		return HttpResponse()

	return HttpResponseBadRequest("Reservation creation failed because invalid parameters were sent to the server.")
Beispiel #9
0
def make_reservation(request):
    # due to unexplained CSRF failures for users try a workaround
    http_origins = [
        'https://rea-demo.mri.psu.edu:8080',
        'https://rea-demo.mri.psu.edu:8888', 'https://leo.psu.edu'
    ]

    if request.META.get('HTTP_ORIGIN') in http_origins:
        origin = request.META.get('HTTP_ORIGIN')
        referer = str(origin) + "/new_reservation/" + str(
            request.POST.get('tool_id')) + "/" + str(
                request.POST['date']) + "/"

        if referer != request.META.get('HTTP_REFERER'):
            return render(request, 'mobile/error.html',
                          {'message': 'Unknown referer - request rejected'})
    else:
        return render(request, 'mobile/error.html',
                      {'message': 'Unknown origin - request rejected'})

    # 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.'
            })
    tool = get_object_or_404(Tool, id=request.POST.get('tool_id'))
    # Create the new reservation:
    reservation = Reservation()
    reservation.user = request.user
    reservation.creator = request.user
    reservation.tool = tool
    reservation.start = start
    reservation.end = end
    reservation.short_notice = determine_insufficient_notice(tool, start)
    policy_problems, overridable = check_policy_to_save_reservation(
        request, None, reservation, request.user, 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.

    if request.user.is_staff:
        mode = request.POST['staff_charge']

        if mode == "self":
            # make a reservation for the user and don't add a record to the ReservationProject table
            active_projects = request.user.active_projects()

            if len(active_projects) == 1:
                reservation.project = active_projects[0]
            else:
                try:
                    reservation.project = Project.objects.get(
                        id=request.POST['project_id'])
                except:
                    msg = 'No project was selected.  Please return to the <a href="/calendar/">calendar</a> to try again.'
                    return render(request, 'mobile/error.html',
                                  {'message': msg})

        else:
            # add ReservationProject entries for the customers submitted by the staff member
            reservation_projects = {}
            reservation.save()

            for key, value in request.POST.items():
                if is_valid_field(key):
                    attribute, separator, index = key.partition("__")
                    index = int(index)
                    if index not in reservation_projects:
                        reservation_projects[index] = ReservationProject()
                        reservation_projects[index].reservation = reservation
                        reservation_projects[index].created = timezone.now()
                        reservation_projects[index].updated = timezone.now()
                    if attribute == "chosen_user":
                        if value is not None and value != "":
                            reservation_projects[
                                index].customer = User.objects.get(id=value)
                        else:
                            reservation.delete()
                            return HttpResponseBadRequest(
                                'Please choose a user for whom the tool will be run.'
                            )
                    if attribute == "chosen_project":
                        if value is not None and value != "" and value != "-1":
                            reservation_projects[
                                index].project = Project.objects.get(id=value)
                        else:
                            reservation.delete()
                            return HttpResponseBadRequest(
                                'Please choose a project for charges made during this run.'
                            )

            for r in reservation_projects.values():
                r.full_clean()
                r.save()

    else:
        try:
            reservation.project = Project.objects.get(
                id=request.POST['project_id'])
        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, res_conf = 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
    policy_problems, overridable = check_policy_to_save_reservation(
        request, None, reservation, request.user, False)
    reservation.save()
    for rc in res_conf:
        rc.reservation = reservation
        rc.save()
    return render(request, 'mobile/reservation_success.html',
                  {'new_reservation': reservation})