views.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import datetime
  2. import json
  3. from django.db import IntegrityError
  4. from django.http import HttpResponseNotFound, HttpResponseRedirect, JsonResponse, HttpResponseNotAllowed
  5. from django.shortcuts import render
  6. from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
  7. from django.views.decorators.csrf import csrf_exempt
  8. from django.views.decorators.vary import vary_on_cookie
  9. from django.views.decorators.cache import cache_page
  10. from django.utils.translation import gettext as _
  11. from django.contrib.auth.models import User
  12. from .forms import CreateEventForm, LoginForm, UpdateSlotsForm
  13. from .models import Event, Participant, Date
  14. from .helpers import slots2string, string2slots, get_slot_count, slots2grid
  15. @cache_page(60 * 15)
  16. def index(request):
  17. return render(request, 'zitap/index.html')
  18. def my_events(request):
  19. if not request.user.is_authenticated:
  20. return HttpResponseRedirect('/my-events/login')
  21. events = Event.objects.filter(participant__user=request.user).prefetch_related('date_set', 'participant_set', 'participant_set__user')
  22. return render(request, 'zitap/my-events.html', {
  23. 'events': events,
  24. })
  25. def about(request):
  26. return render(request, 'zitap/about.html')
  27. @cache_page(60 * 15)
  28. def create_event(request):
  29. if request.method == 'POST':
  30. form = CreateEventForm(request.POST)
  31. if form.is_valid():
  32. data = form.cleaned_data
  33. # Try to create the event. If the url is already taken, try again.
  34. n = 0
  35. while n<10:
  36. try:
  37. event = Event.objects.create(
  38. name=data['event_name'],
  39. start_time=datetime.time(int(data['start_time']), 0),
  40. end_time=datetime.time(int(data['end_time']), 0),
  41. slot_interval=datetime.timedelta(minutes=int(data['slot_interval'])),
  42. )
  43. for date in data['event_date']:
  44. event.date_set.create(date=date)
  45. event.save()
  46. return HttpResponseRedirect(f'/{event.url}')
  47. except IntegrityError:
  48. n += 1
  49. form.add_error(None, _('Could not create event. Please try again.'))
  50. else:
  51. form = CreateEventForm()
  52. return render(request, 'zitap/create-event.html', {'form': form})
  53. @cache_page(60 * 15)
  54. @vary_on_cookie
  55. def event(request, url):
  56. try:
  57. event = Event.objects.prefetch_related('date_set', 'participant_set', 'participant_set__user').get(url=url)
  58. except Event.DoesNotExist:
  59. return render(request, 'zitap/event-not-found.html')
  60. # Check if the user is logged in
  61. if 'user_id' in request.session:
  62. participant = event.participant_set.filter(user_id=request.session['user_id']).first()
  63. if participant is None:
  64. participant, created = Participant.objects.get_or_create(user_id=request.session['user_id'], event=event)
  65. login_form = None
  66. update_form = UpdateSlotsForm(initial={'slots': slots2string(participant, get_slot_count(event))}, participant=participant)
  67. else:
  68. login_form = LoginForm()
  69. update_form = None
  70. return render(
  71. request,
  72. 'zitap/event.html',
  73. {'event': event, 'grid': slots2grid(event, list(event.participant_set.all()), False), 'login_form': login_form, 'update_form': update_form}
  74. )
  75. def login(request, url):
  76. if url == 'my-events':
  77. text = _('Login to My Events')
  78. elif Event.objects.filter(url=url).exists():
  79. text = _('Login to Update Slots')
  80. else:
  81. return render(request, 'zitap/event-not-found.html')
  82. if request.method == 'POST':
  83. form = LoginForm(request.POST)
  84. elif request.user.is_authenticated:
  85. return HttpResponseRedirect(f'/{url}')
  86. else:
  87. form = LoginForm()
  88. if form.is_valid():
  89. data = form.cleaned_data
  90. user = authenticate(request, username=data['username'], password=data.get('password'))
  91. if user is None:
  92. try:
  93. user = User.objects.create_user(data['username'], password=data.get('password'))
  94. except IntegrityError:
  95. form.add_error('username', _('Username already exists'))
  96. return render(request, 'zitap/login.html', {'form': form, 'url': url, 'text': text})
  97. auth_login(request, user)
  98. request.session['user_id'] = user.id
  99. return HttpResponseRedirect(f'/{url}')
  100. return render(request, 'zitap/login.html', {'form': form, 'url': url, 'text': text})
  101. def logout(request, url):
  102. auth_logout(request)
  103. if url == 'my-events':
  104. return HttpResponseRedirect(f'/{url}')
  105. elif Event.objects.filter(url=url).exists():
  106. return HttpResponseRedirect(f'/{url}')
  107. else:
  108. return render(request, 'zitap/event-not-found.html')
  109. def update_slots(request, url):
  110. try:
  111. event = Event.objects.get(url=url)
  112. except Event.DoesNotExist:
  113. return render(request, 'zitap/event-not-found.html')
  114. if request.method != 'POST':
  115. return HttpResponseNotAllowed(['POST'])
  116. participant = Participant.objects.get(user_id=request.session['user_id'], event=event)
  117. form = UpdateSlotsForm(request.POST, participant=participant)
  118. if form.is_valid():
  119. data = form.cleaned_data
  120. participant.slots = string2slots(data['slots'], get_slot_count(event))
  121. participant.save()
  122. return HttpResponseRedirect(f'/{event.url}')
  123. def event_api(request, url):
  124. """
  125. REST JSON API for an event
  126. """
  127. try:
  128. event = Event.objects.get(url=url)
  129. except Event.DoesNotExist:
  130. return JsonResponse({'error': 'Event not found'}, status=404)
  131. if request.method == 'GET':
  132. return JsonResponse({
  133. 'name': event.name,
  134. 'url': event.url,
  135. 'start_time': event.start_time.strftime('%H:%M'),
  136. 'end_time': event.end_time.strftime('%H:%M'),
  137. 'slot_interval': event.slot_interval.seconds // 60,
  138. 'dates': [date.date.strftime('%Y-%m-%d') for date in event.date_set.all()],
  139. })
  140. else:
  141. return HttpResponseNotAllowed(['GET'])
  142. @csrf_exempt
  143. def slots_api(request, url):
  144. """
  145. REST JSON API for slots of all participants of an event
  146. Slots are represented as a string of 0s and 1s where 0 means the slot is available and 1 means the slot is taken.
  147. The string begins with the first slot of the first day of the event and ends with the last slot of the last day of the event.
  148. """
  149. try:
  150. event = Event.objects.get(url=url)
  151. slot_count = get_slot_count(event)
  152. # Check if the user is logged in and wants to update their slots
  153. if 'user_id' in request.session and request.method == 'POST':
  154. participant = Participant.objects.get(user_id=request.session['user_id'], event=event)
  155. form = UpdateSlotsForm(request.POST, participant=participant)
  156. if form.is_valid():
  157. data = form.cleaned_data
  158. participant.slots = string2slots(data['slots'], slot_count)
  159. participant.save()
  160. # Get the slots of each participant
  161. data = {}
  162. participants = event.participant_set.all()
  163. for participant in participants:
  164. data[participant.user.username] = slots2string(participant, slot_count)
  165. return JsonResponse(data)
  166. except Event.DoesNotExist:
  167. return HttpResponseNotFound()