Esempio n. 1
0
def new_reservation(request, item_type, item_id, date=None):
    # If the user has no active projects then they're not allowed to make reservations.
    user: User = request.user
    if user.active_project_count() == 0:
        return render(request, 'mobile/no_active_projects.html')

    item_type = ReservationItemType(item_type)
    item = get_object_or_404(item_type.get_object_class(), id=item_id)
    if item_type == ReservationItemType.TOOL:
        dictionary = item.get_configuration_information(user=request.user,
                                                        start=None)
    else:
        dictionary = {}
    dictionary['item'] = item
    dictionary['item_type'] = item_type.value
    dictionary['date'] = date
    dictionary['item_reservation_times'] = list(
        Reservation.objects.filter(**{
            item_type.value: item
        }).filter(cancelled=False,
                  missed=False,
                  shortened=False,
                  start__gte=timezone.now()))

    # Reservation questions if applicable
    if not user.is_staff:
        reservation_question_dict = {}
        for project in user.active_projects():
            reservation_questions = render_reservation_questions(
                item_type, item_id, project)
            if reservation_questions:
                reservation_question_dict[project.id] = reservation_questions
        dictionary['reservation_questions'] = reservation_question_dict

    return render(request, 'mobile/new_reservation.html', dictionary)
Esempio n. 2
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})
Esempio n. 3
0
def view_calendar(request, item_type, item_id, date=None):
    item_type = ReservationItemType(item_type)
    item = get_object_or_404(item_type.get_object_class(), id=item_id)
    if date:
        try:
            date = extract_date(date)
        except:
            render(request, 'mobile/error.html',
                   {'message': 'Invalid date requested for tool calendar'})
            return HttpResponseBadRequest()
    else:
        date = datetime.now()

    start = beginning_of_the_day(date, in_local_timezone=True)
    end = end_of_the_day(date, in_local_timezone=True)

    reservations = Reservation.objects.filter(**{
        item_type.value: item
    }).filter(cancelled=False, missed=False, shortened=False).filter(**{})
    # Exclude events for which the following is true:
    # The event starts and ends before the time-window, and...
    # The event starts and ends after the time-window.
    reservations = reservations.exclude(start__lt=start, end__lt=start)
    reservations = reservations.exclude(start__gt=end, end__gt=end)

    outages = ScheduledOutage.objects.none()
    if item_type == ReservationItemType.TOOL:
        outages = ScheduledOutage.objects.filter(
            Q(tool=item) | Q(resource__fully_dependent_tools__in=[item]))
    elif item_type == ReservationItemType.AREA:
        outages = item.scheduled_outage_queryset()

    # Exclude outages for which the following is true:
    # The outage starts and ends before the time-window, and...
    # The outage starts and ends after the time-window.
    outages = outages.exclude(start__lt=start, end__lt=start)
    outages = outages.exclude(start__gt=end, end__gt=end)

    events = list(chain(reservations, outages))
    events.sort(key=lambda x: x.start)

    dictionary = {
        'item': item,
        'item_type': item_type.value,
        'previous_day': start - timedelta(days=1),
        'current_day': start,
        'current_day_string': date.strftime('%Y-%m-%d'),
        'next_day': start + timedelta(days=1),
        'events': events,
    }

    return render(request, 'mobile/view_calendar.html', dictionary)
Esempio n. 4
0
def create_reservation(request):
	""" Create a reservation for a user. """
	try:
		start, end = extract_times(request.POST)
		item_type = request.POST['item_type']
		item_id = request.POST.get('item_id')
	except Exception as e:
		return HttpResponseBadRequest(str(e))
	return create_item_reservation(request, start, end, ReservationItemType(item_type), item_id)
Esempio n. 5
0
def refresh_sidebar_icons(request, item_type=None):
    area_summary = []
    tool_summary = []
    item_type = ReservationItemType(item_type)
    if item_type == ReservationItemType.NONE:
        tool_summary = create_tool_summary()
        area_summary = create_area_summary()
    elif item_type == ReservationItemType.AREA:
        area_summary = create_area_summary()
    elif item_type == ReservationItemType.TOOL:
        tool_summary = create_tool_summary()

    return render(request, 'refresh_sidebar_icons.html', {
        'tool_summary': tool_summary,
        'area_summary': area_summary
    })
