def cancel_booking(db: directives.PeeweeSession,
                   secret: hug.types.text,
                   start_date_time: hug.types.text,
                   for_real: hug.types.smart_boolean = False):
    with db.atomic():
        sdt = datetime.fromisoformat(start_date_time).replace(tzinfo=None)
        timeslot = TimeSlot.get(TimeSlot.start_date_time == sdt)
        booking = Booking.select(Booking).join(
            Appointment).where((Booking.secret == secret)
                               & (Appointment.time_slot == timeslot)).get()

        if not for_real:
            print(
                f"This would delete the booking with id '{booking.id}' and secret '{booking.secret}'. Run with "
                f"--for_real if you are sure.")
            sys.exit(1)
        else:
            print(
                f"Deleting the booking with id '{booking.id}' and secret '{booking.secret}'."
            )
            booking.appointment.booked = False
            booking.appointment.save()
            q = Booking.delete().where(Booking.id == booking.id)
            q.execute()
            print("Done.")
Beispiel #2
0
def test_create_appointments(testing_db):
    assert len(Booking.select()) == 0
    assert len(TimeSlot.select()) == 0
    assert len(Appointment.select()) == 0
    NUM_SLOTS = 5
    NUM_APPOINTMENTS = 3
    create_kwargs = {
        'day': 20,
        'month': 4,
        'year': 2020,
        'start_hour': 16,
        'start_min': 20,
        'num_slots': NUM_SLOTS,
        'num_appointment_per_slot': NUM_APPOINTMENTS,
        'slot_duration_min': 10
    }
    hug.test.cli('create_appointments', module='main', **create_kwargs)
    assert len(Booking.select()) == 0
    assert len(TimeSlot.select()) == NUM_SLOTS
    assert len(Appointment.select()) == NUM_APPOINTMENTS * NUM_SLOTS
    sdt = datetime(2020, 4, 20, 16, 20, tzinfo=None)
    for i in range(NUM_SLOTS):
        ts = TimeSlot.get(TimeSlot.start_date_time == sdt +
                          timedelta(minutes=10 * i))
        assert Appointment.select().where(
            Appointment.time_slot == ts).count() == NUM_APPOINTMENTS
def book_appointment(db: PeeweeSession, body: hug.types.json, user: hug.directives.user):
    with db.atomic():
        try:
            assert user.coupons > 0
            if all(key in body for key in ('claim_token', 'start_date_time', 'first_name', 'name', 'phone', 'office')):
                claim_token = body['claim_token']
                start_date_time = body['start_date_time']
                start_date_time_object = datetime.fromisoformat(start_date_time)
                now = datetime.now(tz=config.Settings.tz).replace(tzinfo=None)
                if start_date_time_object < now:
                    raise ValueError("Can't claim an appointment in the past")
                time_slot = TimeSlot.get(TimeSlot.start_date_time == start_date_time_object)
                appointment = Appointment.get(
                    (Appointment.time_slot == time_slot) &
                    (Appointment.booked == False) &
                    (Appointment.claim_token == claim_token)
                )
                appointment.booked = True
                appointment.claim_token = None
                appointment.claimed_at = None
                appointment.save()
                success = False
                with db.atomic():
                    while not success:
                        secret = get_secret_token(6)
                        try:
                            SlotCode.create(date=time_slot.start_date_time.date(), secret=secret)
                            success = True
                        except IntegrityError as e:  # in the offchance that we had a collision with secret codes, retry
                            pass

                booking = Booking.create(appointment=appointment, first_name=body['first_name'], surname=body['name'],
                                         phone=body['phone'], office=body['office'], secret=secret,
                                         booked_by=user.user_name)
                booking.save()
                user.coupons -= 1
                user.save()
                return {
                    "secret": booking.secret,
                    "time_slot": time_slot.start_date_time,
                    "slot_length_min": time_slot.length_min
                }
            else:
                raise ValueError("Missing parameter")
        except DoesNotExist as e:
            raise hug.HTTPGone
        except ValueError as e:
            raise hug.HTTPBadRequest
        except AssertionError as e:
            raise hug.HTTPBadRequest
