API: Allow to send activation email when creating customers (#2729)

Co-authored-by: Raphael Michel <michel@rami.io>
This commit is contained in:
Michael Stapelberg
2022-07-25 12:16:48 +02:00
committed by GitHub
co-authored by Raphael Michel
parent f3a77d8154
commit 0d407ce36f
6 changed files with 74 additions and 22 deletions
+5 -2
View File
@@ -131,7 +131,9 @@ Endpoints
.. http:post:: /api/v1/organizers/(organizer)/customers/
Creates a new customer
Creates a new customer. In addition to the fields defined on the resource, you can pass the field ``send_email``
to control whether the system should send an account activation email with a password reset link (defaults to
``false``).
**Example request**:
@@ -143,7 +145,8 @@ Endpoints
Content-Type: application/json
{
"email": "test@example.org"
"email": "test@example.org",
"send_email": true
}
**Example response**:
+8
View File
@@ -75,6 +75,14 @@ class CustomerSerializer(I18nAwareModelSerializer):
'locale', 'last_modified', 'notes')
class CustomerCreateSerializer(CustomerSerializer):
send_email = serializers.BooleanField(default=False, required=False, allow_null=True)
class Meta:
model = Customer
fields = CustomerSerializer.Meta.fields + ('send_email',)
class MembershipTypeSerializer(I18nAwareModelSerializer):
class Meta:
+15 -5
View File
@@ -22,6 +22,7 @@
from decimal import Decimal
import django_filters
from django.contrib.auth.hashers import make_password
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
@@ -38,8 +39,8 @@ from rest_framework.viewsets import GenericViewSet
from pretix.api.models import OAuthAccessToken
from pretix.api.serializers.organizer import (
CustomerSerializer, DeviceSerializer, GiftCardSerializer,
GiftCardTransactionSerializer, MembershipSerializer,
CustomerCreateSerializer, CustomerSerializer, DeviceSerializer,
GiftCardSerializer, GiftCardTransactionSerializer, MembershipSerializer,
MembershipTypeSerializer, OrganizerSerializer, OrganizerSettingsSerializer,
SeatingPlanSerializer, TeamAPITokenSerializer, TeamInviteSerializer,
TeamMemberSerializer, TeamSerializer,
@@ -514,15 +515,24 @@ class CustomerViewSet(viewsets.ModelViewSet):
raise MethodNotAllowed("Customers cannot be deleted.")
@transaction.atomic()
def perform_create(self, serializer):
inst = serializer.save(organizer=self.request.organizer)
def perform_create(self, serializer, send_email=False):
customer = serializer.save(organizer=self.request.organizer, password=make_password(None))
serializer.instance.log_action(
'pretix.customer.created',
user=self.request.user,
auth=self.request.auth,
data=self.request.data,
)
return inst
if send_email:
customer.send_activation_mail()
return customer
def create(self, request, *args, **kwargs):
serializer = CustomerCreateSerializer(data=request.data, context=self.get_serializer_context())
serializer.is_valid(raise_exception=True)
self.perform_create(serializer, send_email=serializer.validated_data.pop('send_email', False))
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
@transaction.atomic()
def perform_update(self, serializer):
+21
View File
@@ -216,6 +216,27 @@ class Customer(LoggedModel):
testmode=testmode,
)
def send_activation_mail(self):
from pretix.base.services.mail import mail
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.forms.customer import TokenGenerator
ctx = self.get_email_context()
token = TokenGenerator().make_token(self)
ctx['url'] = build_absolute_uri(
self.organizer,
'presale:organizer.customer.activate'
) + '?id=' + self.identifier + '&token=' + token
mail(
self.email,
_('Activate your account at {organizer}').format(organizer=self.organizer.name),
self.organizer.settings.mail_text_customer_registration,
ctx,
locale=self.locale,
customer=self,
organizer=self.organizer,
)
class AttendeeProfile(models.Model):
customer = models.ForeignKey(
+1 -15
View File
@@ -41,9 +41,7 @@ from pretix.base.forms.questions import (
)
from pretix.base.i18n import get_language_without_region
from pretix.base.models import Customer
from pretix.base.services.mail import mail
from pretix.helpers.http import get_client_ip
from pretix.multidomain.urlreverse import build_absolute_uri
class TokenGenerator(PasswordResetTokenGenerator):
@@ -268,19 +266,7 @@ class RegistrationForm(forms.Form):
customer.set_unusable_password()
customer.save()
customer.log_action('pretix.customer.created', {})
ctx = customer.get_email_context()
token = TokenGenerator().make_token(customer)
ctx['url'] = build_absolute_uri(self.request.organizer,
'presale:organizer.customer.activate') + '?id=' + customer.identifier + '&token=' + token
mail(
customer.email,
_('Activate your account at {organizer}').format(organizer=self.request.organizer.name),
self.request.organizer.settings.mail_text_customer_registration,
ctx,
locale=customer.locale,
customer=customer,
organizer=self.request.organizer,
)
customer.send_activation_mail()
return customer
+24
View File
@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>.
#
import pytest
from django.core import mail as djmail
from django_scopes import scopes_disabled
@@ -98,6 +99,29 @@ def test_customer_create(token_client, organizer):
assert customer.is_active
assert customer.name == 'John Doe'
assert customer.is_verified
assert len(djmail.outbox) == 0
@pytest.mark.django_db
def test_customer_create_send_email(token_client, organizer):
resp = token_client.post(
'/api/v1/organizers/{}/customers/'.format(organizer.slug),
format='json',
data={
'identifier': 'IGNORED',
'email': 'bar@example.com',
'name_parts': {
"_scheme": "given_family",
'given_name': 'John',
'family_name': 'Doe',
},
'is_active': True,
'is_verified': True,
'send_email': True,
}
)
assert resp.status_code == 201
assert len(djmail.outbox) == 1
@pytest.mark.django_db