Esempio n. 6
0
def shorten_reservation(user: User, item: Union[Area, Tool], new_end: datetime = None):
	try:
		if new_end is None:
			new_end = timezone.now()
		current_reservation = Reservation.objects.filter(start__lt=timezone.now(), end__gt=timezone.now(),
														 cancelled=False, missed=False, shortened=False, user=user)
		current_reservation = current_reservation.get(**{ReservationItemType.from_item(item).value: item})
		# Staff are exempt from mandatory reservation shortening.
		if user.is_staff is False:
			new_reservation = deepcopy(current_reservation)
			new_reservation.id = None
			new_reservation.pk = None
			new_reservation.end = new_end
			new_reservation.save()
			current_reservation.shortened = True
			current_reservation.descendant = new_reservation
			current_reservation.save()
	except Reservation.DoesNotExist:
		pass
Esempio n. 7
0
def usage_event_feed(request, start, end):
	usage_events = UsageEvent.objects
	# Exclude events for which the following is true:
	# The event starts and ends before the time-window, and...
	# The event starts and ends after the time-window.
	usage_events = usage_events.exclude(start__lt=start, end__lt=start)
	usage_events = usage_events.exclude(start__gt=end, end__gt=end)

	# Filter events that only have to do with the relevant tool.
	item_id = request.GET.get('item_id')
	item_type = ReservationItemType(request.GET.get('item_type')) if request.GET.get('item_type') else None
	if item_id and item_type == ReservationItemType.TOOL:
		usage_events = usage_events.filter(tool__id__in=Tool.objects.get(pk=item_id).get_family_tool_ids())

	area_access_events = None
	# Filter events that only have to do with the current user.
	personal_schedule = request.GET.get('personal_schedule')
	if personal_schedule:
		usage_events = usage_events.filter(user=request.user)
		# Display area access along side tool usage when 'personal schedule' is selected.
		area_access_events = AreaAccessRecord.objects.filter(customer__id=request.user.id)
		area_access_events = area_access_events.exclude(start__lt=start, end__lt=start)
		area_access_events = area_access_events.exclude(start__gt=end, end__gt=end)

	missed_reservations = None
	if personal_schedule:
		missed_reservations = Reservation.objects.filter(missed=True, user=request.user)
	elif item_type:
		reservation_filter = {item_type.value: item_id}
		missed_reservations = Reservation.objects.filter(missed=True).filter(**reservation_filter)
	if missed_reservations:
		missed_reservations = missed_reservations.exclude(start__lt=start, end__lt=start)
		missed_reservations = missed_reservations.exclude(start__gt=end, end__gt=end)

	dictionary = {
		'usage_events': usage_events,
		'area_access_events': area_access_events,
		'personal_schedule': personal_schedule,
		'missed_reservations': missed_reservations,
	}
	return render(request, 'calendar/usage_event_feed.html', dictionary)
Esempio n. 8
0
def reservation_event_feed(request, start, end):
	events = Reservation.objects.filter(cancelled=False, missed=False, shortened=False)
	outages = ScheduledOutage.objects.none()
	# Exclude events for which the following is true:
	# The event starts and ends before the time-window, and...
	# The event starts and ends after the time-window.
	events = events.exclude(start__lt=start, end__lt=start)
	events = events.exclude(start__gt=end, end__gt=end)

	# Filter events that only have to do with the relevant tool/area.
	item_type = request.GET.get('item_type')
	if item_type:
		item_type = ReservationItemType(item_type)
		item_id = request.GET.get('item_id')
		if item_id:
			events = events.filter(**{f'{item_type.value}__id': item_id})
			if item_type == ReservationItemType.TOOL:
				outages = ScheduledOutage.objects.filter(Q(tool=item_id) | Q(resource__fully_dependent_tools__in=[item_id]))
			elif item_type == ReservationItemType.AREA:
				outages = Area.objects.get(pk=item_id).scheduled_outage_queryset()

	# Exclude outages for which the following is true:
	# The outage starts and ends before the time-window, and...
	# The outage starts and ends after the time-window.
	outages = outages.exclude(start__lt=start, end__lt=start)
	outages = outages.exclude(start__gt=end, end__gt=end)

	# Filter events that only have to do with the current user.
	personal_schedule = request.GET.get('personal_schedule')
	if personal_schedule:
		events = events.filter(user=request.user)

	dictionary = {
		'events': events,
		'outages': outages,
		'personal_schedule': personal_schedule,
	}
	return render(request, 'calendar/reservation_event_feed.html', dictionary)