Beispiel #4
0
def claim_appointment(db: PeeweeSession, start_date_time: hug.types.text,
                      user: hug.directives.user):
    """
    UPDATE appointment app
    SET claim_token = 'claimed'
    WHERE app.id
          IN (
              SELECT a.id FROM appointment a
                                 JOIN timeslot t on a.time_slot_id = t.id
              WHERE t.start_date_time = '2020-03-25 08:30:00.000000'
                AND a.claim_token isnull
                AND NOT a.booked
              LIMIT 1
              )
    RETURNING *
    """
    with db.atomic():
        try:
            if user.role != UserRoles.ANON:
                assert user.coupons > 0
            start_date_time_object = datetime.fromisoformat(start_date_time)
            now = datetime.now(tz=config.Settings.tz).replace(tzinfo=None)
            if start_date_time_object < now:
                raise ValueError("Can't claim an appointment in the past")
            time_slot = TimeSlot.get(
                TimeSlot.start_date_time == start_date_time_object)
            appointment = Appointment.select() \
                .where(
                (Appointment.time_slot == time_slot) &
                (Appointment.booked == False) &
                (Appointment.claim_token.is_null() | (Appointment.claimed_at +
                                                      timedelta(
                                                          minutes=config.Settings.claim_timeout_min) < now))
            ) \
                .order_by(Appointment.claim_token.desc()) \
                .get()
            appointment.claim_token = get_random_string(32)
            appointment.claimed_at = now
            appointment.save()
            return appointment.claim_token
        except DoesNotExist as e:
            raise hug.HTTPGone
        except ValueError as e:
            raise hug.HTTPBadRequest
        except AssertionError as e:
            raise hug.HTTPBadRequest
Beispiel #5
0
def test_delete_timeslots(testing_db):
    # this test assumes that create_apointments and cancel_booking both work. They are under test also.
    # first, lets create some timeslots
    NUM_SLOTS = 5
    NUM_APPOINTMENTS = 3
    create_kwargs = {
        'day': 20,
        'month': 4,
        'year': 2020,
        'start_hour': 16,
        'start_min': 20,
        'num_slots': NUM_SLOTS,
        'num_appointment_per_slot': NUM_APPOINTMENTS,
        'slot_duration_min': 10
    }
    hug.test.cli('create_appointments', module='main', **create_kwargs)
    assert len(Booking.select()) == 0
    assert len(TimeSlot.select()) == NUM_SLOTS
    assert len(Appointment.select()) == NUM_APPOINTMENTS * NUM_SLOTS

    # now, lets create two bookings, one of them in a to-be-deleted timeslot
    booking_data = {
        'surname': "Mustermann",
        'first_name': "Marianne",
        'phone': "0123456789",
        'office': "MusterOffice",
        'booked_by': USER,
        'booked_at': datetime.now()
    }
    sdt1 = datetime(2020, 4, 20, 16, 20, tzinfo=None)
    sdt2 = datetime(2020, 4, 20, 16, 40, tzinfo=None)
    a1 = Appointment.get(Appointment.time_slot == TimeSlot.get(TimeSlot.start_date_time == sdt1))
    a2 = Appointment.get(Appointment.time_slot == TimeSlot.get(TimeSlot.start_date_time == sdt2))
    a1.booked = True
    a1.save()
    a2.booked = True
    a2.save()
    Booking.create(**booking_data, secret="secret1", appointment=a1)
    Booking.create(**booking_data, secret="secret2", appointment=a2)

    # with a booking in a timeslot, we should not delete
    delete_kwargs = {
        'year': 2020,
        'month': 4,
        'day': 20,
        'start_hour': 16,
        'start_min': 30,
        'num_slots': 2,
        'for_real': True
    }
    hug.test.cli('delete_timeslots', module='main', **delete_kwargs)
    assert len(Booking.select()) == 2
    assert len(TimeSlot.select()) == NUM_SLOTS
    assert len(Appointment.select()) == NUM_APPOINTMENTS * NUM_SLOTS

    # so let's cancel the booking that conflicts
    hug.test.cli('cancel_booking', module='main', secret='secret2', start_date_time='2020-04-20T16:40', for_real=True)
    assert len(Booking.select()) == 1
    assert len(TimeSlot.select()) == NUM_SLOTS
    assert len(Appointment.select()) == NUM_APPOINTMENTS * NUM_SLOTS

    # and now let's retry the deletion
    hug.test.cli('delete_timeslots', module='main', **delete_kwargs)
    assert len(Booking.select()) == 1
    assert len(TimeSlot.select()) == 3
    assert len(Appointment.select()) == 9
    for i in [0, 3, 4]:
        ts = TimeSlot.get(TimeSlot.start_date_time == sdt1 + timedelta(minutes=10 * i))
        assert Appointment.select().where(Appointment.time_slot == ts).count() == NUM_APPOINTMENTS