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
def booked(db: PeeweeSession, user: hug.directives.user, start_date: hug.types.text, end_date: hug.types.text): user_name = user.user_name with db.atomic(): try: user_role = user.role start_day_object = date.fromisoformat(start_date) end_day_object = date.fromisoformat(end_date) if user_role != UserRoles.ADMIN: start_day_object = date.fromisoformat('2021-01-01') #FIXME: hack to show users all their bookings end_day_object = date.fromisoformat('2022-12-31') #FIXME: hack to show users all their bookings bookings = [] for timeslot in TimeSlot.select().where((TimeSlot.start_date_time >= start_day_object) & (TimeSlot.start_date_time < end_day_object + timedelta(days=1))) \ .order_by(TimeSlot.start_date_time.desc()): for appointment in Appointment.select().where( (Appointment.time_slot == timeslot) & (Appointment.booked == True)): try: booking = Booking.get( Booking.appointment == appointment) if user_role != UserRoles.ADMIN: booking = Booking.select().where((Booking.appointment == appointment) & (Booking.booked_by == user_name)).get() bookings.append({'start_date_time': timeslot.start_date_time, 'first_name': booking.first_name, 'surname': booking.surname, 'phone': booking.phone, 'office': booking.office, 'secret': booking.secret, 'booked_by': booking.booked_by, 'booked_at': booking.booked_at, 'booking_id': booking.get_id()}) except DoesNotExist as e: pass return bookings except DoesNotExist as e: raise hug.HTTPGone except ValueError as e: raise hug.HTTPBadRequest
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.")
def set_frontend_config(db: directives.PeeweeSession, instance_name: hug.types.text, long_instance_name: hug.types.text, contact_info_bookings: hug.types.text, contact_info_appointments: hug.types.text = None, form_fields: hug.types.text = "base,address,dayOfBirth,reason", for_real: hug.types.smart_boolean = False): with db.atomic(): if not contact_info_appointments: appointments_contact = contact_info_bookings else: appointments_contact = contact_info_appointments template = { "instanceName": f"{instance_name}", "longInstanceName": f"{long_instance_name}", "contactInfoCoupons": f"{contact_info_bookings}", "contactInfoAppointment": f"{appointments_contact}", "formFields": form_fields.split(","), } if not for_real: print(f"This would update the config with '{json.dumps(template, indent=2)}'. Run with --for_real if you " f"are sure.") sys.exit(1) else: print( f"Updating the config with '{json.dumps(template, indent=2)}'.") try: config = FrontendConfig.get() config.config = template except FrontendConfig.DoesNotExist: config = FrontendConfig.create(config=template) config.save() print("Done.")
def load_frontend_config(db: directives.PeeweeSession, frontend_config_file: hug.types.text, for_real: hug.types.smart_boolean = False): with db.atomic(): with open(frontend_config_file, 'r') as j_file: try: new_config = json.load(j_file) if 'instanceName' not in new_config or 'longInstanceName' not in new_config or \ 'contactInfoCoupons' not in new_config \ or 'contactInfoAppointment' not in new_config or 'formFields' not in new_config: print( f"Given file '{json.dumps(new_config, indent=2)}' missing required fields!") sys.exit(1) elif type(new_config['formFields']) != list: print("field formFields is not a list!") sys.exit(1) except json.JSONDecodeError as e: print("The file can not decoded as json!") sys.exit(1) if not for_real: print( f"This would update the config with '{json.dumps(new_config, indent=2)}'. " f"Run with --for_real if you are sure.") sys.exit(1) else: print( f"Updating the config with '{json.dumps(new_config, indent=2)}'.") try: config = FrontendConfig.get() config.config = new_config except FrontendConfig.DoesNotExist: config = FrontendConfig.create(config=new_config) config.save() print("Done.")
def init_database(db: PeeweeSession): log.info("Initializing the Database") with db.atomic(): db_proxy.create_tables(tables) log.info("Tables created. Setting migration level.") Migration.create(version=2) log.info("Migration level set.")
def get_bookings_created_at(db: directives.PeeweeSession, booked_at: hug.types.text): """ [--booked_at <ISO datetime string>] get all bookings made at specific day or time Get bookings for a day with yyyy-mm-dd or one specific booking at yyyy-mm-ddThh:mm:ss.mmmmmm """ with db.atomic(): query = Booking.select( Booking, Appointment.time_slot.start_date_time.alias("start_date_time") ).join(Appointment).join(TimeSlot) booked_start = datetime.fromisoformat(booked_at).replace(tzinfo=None) if str(booked_start.date()) == booked_at: # booked_at is yyyy-mm-dd booked_end = booked_start.date() + timedelta(days=1) bookings = query.where( Booking.booked_at.between(booked_start, booked_end)) else: # booked_at is yyyy-mm-ddThh:mm:ss.mmmmmm bookings = query.where(Booking.booked_at == booked_start) result = [] for booking in bookings.dicts().iterator(): del booking["appointment"] result.append({**booking}) return result
def list_for_day(db: PeeweeSession, user: hug.directives.user, date_of_day: hug.types.text = None): if not date_of_day: date_of_day = (date.today() + timedelta(days=1)).isoformat() user_name = user.user_name with db.atomic(): try: user_role = user.role requested_day_object = date.fromisoformat(date_of_day) result = io.StringIO() writer = csv.DictWriter(result, fieldnames=['start_date_time', 'first_name', 'surname', 'phone', 'office', 'secret', 'booked_by']) writer.writeheader() for timeslot in TimeSlot.select().where( (TimeSlot.start_date_time > requested_day_object - timedelta(days=1)) & (TimeSlot.start_date_time < requested_day_object + timedelta(days=1))): for appointment in Appointment.select().where( (Appointment.time_slot == timeslot) & (Appointment.booked == True)): try: booking = Booking.get(Booking.appointment == appointment) if user_role != UserRoles.ADMIN: booking = Booking.select().where((Booking.appointment == appointment) & (Booking.booked_by == user_name)).get() writer.writerow({'start_date_time': timeslot.start_date_time, 'first_name': booking.first_name, 'surname': booking.surname, 'phone': booking.phone, 'office': booking.office, 'secret': booking.secret, 'booked_by': booking.booked_by}) except DoesNotExist as e: pass return result.getvalue().encode('utf8') except DoesNotExist as e: raise hug.HTTPGone except ValueError as e: raise hug.HTTPBadRequest
def set_coupon_count(db: directives.PeeweeSession, user_name: hug.types.text, value: hug.types.number): """ [--user_name] <string> [--value] <number>; set the user coupon_count to <value> """ with db.atomic(): user = User.get(User.user_name == user_name) user.coupons = value user.save()
def inc_coupon_count(db: directives.PeeweeSession, user_name: hug.types.text, increment: hug.types.number): """ [--user_name] <string> [--increment] <number>; increment the user coupon_count, to decrement give a negative number """ with db.atomic(): user = User.get(User.user_name == user_name) user.coupons += increment user.save()
def delete_claim_token(db: PeeweeSession, claim_token: hug.types.text): with db.atomic(): try: appointment = Appointment.get((Appointment.booked == False) & ( Appointment.claim_token == claim_token)) appointment.claim_token = None appointment.claimed_at = None appointment.save() except DoesNotExist as e: pass except ValueError as e: pass
def _add_one_user(db: directives.PeeweeSession, username: hug.types.text, password: hug.types.text = None, role: hug.types.one_of(UserRoles.user_roles()) = UserRoles.USER, coupons: hug.types.number = 10): with db.atomic(): name = username.lower() salt = get_random_string(2) secret_password = password or get_random_string(12) hashed_password = hash_pw(name, salt, secret_password) user = User.create(user_name=name, role=role, salt=salt, password=hashed_password, coupons=coupons) user.save() return {"name": user.user_name, "password": secret_password}
def delete_timeslots(db: directives.PeeweeSession, year: hug.types.number, month: hug.types.number, day: hug.types.number, start_hour: hug.types.number, start_min: hug.types.number, num_slots: hug.types.number, for_real: hug.types.boolean = False): with db.atomic(): dto = datetime(year, month, day, start_hour, start_min, tzinfo=None) tomorrow = datetime(year, month, day, tzinfo=None) + timedelta(days=1) ts = TimeSlot.select().where((TimeSlot.start_date_time >= dto) & ( TimeSlot.start_date_time < tomorrow)).order_by( TimeSlot.start_date_time).limit(num_slots) if not for_real: log.info( f"I would delete the following time slots - run with --for_real if these are correct" ) else: log.info(f"Deleting the following time slots") tsids_to_delete = [] for t in ts: tsids_to_delete.append(t.id) log.info(f"ID: {t.id} - {t.start_date_time}") if not tsids_to_delete: log.error("No matching timeslots found! Exiting.") sys.exit(1) apts = Appointment.select().where( Appointment.time_slot.in_(tsids_to_delete)) log.info( f"this {'will' if for_real else 'would'} affect the following appointments" ) apts_to_delete = [] for apt in apts: apts_to_delete.append(apt) log.info( f"ID: {apt.id} - {apt.time_slot.start_date_time}: {'booked!' if apt.booked else 'free'}" ) if all(not apt.booked for apt in apts_to_delete): log.info( f"none of these appointments are booked, so I {'will' if for_real else 'would'} delete them" ) if for_real: aq = Appointment.delete().where( Appointment.id.in_([a.id for a in apts_to_delete])) tq = TimeSlot.delete().where(TimeSlot.id.in_(tsids_to_delete)) aq.execute() tq.execute() log.info("Done!") else: log.error( f"Some of these appointments are already booked, {'will' if for_real else 'would'} not delete!" )
def init_db(db: directives.PeeweeSession, for_real: hug.types.smart_boolean = False): if not for_real: print('this will create the database (potentially destroying data), run with --for_real, if you are sure ' '*and* have a backup') sys.exit(1) else: with db.atomic(): try: migration = Migration.get() print(f'Migration level is already set to version {migration.version} - implying the db has already been ' f'initialized. Run command `run_migrations` instead.') sys.exit(1) except DatabaseError: init_database()
def delete_booking(db: PeeweeSession, user: hug.directives.user, booking_id: hug.types.text): if user.role == UserRoles.ADMIN: with db.atomic(): try: booking = Booking.get_by_id(booking_id) appointment = booking.appointment appointment.booked = False appointment.save() booking.delete_instance() except DoesNotExist as e: raise hug.HTTP_NOT_FOUND return {"booking_id": booking_id, "deleted": "successful"} else: raise hug.HTTP_METHOD_NOT_ALLOWED
def change_user_pw(db: directives.PeeweeSession, username: hug.types.text, password: hug.types.text, for_real: hug.types.smart_boolean = False): if not for_real: print( f"this would change {username}'s pw to {password}. Run with --for_real if you're sure.") sys.exit(1) with db.atomic(): name = username.lower() salt = get_random_string(2) secret_password = password hashed_password = hash_pw(name, salt, secret_password) user = User.get(User.user_name == username) user.salt = salt user.password = hashed_password user.save() print(f"{user.user_name}'s pw successfully changed.")
def get_or_create_auto_user(db: PeeweeSession, role: str, name: str): coupons = 4 if ( role == UserRoles.ANON ) else config.Ldap.user_coupon_number if role == UserRoles.USER else 1 with db.atomic(): try: user = User.get(User.user_name == name) return user except DoesNotExist: user = User.create(user_name=name, role=role, salt="", password="", coupons=coupons) user.save() return user
def patch_user(db: PeeweeSession, user_name: hug.types.text, coupons: hug.types.number): with db.atomic(): try: user = User.get(User.user_name == user_name) if coupons < 0: coupons = 0 user.coupons = coupons user.save() return {"user_name": user.user_name, "coupons": user.coupons} except DoesNotExist as e: raise hug.HTTPBadRequest except ValueError as e: raise hug.HTTPBadRequest except AssertionError as e: raise hug.HTTPBadRequest
def migrate_db(db: PeeweeSession): with db.atomic() as txs: migrator = PostgresqlMigrator(db) try: migration = Migration.get() if migration.version < 1: # do everything for level 1 level_1(db, migration, migrator) if migration.version < 2: # do everything for level 1 level_2(db, migration, migrator) except ProgrammingError: log.exception('Error - Migrations table not found, please run init_db first!') txs.rollback() sys.exit(1)
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
def put_user(db: PeeweeSession, newUserName: hug.types.text, newUserPassword: hug.types.text, newUserPasswordConfirm: hug.types.text): if newUserPassword != newUserPasswordConfirm: raise hug.HTTPBadRequest with db.atomic(): try: name = newUserName.lower() salt = get_random_string(2) secret_password = newUserPassword hashed_password = hash_pw(name, salt, secret_password) user = User.create(user_name=name, role=UserRoles.USER, salt=salt, password=hashed_password, coupons=10) user.save() return { "username": user.user_name } except IntegrityError: raise hug.HTTPConflict('User already exists.')
def get_free_timeslots_between(db: directives.PeeweeSession, start: datetime, end: datetime): with db.atomic(): now = datetime.now(tz=config.Settings.tz).replace(tzinfo=None) slots = TimeSlot \ .select(TimeSlot.start_date_time, TimeSlot.length_min, fn.count(Appointment.time_slot).alias("free_appointments")) \ .join(Appointment) \ .where( (TimeSlot.start_date_time >= start) & (TimeSlot.start_date_time <= end) & (Appointment.claim_token.is_null() | (Appointment.claimed_at + timedelta( minutes=config.Settings.claim_timeout_min) < now)) & (Appointment.booked == False) ) \ .group_by(TimeSlot.start_date_time, TimeSlot.length_min) \ .order_by(TimeSlot.start_date_time) \ # @formatter:on return [{"startDateTime": str(slot.start_date_time)} for slot in slots]
def create_appointments(db: directives.PeeweeSession, day: hug.types.number, month: hug.types.number, year: hug.types.number = 2020, start_hour: hug.types.number = 8, start_min: hug.types.number = 30, num_slots: hug.types.number = 13, num_appointment_per_slot: hug.types.number = 8, slot_duration_min: hug.types.number = 30): with db.atomic(): for i in range(num_slots): ts = TimeSlot.create(start_date_time=datetime( year, month, day, start_hour, start_min, tzinfo=None) + timedelta(minutes=i * slot_duration_min), length_min=slot_duration_min) for _ in range(num_appointment_per_slot): Appointment.create(booked=False, time_slot=ts) ts.save()
def set_frontend_config(db: directives.PeeweeSession, instance_name: hug.types.text, long_instance_name: hug.types.text, contact_info_bookings: hug.types.text, contact_info_appointments: hug.types.text = None, for_real: hug.types.smart_boolean = False): with db.atomic(): if "@" in contact_info_bookings: bookings_contact = f"<a href=\"mailto:{contact_info_bookings}\">{contact_info_bookings}</a>" else: bookings_contact = contact_info_bookings if not contact_info_appointments: appointments_contact = bookings_contact else: if "@" in contact_info_appointments: appointments_contact = f"<a href=\"mailto:{contact_info_appointments}\">{contact_info_appointments}</a>" else: appointments_contact = contact_info_appointments template = { "instanceName": f"{instance_name}", "longInstanceName": f"{long_instance_name}", "contactInfoCoupons": f"<span class=\"hintLabel\">Um mehr Termine vergeben zu können wenden Sie sich an " f"{bookings_contact}</span>", "contactInfoAppointment": f"<span class=\"hintLabel\">Kontaktieren Sie {appointments_contact}</span>" } if not for_real: print( f"This would update the config with '{json.dumps(template, indent=2)}'. Run with --for_real if you " f"are sure.") sys.exit(1) else: print( f"Updating the config with '{json.dumps(template, indent=2)}'." ) config = FrontendConfig.create(config=template) config.save() print("Done.")
def next_free_slots(db: PeeweeSession, user: hug.directives.user, at_datetime: hug.types.text = None): """ SELECT t.start_date_time, count(a.time_slot_id) FROM appointment a JOIN timeslot t ON a.time_slot_id = t.id WHERE a.booked IS false AND a.claim_token ISNULL AND t.start_date_time > NOW() GROUP BY t.start_date_time ORDER BY t.start_date_time """ with db.atomic(): # @formatter:off if at_datetime is not None: now = datetime.fromisoformat(at_datetime).replace(tzinfo=None) else: now = datetime.now(tz=config.Settings.tz).replace(tzinfo=None) slots = TimeSlot \ .select(TimeSlot.start_date_time, TimeSlot.length_min, fn.count(Appointment.time_slot).alias("free_appointments")) \ .join(Appointment) \ .where( (TimeSlot.start_date_time > now) & (Appointment.claim_token.is_null() | (Appointment.claimed_at + timedelta( minutes=config.Settings.claim_timeout_min) < now)) & (Appointment.booked == False) ) \ .group_by(TimeSlot.start_date_time, TimeSlot.length_min) \ .order_by(TimeSlot.start_date_time) \ .limit(config.Settings.num_display_slots) # @formatter:on return { "slots": [{ "startDateTime": slot.start_date_time, "freeAppointments": slot.free_appointments, "timeSlotLength": slot.length_min } for slot in slots], "coupons": user.coupons }
def patch_user(db: PeeweeSession, body: hug.types.json, user: hug.directives.user): old_user_password = body["old_user_password"] new_user_password = body["new_user_password"] new_user_password_confirm = body["new_user_password_confirm"] if new_user_password != new_user_password_confirm: raise hug.HTTPBadRequest with db.atomic(): try: if user.password != hash_pw(user.user_name, user.salt, old_user_password): raise hug.HTTPBadRequest salt = get_random_string(2) secret_password = new_user_password hashed_password = hash_pw(user.user_name, salt, secret_password) user.salt = salt user.password = hashed_password user.save() log.info(f"updated {user.user_name}'s pw.") return "updated" except DoesNotExist as e: raise hug.HTTPBadRequest except ValueError as e: raise hug.HTTPBadRequest
def create_appointments( db: directives.PeeweeSession, day: hug.types.number, month: hug.types.number, year: hug.types.number = date.today().year, start_hour: hug.types.number = 8, start_min: hug.types.number = 30, num_slots: hug.types.number = 13, num_appointment_per_slot: hug.types.number = 8, slot_duration_min: hug.types.number = 30 ): """ [--day] <number> [--month] <number> [--year <number=date.today().year>] [--start_hour <number=8>] [--start_min <number=30>] [--num_slots <number=13>] [--num_appointment_per_slot <number=8>] [--slot_duration_min <number=30>] creates timeslots and their corresponsing appointments """ with db.atomic(): for i in range(num_slots): ts = TimeSlot.create( start_date_time=datetime(year, month, day, start_hour, start_min, tzinfo=None) + timedelta( minutes=i * slot_duration_min), length_min=slot_duration_min) for _ in range(num_appointment_per_slot): Appointment.create(booked=False, time_slot=ts) ts.save()
def list_for_day(db: PeeweeSession, user: hug.directives.user, start_date: hug.types.text, end_date: hug.types.text): user_name = user.user_name with db.atomic(): try: user_role = user.role start_day_object = date.fromisoformat(start_date) end_day_object = date.fromisoformat(end_date) result = io.BytesIO() workbook = xlsxwriter.Workbook(result) worksheet = workbook.add_worksheet() bold = workbook.add_format({'bold': 1}) date_format = workbook.add_format({'num_format': 'dd.mm.yyyy'}) time_format = workbook.add_format({'num_format': 'hh:mm'}) worksheet.set_column('A:A', 15) worksheet.set_column('B:B', 8) worksheet.set_column('C:C', 18) worksheet.set_column('D:D', 15) worksheet.set_column('E:E', 18) worksheet.set_column('F:F', 15) worksheet.set_column('G:G', 15) worksheet.set_column('H:H', 15) worksheet.set_column('I:I', 15) worksheet.set_column('J:J', 15) worksheet.set_column('K:K', 15) worksheet.set_column('L:L', 15) worksheet.set_column('M:M', 15) worksheet.set_column('N:N', 15) worksheet.set_column('O:O', 15) worksheet.write('A1', 'Termin', bold) worksheet.write('B1', 'Uhrzeit', bold) worksheet.write('C1', 'Vorname', bold) worksheet.write('D1', 'Nachname', bold) worksheet.write('E1', 'Telefon', bold) worksheet.write('F1', 'Straße', bold) worksheet.write('G1', 'Hausnummer', bold) worksheet.write('H1', 'PLZ', bold) worksheet.write('I1', 'Stadt', bold) worksheet.write('J1', 'Geburtdatum', bold) worksheet.write('K1', 'Risikokategorie 1', bold) worksheet.write('L1', 'Berechtigungscode', bold) worksheet.write('M1', 'Behörde', bold) worksheet.write('N1', 'Gebucht von', bold) worksheet.write('O1', 'Gebucht am', bold) row = 1 col = 0 for timeslot in TimeSlot.select().where( (TimeSlot.start_date_time >= start_day_object) & (TimeSlot.start_date_time < end_day_object + timedelta(days=1))).order_by( TimeSlot.start_date_time.desc()): for appointment in Appointment.select().where( (Appointment.time_slot == timeslot) & (Appointment.booked == True)): try: booking = Booking.get( Booking.appointment == appointment) if user_role != UserRoles.ADMIN: booking = Booking.select().where( (Booking.appointment == appointment) & (Booking.booked_by == user_name)).get() worksheet.write_datetime(row, col, timeslot.start_date_time, date_format) worksheet.write_datetime(row, col + 1, timeslot.start_date_time, time_format) worksheet.write_string(row, col + 2, booking.first_name) worksheet.write_string(row, col + 3, booking.surname) worksheet.write_string(row, col + 4, booking.phone) worksheet.write_string( row, col + 5, booking.street if booking.street is not None else "") worksheet.write_string( row, col + 6, booking.street_number if booking.street_number is not None else "") worksheet.write_string( row, col + 7, booking.post_code if booking.post_code is not None else "") worksheet.write_string( row, col + 8, booking.city if booking.city is not None else "") if booking.birthday is None: worksheet.write_string(row, col + 9, "") else: worksheet.write_datetime(row, col + 9, booking.birthday, date_format) worksheet.write_string( row, col + 10, booking.reason if booking.reason is not None else "") worksheet.write_string(row, col + 11, booking.secret) worksheet.write_string(row, col + 12, booking.office) worksheet.write_string(row, col + 13, booking.booked_by) worksheet.write_datetime(row, col + 14, booking.booked_at, date_format) row += 1 except DoesNotExist as e: pass workbook.close() result.flush() return result.getvalue() except DoesNotExist as e: raise hug.HTTPGone except ValueError as e: raise hug.HTTPBadRequest
def instance_admin_config(db: PeeweeSession): with db.atomic(): return f"window.config = {json.dumps(FrontendConfig.get().config)};"
def inc_coupon_count(db: directives.PeeweeSession, user_name: hug.types.text, increment: hug.types.number): with db.atomic(): user = User.get(User.user_name == user_name) user.coupons += increment user.save()