-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Django Rest Framework contrib package
- Loading branch information
Showing
11 changed files
with
344 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[[source]] | ||
name = "pypi" | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
|
||
[dev-packages] | ||
tox = "*" | ||
coverage = "*" | ||
djangorestframework = "*" | ||
|
||
[packages] | ||
|
||
[requires] | ||
python_version = "3.7" |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Empty file.
Empty file.
14 changes: 14 additions & 0 deletions
14
simple_email_confirmation/contrib/rest_framework/permissions.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from rest_framework import permissions | ||
|
||
|
||
class EmailViewSetPermission(permissions.IsAuthenticated): | ||
""" | ||
The request is authenticated as a user, or is a request to the | ||
confirm endpoint. | ||
""" | ||
|
||
def has_permission(self, request, view): | ||
if view.action == 'confirm': | ||
return True | ||
|
||
return super().has_permission(request, view) |
20 changes: 20 additions & 0 deletions
20
simple_email_confirmation/contrib/rest_framework/serializers.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from rest_framework import serializers | ||
|
||
from simple_email_confirmation import get_email_address_model | ||
|
||
|
||
class EmailAddressSerializer(serializers.ModelSerializer): | ||
|
||
class Meta: | ||
model = get_email_address_model() | ||
fields = ( | ||
'pk', | ||
'email', | ||
'is_confirmed', | ||
'is_primary', | ||
) | ||
|
||
|
||
class ConfirmEmailAddressSerializer(serializers.Serializer): | ||
id = serializers.UUIDField() | ||
code = serializers.CharField() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from rest_framework.routers import SimpleRouter | ||
|
||
from . import views | ||
|
||
|
||
router = SimpleRouter() | ||
|
||
router.register( | ||
r'auth/emails', | ||
views.EmailViewSet, | ||
basename='user-emails', | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
class CurrentUserMixin: | ||
def get_queryset(self): | ||
queryset = super().get_queryset() | ||
|
||
# Get configuration | ||
current_user = self.request.user | ||
user_field = self.user_field | ||
|
||
return queryset.filter(**{ | ||
user_field: current_user | ||
}) | ||
|
||
|
||
class ActionSerializerMixin: | ||
action_serializers = {} | ||
|
||
def get_action_serializers(self): | ||
return self.action_serializers | ||
|
||
def get_serializer_class(self): | ||
if self.action in self.get_action_serializers(): | ||
return self.action_serializers.get(self.action, None) | ||
|
||
else: | ||
return super().get_serializer_class() |
134 changes: 134 additions & 0 deletions
134
simple_email_confirmation/contrib/rest_framework/views.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
from django.db import IntegrityError | ||
from django.shortcuts import get_object_or_404 | ||
from rest_framework import viewsets, status | ||
from rest_framework.decorators import action | ||
from rest_framework.response import Response | ||
|
||
from simple_email_confirmation import get_email_address_model | ||
from simple_email_confirmation.exceptions import ( | ||
EmailConfirmationExpired, EmailIsPrimary, EmailNotConfirmed, | ||
) | ||
|
||
from . import permissions, serializers, utils | ||
|
||
|
||
class EmailViewSet( | ||
utils.ActionSerializerMixin, | ||
utils.CurrentUserMixin, | ||
viewsets.ModelViewSet, | ||
): | ||
email_address_model = get_email_address_model() | ||
queryset = email_address_model.objects.all() | ||
user_field = 'user' | ||
permission_classes = [permissions.EmailViewSetPermission] | ||
|
||
serializer_class = serializers.EmailAddressSerializer | ||
action_serializers = { | ||
'send_confirmation': None, | ||
'confirm': serializers.ConfirmEmailAddressSerializer, | ||
'set_primary': None, | ||
} | ||
|
||
def create(self, request, *args, **kwargs): | ||
try: | ||
# Add the new unconfirmed email | ||
request.user.add_unconfirmed_email(request.data['email']) | ||
|
||
# Retrieve the new email | ||
new_email = request.user.email_address_set.filter( | ||
email=request.data['email'] | ||
).first() | ||
|
||
# Return serialized email | ||
serializer = self.get_serializer(new_email) | ||
return Response(serializer.data) | ||
|
||
except IntegrityError: | ||
return Response( | ||
{'errors': ['Email already exists']}, | ||
status=status.HTTP_400_BAD_REQUEST, | ||
) | ||
|
||
def destroy(self, request, *args, **kwargs): | ||
email = self.get_object() | ||
|
||
try: | ||
# Delete the email | ||
request.user.remove_email(email.email) | ||
|
||
return Response({'status': 'OK'}) | ||
|
||
except EmailIsPrimary: | ||
return Response( | ||
{'errors': ['Cannot delete the primary email']}, | ||
status=status.HTTP_400_BAD_REQUEST, | ||
) | ||
|
||
@action(methods=['post'], detail=True) | ||
def send_confirmation(self, request, pk=None): | ||
""" | ||
Send a confirmation email. | ||
""" | ||
|
||
# Retrive email | ||
email = self.get_object() | ||
|
||
# Confirm email | ||
email.user.reset_email_confirmation(email.email) | ||
email.user.send_confirmation_email(email.email) | ||
|
||
# Success! | ||
return Response({'status': 'OK'}) | ||
|
||
@action(methods=['post'], detail=False) | ||
def confirm(self, request): | ||
""" | ||
Confirm an email. | ||
""" | ||
|
||
try: | ||
# Parse data | ||
serializer = self.get_serializer(data=request.data) | ||
serializer.is_valid(raise_exception=True) | ||
|
||
# Retrieve email | ||
email = get_object_or_404( | ||
self.email_address_model, | ||
pk=serializer.data['id'], | ||
) | ||
|
||
# Retrieve user | ||
email.user.confirm_email(serializer.data['code']) | ||
|
||
# Success! | ||
return Response({'status': 'OK'}) | ||
|
||
except EmailConfirmationExpired: | ||
return Response( | ||
{'errors': ['Confirmation key is not valid']}, | ||
status=status.HTTP_400_BAD_REQUEST, | ||
) | ||
|
||
@action(methods=['post'], detail=True) | ||
def set_primary(self, request, pk=None): | ||
""" | ||
Set an email as primary. | ||
""" | ||
|
||
# Retrive email | ||
email = self.get_object() | ||
|
||
try: | ||
# Set email as primary | ||
email.user.set_primary_email(email.email) | ||
|
||
# Success! | ||
return Response({'status': 'OK'}) | ||
|
||
except EmailNotConfirmed: | ||
return Response( | ||
{'errors': [ | ||
'Email must be confirmed before it can be set as primary' | ||
]}, | ||
status=status.HTTP_400_BAD_REQUEST, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,8 @@ | ||
urlpatterns = [] | ||
from django.urls import path, include | ||
|
||
from simple_email_confirmation.contrib.rest_framework.urls import router | ||
|
||
|
||
urlpatterns = [ | ||
path('api/', include(router.urls)), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,3 +28,4 @@ commands = | |
deps = | ||
coverage | ||
django<1.12 | ||
djangorestframework |