import datetime import json from django.db import IntegrityError from django.http import HttpResponseForbidden, HttpResponseNotFound, HttpResponseRedirect, JsonResponse, HttpResponseNotAllowed from django.shortcuts import render from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout from django.views.decorators.csrf import csrf_exempt from django.views.decorators.vary import vary_on_cookie from django.views.decorators.cache import cache_page from django.utils.translation import gettext as _ from django.contrib.auth.models import User from .forms import CreateEventForm, LoginForm, UpdateSlotsForm from .models import Event, Participant, Date from .helpers import slots2string, string2slots, get_slot_count, slots2grid @cache_page(60 * 15) def index(request): return render(request, 'zitap/index.html') def my_events(request): if not request.session.get('user_id'): form = LoginForm({'username': request.session.get('username', '')}) form.add_error('password', _('Please enter a password.')) return render(request, 'zitap/login.html', {'form': form, 'url': 'my-events', 'text': _('Login to My Events')}) print(request.session.get('user_id')) events = Event.objects.filter(participant__user=request.user).prefetch_related('date_set', 'participant_set', 'participant_set__user') return render(request, 'zitap/my-events.html', { 'events': events, }) def about(request): return render(request, 'zitap/about.html') @cache_page(60 * 15) def create_event(request): if request.method == 'POST': form = CreateEventForm(request.POST) if form.is_valid(): data = form.cleaned_data # Try to create the event. If the url is already taken, try again. n = 0 while n<10: try: event = Event.objects.create( name=data['event_name'], start_time=datetime.time(int(data['start_time']), 0), end_time=datetime.time(int(data['end_time']), 0), slot_interval=datetime.timedelta(minutes=int(data['slot_interval'])), ) for date in data['event_date']: event.date_set.create(date=date) event.save() return HttpResponseRedirect(f'/{event.url}') except IntegrityError: n += 1 form.add_error(None, _('Could not create event. Please try again.')) else: form = CreateEventForm() return render(request, 'zitap/create-event.html', {'form': form}) @cache_page(60 * 15) @vary_on_cookie def event(request, url): event = Event.objects.filter(url=url).prefetch_related('date_set', 'participant_set', 'participant_set__user').first() participants = list(event.participant_set.all()) if event else [] if not event: return render(request, 'zitap/event-not-found.html') # Check if the user is logged in participant = None if 'username' in request.session: for participant in participants: if participant.name == request.session['username']: break else: participant = None login_form = None n_slots = get_slot_count(event) update_form = UpdateSlotsForm(initial={'slots': slots2string(participant, n_slots)}, event=event, n_slots=n_slots, participant=participant) else: login_form = LoginForm() update_form = None return render( request, 'zitap/event.html', {'event': event, 'grid': slots2grid(event, participants, False), 'login_form': login_form, 'update_form': update_form} ) def login(request, url): if url == 'my-events': text = _('Login to My Events') elif Event.objects.filter(url=url).exists(): text = _('Login to Update Slots') else: return render(request, 'zitap/event-not-found.html') if request.method == 'POST': form = LoginForm(request.POST) elif 'username' in request.session: return HttpResponseRedirect(f'/{url}') else: form = LoginForm() if form.is_valid(): data = form.cleaned_data user = authenticate(request, username=data['username'], password=data.get('password')) if user is None and data.get('password'): try: user = User.objects.create_user(data['username'], password=data.get('password')) except IntegrityError: form.add_error('password', _('Wrong password')) return render(request, 'zitap/login.html', {'form': form, 'url': url, 'text': text}) elif user is None and User.objects.filter(username=data['username']).exists(): form.add_error('username', _('Username already exists')) return render(request, 'zitap/login.html', {'form': form, 'url': url, 'text': text}) if user: auth_login(request, user) request.session['user_id'] = user.id elif 'user_id' in request.session: del request.session['user_id'] request.session['username'] = data['username'] return HttpResponseRedirect(f'/{url}') return render(request, 'zitap/login.html', {'form': form, 'url': url, 'text': text}) def logout(request, url): auth_logout(request) if url == 'my-events': return HttpResponseRedirect(f'/my-events/login') elif Event.objects.filter(url=url).exists(): return HttpResponseRedirect(f'/{url}') else: return render(request, 'zitap/event-not-found.html') def update_slots(request, url): try: event = Event.objects.get(url=url) except Event.DoesNotExist: return render(request, 'zitap/event-not-found.html') if request.method != 'POST': return HttpResponseNotAllowed(['POST']) if 'username' not in request.session: return HttpResponseForbidden() slot_count = get_slot_count(event) participant = event.participant_set.filter(name=request.session['username'], event=event).first() form = UpdateSlotsForm(request.POST, event=event, n_slots=slot_count, participant=participant) if form.is_valid(): data = form.cleaned_data if data['slots'] == '0' * slot_count and participant: participant.delete() elif not participant: participant = Participant.objects.create(name=request.session['username'], user_id=request.session['user_id'], event=event, slots=string2slots(data['slots'], slot_count)) else: participant.slots = string2slots(data['slots'], slot_count) participant.save() return HttpResponseRedirect(f'/{event.url}') def event_api(request, url): """ REST JSON API for an event """ try: event = Event.objects.get(url=url) except Event.DoesNotExist: return JsonResponse({'error': 'Event not found'}, status=404) if request.method == 'GET': return JsonResponse({ 'name': event.name, 'url': event.url, 'start_time': event.start_time.strftime('%H:%M'), 'end_time': event.end_time.strftime('%H:%M'), 'slot_interval': event.slot_interval.seconds // 60, 'dates': [date.date.strftime('%Y-%m-%d') for date in event.date_set.all()], }) else: return HttpResponseNotAllowed(['GET']) @csrf_exempt def slots_api(request, url): """ REST JSON API for slots of all participants of an event Slots are represented as a string of 0s and 1s where 0 means the slot is available and 1 means the slot is taken. 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. """ event = Event.objects.filter(url=url).prefetch_related('date_set', 'participant_set', 'participant_set__user').first() participants = list(event.participant_set.all()) if event else [] if not event: return HttpResponseNotFound() slot_count = get_slot_count(event) # Check if the user is logged in and wants to update their slots if 'username' in request.session and request.method == 'POST': for participant in participants: if participant.name == request.session['username']: break else: participant = None slot_count = get_slot_count(event) form = UpdateSlotsForm(request.POST, event=event, n_slots=slot_count, participant=participant) if form.is_valid(): data = form.cleaned_data if data['slots'] == '0' * slot_count and participant: participant.delete() elif not participant: participant = Participant.objects.create(name=request.session['username'], user_id=request.session.get('user_id'), event=event, slots=string2slots(data['slots'], slot_count)) else: participant.slots = string2slots(data['slots'], slot_count) participant.save() # Get the slots of each participant data = { 'username': request.session.get('username'), 'n_slots': slot_count, 'participants': [participant.name for participant in participants], 'slots': [slots2string(participant, slot_count) for participant in participants], } return JsonResponse(data)