2021-05-21 14:46:34 +02:00
|
|
|
from django.contrib.auth.tokens import default_token_generator
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
from django.utils.encoding import force_bytes
|
|
|
|
from django.utils.http import urlsafe_base64_encode
|
|
|
|
from rest_framework.exceptions import PermissionDenied
|
|
|
|
|
|
|
|
|
|
|
|
def encode_pk(resource):
|
|
|
|
"""Encode the primary key of a resource with Base64 for usage in URLs."""
|
|
|
|
return urlsafe_base64_encode(force_bytes(resource.pk))
|
|
|
|
|
|
|
|
|
|
|
|
class AlreadyConfirmed(Exception):
|
|
|
|
"""The given resource has already been confirmed."""
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class Confirmation:
|
|
|
|
"""
|
|
|
|
Base class for handling a confirmation process.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, user, resource):
|
|
|
|
self.user = user
|
|
|
|
self.resource = resource
|
|
|
|
|
|
|
|
def check(self):
|
|
|
|
if not self.has_permission(self.user, self.resource):
|
|
|
|
raise PermissionDenied()
|
|
|
|
if self.is_confirmed(self.resource):
|
|
|
|
raise AlreadyConfirmed()
|
|
|
|
self.confirm(self.resource)
|
|
|
|
|
|
|
|
def confirm(self, resource):
|
|
|
|
"""Overwrite this method to supply operations to confirm the resource."""
|
|
|
|
pass
|
|
|
|
|
|
|
|
def has_permission(self, user, resource) -> bool:
|
|
|
|
"""Overwrite this method returning if a user may confirm a resource."""
|
|
|
|
return False
|
|
|
|
|
|
|
|
def is_confirmed(self, resource) -> bool:
|
|
|
|
"""Overwrite this method to tell if a resource is confirmed."""
|
|
|
|
return False
|
|
|
|
|
|
|
|
def send_request(self):
|
|
|
|
if self.is_confirmed(self.resource):
|
|
|
|
return
|
|
|
|
|
|
|
|
site = Site.objects.get_current()
|
|
|
|
uid = encode_pk(self.user)
|
|
|
|
token = default_token_generator.make_token(self.user)
|
|
|
|
obj_type = ContentType.objects.get_for_model(self.resource)
|
|
|
|
type_id = encode_pk(obj_type)
|
|
|
|
obj_id = encode_pk(self.resource)
|
|
|
|
confirmation_url = (
|
|
|
|
f"https://{site.domain}/confirm/{uid}/{token}/{type_id}/{obj_id}"
|
|
|
|
)
|
|
|
|
self.user.email_user(
|
|
|
|
f"{site.name}: Bestätigung der Anfrage",
|
|
|
|
f"Bitte bestätige, dass du deine E-Mail-Adresse auf der Seite {site.name} ({site.domain}) eingegeben hast. "
|
|
|
|
f"Kopiere dazu folgende URL in deinen Webbrowser:\n\n{confirmation_url}",
|
|
|
|
)
|