123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import datetime
- from .models import Participant, Date, Event
- def slots2string( participant : Participant, n_slots : int ) -> str :
- """ Convert the slots of a participant to a string. """
- # Get the slots of the participant
- byte_array = participant.slots
- # Convert the slots to a string
- string_value = bin(int.from_bytes(byte_array, byteorder='big'))[2:]
- # Pad the string with 0s if necessary
- return '0' * (n_slots - len(string_value)) + string_value
- def string2slots( string : str, n_slots : int ) -> bytes :
- """ Convert a string to a byte array. """
- if len(string) != n_slots:
- raise ValueError(f"Invalid string length: {len(string)} (expected {n_slots})")
- # Convert the string to a byte array
- return int(string, 2).to_bytes((n_slots + 7) // 8, byteorder='big')
- def get_slot_count( event ) -> int :
- """ Get the number of slots in an event. """
- # Get the timespan of the event
- start_time = datetime.datetime.combine(datetime.date.today(), event.start_time)
- end_time = datetime.datetime.combine(datetime.date.today(), event.end_time)
- timespan = abs(end_time - start_time)
- # Get the number of slots in the event
- days = event.date_set.count()
- slots_per_day = int(timespan.total_seconds() // event.slot_interval.total_seconds())
- return days * slots_per_day
- def slots2grid( event : Event ) -> dict :
- """ Convert the slots of an event to data for the grid. """
- # Get the number of slots in the event
- n_slots = get_slot_count(event)
- data = {
- 'rows': [],
- 'days': [],
- 'colors': [],
- 'n_days': event.date_set.count(),
- }
- # Get the timespan of the event
- start_time = datetime.datetime.combine(datetime.date.today(), event.start_time)
- end_time = datetime.datetime.combine(datetime.date.today(), event.end_time)
- timespan = abs(end_time - start_time)
-
- # Get the slots in a day
- slots_per_day = int(timespan.total_seconds() // event.slot_interval.total_seconds())
- # Get the slots of each day
- participants = event.participant_set.all()
- participant_slot_strings = [slots2string(participant, n_slots) for participant in participants]
- max_occupancy = 1
- for n, date in enumerate(event.date_set.all()):
- # Get participants for each slot
- slot_participants = [[] for i in range(slots_per_day)]
- for i, participant in enumerate(participants):
- for j in range(slots_per_day):
- if participant_slot_strings[i][n*slots_per_day + j] == '1':
- slot_participants[j].append(participant)
- # Fill the slots of the day
- slots = []
- last_hour = None
- last_half_hour = None
- for j, ps in enumerate(slot_participants):
- slot_begin = (start_time + j * event.slot_interval).strftime('%H:%M')
- slot_end = (start_time + (j+1) * event.slot_interval).strftime('%H:%M')
- current_time = start_time + j * event.slot_interval
- slots.append({
- 'tooltip': f"{slot_begin} - {slot_end} \n{', '.join([p.user.username for p in ps])}",
- 'offset': n*slots_per_day + j,
- 'date': date.date,
- 'time': current_time,
- 'class': f'color_{len(ps)}',
- 'is_full_hour': current_time.hour != last_hour,
- 'is_half_hour': current_time.minute // 30 != last_half_hour,
- })
- max_occupancy = max(max_occupancy, len(ps))
- last_hour = current_time.hour
- last_half_hour = current_time.minute // 30
-
- day = {
- 'date': date.date,
- 'slots': slots,
- }
- data['days'].append(day)
- # Fill the rows of the grid
- last_hour = None
- for i in range(slots_per_day):
- current_time = start_time + i * event.slot_interval
- data['rows'].append({
- 'time': current_time,
- 'is_full_hour': current_time.hour != last_hour,
- })
- last_hour = current_time.hour
- data['rows'].append({
- 'time': end_time,
- 'is_full_hour': True,
- })
- # create a color for each slot from white to dark green
- for i in range(max_occupancy+1):
- data['colors'].append({
- 'color': f"hsl(120, 100%, {100 - 70 * i / max_occupancy}%)",
- 'name': f'color_{i}'
- })
- return data
|