Пример #1
0
def test_admin_may_bypass_min_period(resource_with_opening_hours, user):
    """
    Admin users should be able to bypass min_period,
    and their minimum reservation time should be limited by slot_size
    """
    activate('en')

    # min_period is bypassed respecting slot_size restriction
    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=0, minutes=30)

    UnitAuthorization.objects.create(
        subject=resource_with_opening_hours.unit,
        level=UnitAuthorizationLevel.admin,
        authorized=user,
    )

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end, user=user)
    reservation.clean()

    # min_period is bypassed and slot_size restriction is violated
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=25)
    resource_with_opening_hours.save()

    with pytest.raises(ValidationError) as error:
        reservation.clean()
    assert error.value.code == 'invalid_time_slot'
Пример #2
0
    def create_respa_outlook_reservation(self, appointment, reservation,
                                         email):
        if not appointment:
            return
        if not reservation:
            if not email:
                return
            reservation = Reservation(resource=self.resource,
                                      begin=appointment.start,
                                      end=appointment.end,
                                      reserver_email_address=email,
                                      state=Reservation.CONFIRMED)
            reservation.clean()
            reservation.save()
            ret = send_respa_mail(email_address=email,
                                  subject="Reservation created",
                                  body="Reservation via outlook created")
            print(ret[0], ret[1])

        RespaOutlookReservation(
            name='%s (%s)' %
            (reservation.reserver_email_address, self.resource.name),
            exchange_id=appointment.id,
            exchange_changekey=appointment.changekey,
            reservation=reservation).save()
Пример #3
0
def test_valid_reservation_duration_with_slot_size(resource_with_opening_hours):
    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=2, minutes=30)

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end)
    reservation.clean()
Пример #4
0
def test_invalid_reservation_duration_with_slot_size(resource_with_opening_hours):
    activate('en')

    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=2, minutes=45)

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end)

    with pytest.raises(ValidationError) as error:
        reservation.clean()
    assert error.value.code == 'invalid_time_slot'
