from django.shortcuts import render from django.http import HttpResponse from django.template.response import TemplateResponse from django.shortcuts import redirect from django.views.decorators.csrf import csrf_exempt from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.models import User as DjangoUser from django.contrib.auth import authenticate from django.contrib.auth import login as auth_login, logout as auth_logout from django.core.mail import send_mail, mail_admins, EmailMessage from django.db.utils import IntegrityError from django.db import transaction from django.utils.datastructures import MultiValueDictKeyError from datetime import date, datetime, timedelta from dateutil.relativedelta import relativedelta from weasyprint import HTML from urllib.parse import parse_qs import requests import json import glob import PIL.Image import random import itertools from collections import OrderedDict from .models import ( User, ALKATOR_CHOICES_DICT, ALKATOR_CLASSES, Profile, Racer, Invoice, Product, InvoiceProduct, Cart, CartProduct ) from alkator.settings import COMGATE_MERCHANT, COMGATE_SECRET, COMGATE_TEST DEADLINE = date(2025, 10, 5) ALKATOR_CLASS = 3 @csrf_exempt def register_user(request): if not request.POST['first_name']: return HttpResponse('{"reason":"Jméno je povinné!"}', status=400, content_type='application/json') if not request.POST['last_name']: return HttpResponse('{"reason":"Přijmení je povinné!"}', status=400, content_type='application/json') if not request.POST['email']: return HttpResponse('{"reason":"Email je povinný!"}', status=400, content_type='application/json') if not request.POST['address']: return HttpResponse('{"reason":"Adresa je povinná!"}', status=400, content_type='application/json') if not request.POST['password1'] or not request.POST['password2']: return HttpResponse('{"reason":"Heslo je povinné!"}', status=400, content_type='application/json') if request.POST['password1'] != request.POST['password2']: return HttpResponse('{"reason":"Hesla se neshodují!"}', status=400, content_type='application/json') if not request.POST['phone']: return HttpResponse('{"reason":"Telefon je povinný"}', status=400, content_type='application/json') if DjangoUser.objects.filter(email=request.POST['email']): return HttpResponse('{"reason":"Email je již registrován!"}', status=400, content_type='application/json') email = request.POST['email'] user = DjangoUser.objects.create_user( email, email, request.POST['password1'] ) profile = Profile( user=user, first_name=request.POST['first_name'], last_name=request.POST['last_name'], address=request.POST['address'], phone=request.POST['phone'], ) profile.save() auth_login(request, user) return HttpResponse('{"success":"Úspěšná registrace!", "redirect":"/#"}', content_type='application/json') @csrf_exempt def login(request): try: user = authenticate(request, username=request.POST['email'], password=request.POST['password']) except MultiValueDictKeyError: return HttpResponse('{"reason":"Nezadané jméno nebo heslo!"}', status=400, content_type='application/json') if user is not None: auth_login(request, user) return HttpResponse('{"success":"Úspěšně přihlášen uživatel '+ user.email + '", "redirect":"/#"}', content_type='application/json') else: return HttpResponse('{"reason":"Nesprávné jméno nebo heslo!"}', status=400, content_type='application/json') @csrf_exempt def logout(request): auth_logout(request) return redirect("/#") @csrf_exempt def register_racer(request): if not request.user.is_authenticated: return HttpResponse('{"reason":"Je potřeba se přihlásit!"}', status=400, content_type='application/json') if date.today() >= DEADLINE: return HttpResponse('{"reason":"Too late!"}', status=400, content_type='application/json') if not request.POST.get('agreement'): return HttpResponse('{"reason":"Je potřeba souhlasit se zpracováním údajů!"}', status=400, content_type='application/json') if not request.POST['first_name']: return HttpResponse('{"reason":"Jméno je povinné!"}', status=400, content_type='application/json') if not request.POST['last_name']: return HttpResponse('{"reason":"Přijmení je povinné!"}', status=400, content_type='application/json') try: dob = datetime.strptime(request.POST['date_of_birth'], "%Y-%m-%d").date() if dob > DEADLINE - relativedelta(years=18): return HttpResponse('{"reason":"Je potřeba mít 18 let v den závodu!"}', status=400, content_type='application/json') elif dob < DEADLINE - relativedelta(years=100): return HttpResponse('{"reason":"Opravdu vám je 100 let?"}', status=400, content_type='application/json') except: return HttpResponse('{"reason":"Špatný formát datu narození!"}', status=400, content_type='application/json') invoice_id = Invoice.next_invoice_id() profile = request.user.profile user = request.user product = Product.objects.get(id=1) price = product.price if product.quantity <= 0: return HttpResponse('{"reason":"Jsme vyprodaní!"}', status=400, content_type='application/json') invoice = Invoice( invoice_id=invoice_id, user=user, total_price=price, address="", ) racer = Racer( product=product, invoice=invoice, quantity=1, profile = profile, first_name = request.POST['first_name'], last_name = request.POST['last_name'], email = request.POST['email'], team = request.POST['team'], phone = request.POST['phone'], date_of_birth = dob, alkator_class = ALKATOR_CLASS, price=price, ) invoice.save() racer.save() payment_data = { 'merchant': COMGATE_MERCHANT, 'test': 'true' if COMGATE_TEST else 'false', 'price': price * 100, 'curr': 'CZK', 'method': 'ALL', 'label': 'Startovné na závod Alkátor Race Dolní Čermná 2025', 'email': user.email, 'fullName': f"{profile.first_name} {profile.last_name}", 'refId': f'{invoice.invoice_id}', 'secret': COMGATE_SECRET, 'prepareOnly': 'true', } result = requests.post('https://payments.comgate.cz/v1.0/create', data=payment_data) result = parse_qs(result.text) if result['code'][0] != '0': racer.delete() invoice.delete() return HttpResponse('{"reason":"Chyba na straně platební brány: ' + result['message'][0] + ', zkuste prosím registraci později."}', status=400, content_type='application/json') product.quantity -= 1 product.save() invoice.trans_id = result['transId'][0] invoice.save() return HttpResponse('{"success":"", "redirect":"' + result['redirect'][0] + '"}', content_type='application/json') def login_status(request): if not request.user.is_authenticated: return HttpResponse('{}', content_type='application/json') user = request.user racers = user.profile.racers.all() return HttpResponse(json.dumps({ "email": user.email, "first_name": user.profile.first_name, "last_name": user.profile.last_name, "address": user.profile.address, "racers": [{ "id": racer.invoice_id, "first_name": racer.first_name, "last_name": racer.last_name, "email": racer.email, "phone": racer.phone, "team": racer.team, "date_of_birth": racer.date_of_birth.strftime("%Y-%m-%d"), "paid": racer.invoice.paid, } for racer in racers] }), content_type='application/json') @csrf_exempt def change_racer(request): try: racer = Racer.objects.get(invoice_id=request.POST['id']) if request.user != racer.profile.user: return HttpResponse('{"reason":"Nedostatečná práva!"}', status=400, content_type='application/json') if date.today() >= DEADLINE: return HttpResponse('{"reason":"Příliš pozdě na změnu účastníka!"}', status=400, content_type='application/json') if not request.POST['first_name']: return HttpResponse('{"reason":"Jméno je povinné!"}', status=400, content_type='application/json') if not request.POST['last_name']: return HttpResponse('{"reason":"Přijmení je povinné!"}', status=400, content_type='application/json') try: dob = datetime.strptime(request.POST['date_of_birth'], "%Y-%m-%d").date() if dob > DEADLINE - relativedelta(years=18): return HttpResponse('{"reason":"Je potřeba mít 18 let v den závodu!"}', status=400, content_type='application/json') elif dob < DEADLINE - relativedelta(years=100): return HttpResponse('{"reason":"Opravdu vám je 100 let?"}', status=400, content_type='application/json') except: return HttpResponse('{"reason":"Špatný formát datu narození!"}', status=400, content_type='application/json') racer.first_name = request.POST['first_name'] racer.last_name = request.POST['last_name'] racer.email = request.POST['email'] racer.phone = request.POST['phone'] racer.team = request.POST['team'] racer.date_of_birth = dob racer.save() return HttpResponse('{"success":"Úspěšně uloženo."}', content_type='application/json') except MultiValueDictKeyError: return HttpResponse('{"reason":"Nějaký údaj chybí!"}', status=400, content_type='application/json') except Racer.DoesNotExist: return HttpResponse('{"reason":"Upravujete neexistujícího závodníka!"}', status=400, content_type='application/json') @csrf_exempt def payment_result(request): result = parse_qs(request.body.decode('utf8')) ref_id = int(result['refId'][0]) paid = result['status'][0] secret_match = result['secret'][0] == COMGATE_SECRET test = result['test'][0] != 'false' if not secret_match or test != COMGATE_TEST: return HttpResponse(status=400) try: invoice = Invoice.objects.get(invoice_id=ref_id) user = invoice.user except Invoice.DoesNotExist: mail_admins('Chyba s platbou!', f'invoice_id={ref_id}&paid={paid}') return HttpResponse(status=404) if paid == 'PAID': invoice.paid = True invoice.save() try: racer = Racer.objects.get(invoice=invoice) mail = EmailMessage( subject=f"úspěšná registrace do závodu Alkátor race Dolní Čermná ({racer.first_name} {racer.last_name})", body=f"""Zdravím tě Alkátore, toto je potvrzovací email o účasti v nezapomenutelném závodě Alkátor-race. Prosíme kontrolujete si své hromadné schránky a spamy. Závod se koná 5.10.2024 v Dolní Čermné. Zajištěno je stanování, občerstvení a také večerní after párty. Připrav na zkoušku své tělo, játra a tvé mozkové buňky. Budou tě čekat nevídané překážky. O podrobnostech tě budeme informovat emailem. Nezapomeň nás sledovat na Facebooku, Instagramu, YouTube a TikToku. Na tento email není třeba odpovídat, protože je generován automaticky s přijatou platbou. V případě potřeby pište na info@alkator.cz . ALKÁTOR TEAM email: info@alkator.cz tel: + 420 728 018 088 web: https://alkator.cz""", from_email="info@alkator.cz", to=[invoice.user.email, racer.email] if racer.email and invoice.user.email != racer.email else [invoice.user.email], bcc=["info@alkator.cz"], cc=[] ) except Racer.DoesNotExist: mail = EmailMessage( subject=f"úspěšně zaplacený nákup v Alkátor shopu", body=f"""Zdravím tě Alkátore, úspěšně si zakoupil merch na Alkátor shopu. Na tento email není třeba odpovídat, protože je generován automaticky s přijatou platbou. V případě potřeby pište na info@alkator.cz . ALKÁTOR TEAM email: info@alkator.cz tel: + 420 728 018 088 web: https://alkator.cz""", from_email="info@alkator.cz", to=[invoice.user.email], bcc=["info@alkator.cz"], cc=[] ) template = TemplateResponse( None, 'invoice.html', { 'user': user, 'invoice': invoice, 'products': InvoiceProduct.objects.filter(invoice=invoice), 'paid_date': invoice.paid_date + timedelta(days=1), } ) template.render() pdf_name = f"invoices/{invoice.invoice_id}_{user.profile.last_name}_{user.profile.first_name}.pdf" HTML(string=template.content).write_pdf(pdf_name) attach = open(pdf_name, 'rb') mail.attach('faktura.pdf', attach.read(), 'application/pdf') if not mail.send(): return HttpResponse(status=500) elif paid == 'CANCELLED' and not invoice.paid: for ip in InvoiceProduct.objects.filter(invoice=invoice): ip.product.quantity += ip.quantity ip.product.save() ip.delete() invoice.delete() return HttpResponse(status=200) def payment_state(request): invoice_id = request.GET['refId'] try: if Invoice.objects.get(invoice_id=invoice_id).paid: return HttpResponse('{"status":"success", "reason":"Úspěšná platba"}', content_type='application/json') else: return HttpResponse('{"status":"failed", "reason":"Zatím nemáme informace o provedené platbě. Zkuste reload nebo zkontrolujte email."}', content_type='application/json') except Invoice.DoesNotExist: return HttpResponse('{"status":"failed", "reason":"Závodník neexistuje, registraci závodníka prosím opakujte."}', content_type='application/json') def products(request): return HttpResponse(json.dumps([ { 'id': product.id, 'name': product.name, 'description': product.description, 'img': product.img.url, 'price': product.price, 'quantity': product.quantity, } for product in Product.objects.all() if product.quantity > 0 and not product.hidden ]), content_type='application/json') def cart_add(request): _id = request.GET['id'] user = request.user if not user.is_authenticated: return HttpResponse('{"status": "failed", "reason": "Pro využivání Košíku je třeba se přihlásit!"}') try: cart = user.cart except AttributeError: cart = Cart(user=user) cart.save() product = Product.objects.get(id=_id) try: cart_product = CartProduct( product=product, cart=cart, quantity=1, ) cart_product.save() except IntegrityError as e: cart_product = CartProduct.objects.get(cart=cart, product=product) cart_product.quantity += 1 if cart_product.quantity > product.quantity: return HttpResponse('{"status": "failed", "reason": "Nemáme dostatek předmětů na skladě!"}') cart_product.save() return HttpResponse('{"status":"success", "reason":"Úspěšně přidáno do košíku."}', status=200) def select_delivery(request): user = request.user cart = user.cart cart.address = request.GET['delivery'] cart.save() return HttpResponse('{"status":"success", "reason":"Úspěšně vybraná zásilkovna."}', status=200) def delivery(request): try: if request.user.cart.address: return HttpResponse('"' + request.user.cart.address + '"', status=200, content_type='application/json') return HttpResponse("undefined", status=200, content_type='application/json') except AttributeError: return HttpResponse("undefined", status=200, content_type='application/json') @csrf_exempt @transaction.atomic def cart_buy(request): cart = request.user.cart user = request.user profile = user.profile cart_products = CartProduct.objects.filter(cart=cart) for cp in cart_products: if cp.quantity > cp.product.quantity: return HttpResponse('{"status": "failed", "reason": "Nemáme dostatek ' + cp.product.name + ' na skladě!"}', status=400, content_type='application/json') if not cart.address: return HttpResponse('{"status": "failed", "reason": "Je potřeba vybrat výběrní místo!"}', status=400, content_type='application/json') invoice = Invoice( user=user, address=cart.address, invoice_id=Invoice.next_invoice_id(), total_price=0, ) total_price = 0 invoice.save() for cp in itertools.chain(cart_products, [CartProduct(quantity=1, product=Product.objects.get(id=2), cart=cart)]): ip = InvoiceProduct( invoice=invoice, price=cp.product.price, quantity=cp.quantity, product=cp.product, ) cp.product.quantity -= cp.quantity cp.product.save() total_price += cp.quantity * cp.product.price ip.save() if total_price <= 79: return HttpResponse('{"status": "failed", "reason": "Prosím přidejte svoje položky do košíku!"}', status=400, content_type='application/json') payment_data = { 'merchant': COMGATE_MERCHANT, 'test': 'true' if COMGATE_TEST else 'false', 'price': total_price * 100, 'curr': 'CZK', 'method': 'ALL', 'label': 'Merch Alkátor Race', 'email': user.email, 'fullName': f"{profile.first_name} {profile.last_name}", 'refId': f'{invoice.invoice_id}', 'secret': COMGATE_SECRET, 'prepareOnly': 'true', } result = requests.post('https://payments.comgate.cz/v1.0/create', data=payment_data) result = parse_qs(result.text) if result['code'][0] != '0': for ip in InvoiceProduct.objects.filter(invoice=invoice): ip.delete() invoice.delete() return HttpResponse('{"reason":"Chyba na straně platební brány: ' + result['message'][0] + ', zkuste prosím nákup později."}', status=400, content_type='application/json') invoice.total_price = total_price invoice.trans_id = result['transId'][0] cart.delete() invoice.save() return HttpResponse('{"success":"", "redirect":"' + result['redirect'][0] + '"}', content_type='application/json') def cart_delete(request): _id = request.GET['id'] user = request.user cart = user.cart product = Product.objects.get(id=_id) cart_product = CartProduct.objects.get(cart=cart, product=product) cart_product.delete() return HttpResponse('{"status":"success", "reason":"Úspěšně odstraněno z košíku."}', content_type='application/json') def cart_decrease(request): _id = request.GET['id'] user = request.user cart = user.cart product = Product.objects.get(id=_id) cart_product = CartProduct.objects.get(cart=cart, product=product) cart_product.quantity -= 1 if cart_product.quantity == 0: cart_product.delete() else: cart_product.save() return HttpResponse('{"status":"success", "reason":"Úspěšně sníženo množství v košíku."}', content_type='application/json') def cart(request): user = request.user if not user.is_authenticated: return HttpResponse("[]", content_type='application/json') cart = [] try: for cart_product in CartProduct.objects.filter(cart=user.cart): cart.append({ 'id': cart_product.product.id, 'name': cart_product.product.name, 'description': cart_product.product.description, 'quantity': cart_product.quantity, 'price': cart_product.product.price, 'img': cart_product.product.img.url, }) except AttributeError: return HttpResponse("[]", content_type='application/json') return HttpResponse(json.dumps(cart)) def results(request): results = [] n = 1 for user in User.objects.filter(alkator_class=2).order_by('duration'): if user.duration: if user.alkator_category == 1: order = f'{n}.' n += 1 else: order = 'x.' results.append({ 'order': order, 'duration': str(user.duration), 'alkator_category': ALKATOR_CHOICES_DICT[user.alkator_category], 'starting_number': user.starting_number, }) for user in User.objects.filter(alkator_class=2).order_by('duration'): if not user.duration and user.starting_number: results.append({ 'order': 'DNF', 'duration': 'Nedokončil', 'starting_number': user.starting_number, 'alkator_category': '' }) return HttpResponse(json.dumps(results), content_type='application/json') def photos(request): rtn = [] for (i, name) in ALKATOR_CLASSES[:2]: photos = {} rtn.append(photos) photos['name'] = name photos['index'] = i photos['photos'] = [] files = glob.glob(f"photos/{i}/*.jpg") random.shuffle(files) for file in files: img = PIL.Image.open(file) photos['photos'].append({ 'original': '/' + file.replace(".jpg", ".webp"), 'thumbnail': '/' + file.replace(f'photos/{i}/', f'photos/{i}/thumbnail/').replace(".jpg", ".webp"), 'original_width': img.width, 'original_height': img.height, }) return HttpResponse(json.dumps(rtn), content_type='application/json') @csrf_exempt def upload_files(request): for file in request.FILES.getlist('files'): rand = random.randint(0, 99999) random_name = f'photos/uploads/{rand}_{file.name}' with open(random_name, "wb+") as destination: for chunk in file.chunks(): destination.write(chunk) return HttpResponse('{"success":"Úspěšně nahráno! Počkejte až dojde ke schválení nahraných souborů."}', content_type='application/json') @staff_member_required def invoice(request): invoice = Invoice.objects.get(invoice_id=request.GET['invoice_id']) user = DjangoUser.objects.get(id=invoice.user_id) return TemplateResponse( None, 'invoice.html', { 'user': user, 'invoice': invoice, 'products': InvoiceProduct.objects.filter(invoice=invoice), 'paid_date': invoice.paid_date + timedelta(days=1), } )