Esempio n. 9
0
 def get_target(self):
     target = self.cleaned_data["target"].split("|", 1)
     return ReservationItemType(target[0]), int(target[1])
Esempio n. 10
0
def create_outage(request):
	""" Create an outage. """
	try:
		start, end = extract_times(request.POST)
		item_type = ReservationItemType(request.POST['item_type'])
		item_id = request.POST.get('item_id')
	except Exception as e:
		return HttpResponseBadRequest(str(e))
	item = get_object_or_404(item_type.get_object_class(), id=item_id)
	# Create the new reservation:
	outage = ScheduledOutage()
	outage.creator = request.user
	outage.category = request.POST.get('category', '')[:200]
	outage.outage_item = item
	outage.start = start
	outage.end = end

	# If there is a policy problem for the outage then return the error...
	policy_problem = check_policy_to_create_outage(outage)
	if policy_problem:
		return HttpResponseBadRequest(policy_problem)

	# Make sure there is at least an outage title
	if not request.POST.get('title'):
		dictionary = {
			'categories': ScheduledOutageCategory.objects.all(),
			'recurrence_intervals': recurrence_frequency_display,
			'recurrence_date_start': start.date(),
		}
		return render(request, 'calendar/scheduled_outage_information.html', dictionary)

	outage.title = request.POST['title']
	outage.details = request.POST.get('details', '')

	if request.POST.get('recurring_outage') == 'on':
		# we have to remove tz before creating rules otherwise 8am would become 7am after DST change for example.
		start_no_tz = outage.start.replace(tzinfo=None)
		end_no_tz = outage.end.replace(tzinfo=None)

		submitted_frequency = request.POST.get('recurrence_frequency')
		submitted_date_until = request.POST.get('recurrence_until', None)
		date_until = end.replace(hour=0, minute=0, second=0)
		if submitted_date_until:
			date_until = localize(datetime.strptime(submitted_date_until, '%m/%d/%Y'))
		date_until += timedelta(days=1, seconds=-1) # set at the end of the day
		by_week_day = None
		if submitted_frequency == 'DAILY_WEEKDAYS':
			by_week_day = (rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR)
		elif submitted_frequency == 'DAILY_WEEKENDS':
			by_week_day = (rrule.SA, rrule.SU)
		frequency = recurrence_frequencies.get(submitted_frequency, rrule.DAILY)
		rules: Iterable[datetime] = rrule.rrule(dtstart=start, freq=frequency, interval=int(request.POST.get('recurrence_interval',1)), until=date_until, byweekday=by_week_day)
		for rule in list(rules):
			recurring_outage = ScheduledOutage()
			recurring_outage.creator = outage.creator
			recurring_outage.category = outage.category
			recurring_outage.outage_item = outage.outage_item
			recurring_outage.title = outage.title
			recurring_outage.details = outage.details
			recurring_outage.start = localize(start_no_tz.replace(year=rule.year, month=rule.month, day=rule.day))
			recurring_outage.end = localize(end_no_tz.replace(year=rule.year, month=rule.month, day=rule.day))
			recurring_outage.save()
	else:
		outage.save()

	return HttpResponse()
Esempio n. 11
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.")
Esempio n. 12
0
 def get_target(self):
     target = self.cleaned_data['target'].split('|', 1)
     return ReservationItemType(target[0]), int(target[1])