Пример #5
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(_('You cannot make a reservation in the past'))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation, request_user, data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(dict(comments=_('Only allowed to be set by staff members')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        instance.clean(original_reservation=reservation)

        return data
Пример #6
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(
                _('You cannot make a reservation in the past'))

        if not resource.is_admin(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(
                    _('The resource is reservable only before %(datetime)s' %
                      {'datetime': reservable_before}))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation,
                                             request_user,
                                             data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(
                    dict(
                        comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] == None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(
                    dict(access_code=_(
                        'This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data[
                    'access_code'] != reservation.access_code:
                raise ValidationError(
                    dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation)
        except DjangoValidationError as exc:

            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)

        return data
Пример #7
0
    def test_reservation(self):
        r1a = Resource.objects.get(id='r1a')
        r1b = Resource.objects.get(id='r1b')

        tz = timezone.get_current_timezone()
        begin = tz.localize(datetime.datetime(2116, 6, 1, 8, 0, 0))
        end = begin + datetime.timedelta(hours=2)

        reservation = Reservation.objects.create(resource=r1a, begin=begin, end=end)
        reservation.clean()

        # Attempt overlapping reservation
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=begin, end=end)
            reservation.clean()

        valid_begin = begin + datetime.timedelta(hours=3)
        valid_end = end + datetime.timedelta(hours=3)

        # Attempt incorrectly aligned begin time
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=valid_begin + datetime.timedelta(minutes=1), end=valid_end)
            reservation.clean()

        # Attempt incorrectly aligned end time
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=valid_begin, end=valid_end + datetime.timedelta(minutes=1))
            reservation.clean()

        # Attempt reservation that starts before the resource opens
        # Should not raise an exception as this check isn't included in model clean
        reservation = Reservation(
            resource=r1a,
            begin=begin - datetime.timedelta(hours=1),
            end=begin
        )
        reservation.clean()

        begin = tz.localize(datetime.datetime(2116, 6, 1, 16, 0, 0))
        end = begin + datetime.timedelta(hours=2)

        # Make a reservation that ends when the resource closes
        reservation = Reservation(resource=r1a, begin=begin, end=end)
        reservation.clean()

        # Attempt reservation that ends after the resource closes
        # Should not raise an exception as this check isn't included in model clean
        reservation = Reservation(resource=r1a, begin=begin, end=end + datetime.timedelta(hours=1))
        reservation.clean()
Пример #8
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user
        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource
            data.update({'resource': resource})

        if not data.get('begin', None):
            data.update({'begin': reservation.begin})

        if not data.get('end', None):
            data.update({'end': reservation.end})

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied(
                _('You are not allowed to make reservations in this resource.')
            )

        if data['end'] < timezone.now():
            raise ValidationError(
                _('You cannot make a reservation in the past'))

        if resource.min_age and is_underage(request_user, resource.min_age):
            raise PermissionDenied(
                _('You have to be over %s years old to reserve this resource' %
                  (resource.min_age)))

        if resource.max_age and is_overage(request_user, resource.max_age):
            raise PermissionDenied(
                _('You have to be under %s years old to reserve this resource'
                  % (resource.max_age)))

        is_resource_admin = resource.is_admin(request_user)
        is_resource_manager = resource.is_manager(request_user)

        if not isinstance(request_user, AnonymousUser):
            if request_user.preferred_language is None:
                request_user.preferred_language = settings.LANGUAGES[0][0]
                request_user.save()

        if not resource.can_ignore_opening_hours(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(
                    _('The resource is reservable only before %(datetime)s' %
                      {'datetime': reservable_before}))
            reservable_after = resource.get_reservable_after()
            if reservable_after and data['begin'] < reservable_after:
                raise ValidationError(
                    _('The resource is reservable only after %(datetime)s' %
                      {'datetime': reservable_after}))

        # Check given home municipality is included in resource's home municipality set
        if 'home_municipality' in data:
            included = resource.get_included_home_municipality_names()
            found = False

            for municipality in included:
                if data['home_municipality'].id == municipality['id']:
                    found = True
                    break

            if not found:
                raise ValidationError(
                    _('Home municipality has to be one of the included home municipality options'
                      ))

        # normal users cannot make reservations for other people
        if not resource.can_create_reservations_for_other_users(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation,
                                             request_user,
                                             data=data)
        reserver_phone_number = data.get('reserver_phone_number', '')
        if reserver_phone_number.startswith('+'):
            if not region_code_for_country_code(
                    phonenumbers.parse(reserver_phone_number).country_code):
                raise ValidationError(
                    dict(reserver_phone_number=_('Invalid country code')))

        if data.get('staff_event', False):
            if not resource.can_create_staff_event(request_user):
                raise ValidationError(
                    dict(staff_event=_(
                        'Only allowed to be set by resource managers')))

        if 'type' in data:
            if (data['type'] != Reservation.TYPE_NORMAL
                    and not resource.can_create_special_type_reservation(
                        request_user)):
                raise ValidationError({
                    'type':
                    _('You are not allowed to make a reservation of this type')
                })

        if 'comments' in data:
            if not resource.can_comment_reservations(request_user):
                raise ValidationError(
                    dict(
                        comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] is None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(
                    dict(access_code=_(
                        'This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data[
                    'access_code'] != reservation.access_code:
                raise ValidationError(
                    dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None and not isinstance(request_user, AnonymousUser):
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation, user=request_user)
        except DjangoValidationError as exc:
            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)
        return data
Пример #9
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(_('You cannot make a reservation in the past'))

        if not resource.is_admin(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(_('The resource is reservable only before %(datetime)s' %
                                        {'datetime': reservable_before}))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation, request_user, data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(dict(comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] == None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(dict(access_code=_('This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data['access_code'] != reservation.access_code:
                raise ValidationError(dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation)
        except DjangoValidationError as exc:

            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)

        return data