Jádro implementace view na doregistraci
This commit is contained in:
parent
a0edc1e0a1
commit
c9f0d60e7c
1 changed files with 120 additions and 22 deletions
|
@ -4,32 +4,119 @@ Registrace uživatelů k existujícím osobám
|
|||
V tomto souboru bude asi všechno, co je relevantní (kromě template), protože to
|
||||
je dostatečně malá a jednorázová věc.
|
||||
|
||||
Proto všechno kromě view začíná podtržítkem, aby se to nenatáhlo jako součást
|
||||
seminar.views
|
||||
Importovat prosím jen ty dva Views, ve výjimečných případech invite, nic dalšího.
|
||||
"""
|
||||
|
||||
#TODO: Logování (tohle logovat chce skoro určitě)
|
||||
#TODO: Omezení počtu pokusů (per token -- města / údaje se bruteforcit dají, na rozdíl od tokenů)
|
||||
|
||||
from enum import Enum
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from django.forms import Form
|
||||
from django.views.generic.edit import FormView
|
||||
from django.views import View
|
||||
from django.views.generic.base import TemplateResponseMixin
|
||||
import hmac
|
||||
from typing import Optional
|
||||
|
||||
from django.conf.settings import AUTH_USER_MODEL, SECRET_KEY
|
||||
from django.conf.settings import SECRET_KEY
|
||||
from seminar.models import Osoba
|
||||
|
||||
class DodatecnaRegistraceUzivateleView(FormView):
|
||||
form = _RegistraceUzivateleForm
|
||||
# Složitější class-based views mi neumožňují vracet chyby.
|
||||
class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View):
|
||||
template_name = ...
|
||||
success_url_pattern = ...
|
||||
form = RegistraceUzivateleForm
|
||||
|
||||
def form_valid(self, form):
|
||||
pass
|
||||
def get(self, request, url_token):
|
||||
# Ověřit token
|
||||
tok_data = verify_token(UseCase.email, url_token)
|
||||
if tok_data is None:
|
||||
return render_to_response(
|
||||
context={
|
||||
'error': 'Token není platný',
|
||||
},
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
# Zkontrolovat, že to není moc staré poslání
|
||||
now = datetime.now()
|
||||
token_generation = datetime.fromisoformat(tok_data['timestamp'])
|
||||
delta = now - token_generation
|
||||
if delta >= timedelta(weeks=10):
|
||||
return render_to_response(
|
||||
context={
|
||||
'error': 'Vypršela časová platnost tokenu',
|
||||
},
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
|
||||
# Najít osobu
|
||||
osoba_id = int(tok_data['osoba']) # Pokud tam není, tak jsme vygenerovali špatný token my (byl validní).
|
||||
osoba = m.Osoba.objects.get(id=osoba_id)
|
||||
if osoba.user is not None:
|
||||
return render_to_response(
|
||||
context={
|
||||
'error': 'Už máte uživatele',
|
||||
},
|
||||
status_code=400,
|
||||
)
|
||||
# Vrátit view s formulářem a formulářovým tokenem
|
||||
form_token = gen_token(UseCase.form, data={
|
||||
'osoba': str(osoba_id),
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
})
|
||||
return render_to_response(
|
||||
context={
|
||||
'form': self.form(initial={
|
||||
'token': form_token,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
def post(self, request, url_token):
|
||||
# Zkontrolovat formulář
|
||||
form = self.form(self.request.POST)
|
||||
if not form.is_valid():
|
||||
return render_to_response(
|
||||
context={
|
||||
'error': 'Chyba ve formuláři', # TODO: Umíme dostat konkrétní detaily?
|
||||
# TODO: Formulář pro zkusení znovu?
|
||||
},
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
form_data = form.cleaned_data
|
||||
# Zkontrolovat token
|
||||
token_data = verify_token(UseCase.form, form_data['token'])
|
||||
if token_data is None:
|
||||
return render_to_response(
|
||||
context={
|
||||
'error': 'Neplatný token',
|
||||
},
|
||||
status_code=400,
|
||||
)
|
||||
osoba_id = int(token_data['osoba'])
|
||||
osoba = m.Osoba.objects.get(id=osoba_id)
|
||||
# Zkontrolovat verifikační field
|
||||
...
|
||||
# Vyrobit uživatele
|
||||
u = User.objects.create_user(
|
||||
username=form_data['username'],
|
||||
password=form_data['password'],
|
||||
email=osoba.email,
|
||||
#first_name=o.jmeno,
|
||||
#last_name=o.prijmeni,
|
||||
)
|
||||
u.user_permissions.add(Permission.objects.get(codename__exact='resitel'))
|
||||
# Přesměrovat na kontrolu údajů
|
||||
return ...
|
||||
|
||||
class KontrolaUdajuASouhlasyView(FormView):
|
||||
...
|
||||
|
||||
class _RegistraceUzivateleForm(Form):
|
||||
#model = AUTH_USER_MODEL
|
||||
class RegistraceUzivateleForm(Form):
|
||||
#model = User
|
||||
# Zkopírováno z přihlášky :-)
|
||||
username = forms.CharField(label='Přihlašovací jméno',
|
||||
max_length=256,
|
||||
|
@ -47,21 +134,32 @@ class _RegistraceUzivateleForm(Form):
|
|||
widget=forms.PasswordInput())
|
||||
|
||||
# Dodatečné fieldy + token…
|
||||
token = ...
|
||||
token = forms.CharField(widget=forms.HiddenInput(), required=True)
|
||||
verifikace_TODO = ... # TODO: Co verifikovat
|
||||
|
||||
# TODO: clean_username, verifikace …
|
||||
|
||||
|
||||
# Pozor, tokeny existují dva: jeden do URL do mailu, druhý do hidden položky ve formuláři.
|
||||
|
||||
def _gen_token(usecase: str, data: dict[str, object]):
|
||||
...
|
||||
|
||||
def _verify_token(usecase: str, data: dict[str, object]):
|
||||
...
|
||||
|
||||
def _invite(osoba: Osoba):
|
||||
def invite(osoba: Osoba):
|
||||
"""
|
||||
Pošle dané osobě e-mail s odkazem na registraci.
|
||||
"""
|
||||
...
|
||||
|
||||
# Pozor, tokeny existují dva: jeden do URL do mailu, druhý do hidden položky ve formuláři.
|
||||
class UseCase(Enum):
|
||||
email = 'email'
|
||||
form = 'form'
|
||||
|
||||
# Token kóduje všechno v sobě
|
||||
def gen_token(usecase: _UseCase, data: dict[str, str]) -> str:
|
||||
...
|
||||
|
||||
def verify_token(usecase: _UseCase, token: str) -> Optional[dict[str, str]]:
|
||||
"""
|
||||
Vrací slovník dat, pokud je token validní, jinak None.
|
||||
|
||||
Inspirováno OSMO, je díky tomu jednoduché zároveň předat dekódovaná data a
|
||||
výsledek ověření.
|
||||
"""
|
||||
...
|
||||
|
||||
|
|
Loading…
Reference in a new issue