helpers.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import datetime
  2. from django.utils.translation import gettext as _
  3. from .models import Participant, Date, Event
  4. def slots2string( participant : Participant, n_slots : int ) -> str :
  5. """ Convert the slots of a participant to a string. """
  6. # Get the slots of the participant
  7. byte_array = participant.slots
  8. # Convert the slots to a string
  9. string_value = bin(int.from_bytes(byte_array, byteorder='big'))[2:]
  10. # Pad the string with 0s if necessary
  11. return '0' * (n_slots - len(string_value)) + string_value
  12. def string2slots( string : str, n_slots : int ) -> bytes :
  13. """ Convert a string to a byte array. """
  14. if len(string) != n_slots:
  15. raise ValueError(_("Invalid string length: {0} (expected: {1})").format(len(string), n_slots))
  16. # Convert the string to a byte array
  17. return int(string, 2).to_bytes((n_slots + 7) // 8, byteorder='big')
  18. def get_slot_count( event ) -> int :
  19. """ Get the number of slots in an event. """
  20. # Get the timespan of the event
  21. start_time = datetime.datetime.combine(datetime.date.today(), event.start_time)
  22. end_time = datetime.datetime.combine(datetime.date.today(), event.end_time)
  23. if(start_time>end_time):
  24. end_time += datetime.timedelta(days=1)
  25. timespan = end_time - start_time
  26. # Get the number of slots in the event
  27. days = event.date_set.count()
  28. slots_per_day = int(timespan.total_seconds() // event.slot_interval.total_seconds())
  29. return days * slots_per_day
  30. def slots2grid( event : Event, participants : list[Participant]) -> dict :
  31. """ Convert the slots of an event to data for the grid. """
  32. # Get the number of slots in the event
  33. n_slots = get_slot_count(event)
  34. data = {
  35. 'rows': [],
  36. 'days': [],
  37. 'colors': [],
  38. 'n_days': event.date_set.count(),
  39. }
  40. # Get the timespan of the event
  41. start_time = datetime.datetime.combine(datetime.date.today(), event.start_time)
  42. end_time = datetime.datetime.combine(datetime.date.today(), event.end_time)
  43. if(start_time>end_time):
  44. end_time += datetime.timedelta(days=1)
  45. timespan = end_time - start_time
  46. # Get the slots in a day
  47. slots_per_day = int(timespan.total_seconds() // event.slot_interval.total_seconds())
  48. # Get the slots of each day
  49. participant_slot_strings = [slots2string(participant, n_slots) for participant in participants]
  50. max_occupancy = 1
  51. for n, date in enumerate(event.date_set.all()):
  52. # Get participants for each slot
  53. slot_participants = [[] for i in range(slots_per_day)]
  54. for i, participant in enumerate(participants):
  55. for j in range(slots_per_day):
  56. if participant_slot_strings[i][n*slots_per_day + j] == '1':
  57. slot_participants[j].append(participant)
  58. # Fill the slots of the day
  59. slots = []
  60. last_hour = None
  61. last_half_hour = None
  62. for j, ps in enumerate(slot_participants):
  63. slot_begin = (start_time + j * event.slot_interval).strftime('%H:%M')
  64. slot_end = (start_time + (j+1) * event.slot_interval).strftime('%H:%M')
  65. current_time = start_time + j * event.slot_interval
  66. slots.append({
  67. 'tooltip': f"{slot_begin} - {slot_end} \n{', '.join([p.user.username for p in ps])}",
  68. 'offset': n*slots_per_day + j,
  69. 'date': date.date,
  70. 'time': current_time,
  71. 'color': len(ps),
  72. 'checked': 'checked="checked"' if len(ps) > 0 else '',
  73. 'is_full_hour': current_time.hour != last_hour,
  74. 'is_half_hour': current_time.minute // 30 != last_half_hour,
  75. })
  76. max_occupancy = max(max_occupancy, len(ps))
  77. last_hour = current_time.hour
  78. last_half_hour = current_time.minute // 30
  79. day = {
  80. 'date': date.date,
  81. 'slots': slots,
  82. }
  83. data['days'].append(day)
  84. data['days'] = reversed(data['days'])
  85. # Fill the rows of the grid
  86. last_hour = None
  87. for i in range(slots_per_day):
  88. current_time = start_time + i * event.slot_interval
  89. data['rows'].append({
  90. 'time': current_time,
  91. 'is_full_hour': current_time.hour != last_hour,
  92. })
  93. last_hour = current_time.hour
  94. data['rows'].append({
  95. 'time': end_time,
  96. 'is_full_hour': True,
  97. })
  98. data['colors'] = max_occupancy
  99. return data