Commit d8dbb1ccdcff6aef455533463a192c5ddadefb02
1 parent
9bd8c31d05
Exists in
master
fixed signup, login - was not passing in password to create_user
Showing 2 changed files with 22 additions and 19 deletions Inline Diff
flashcards/api.py
View file @
d8dbb1c
from django.contrib.auth import login, authenticate | 1 | |||
from django.core.mail import send_mail | 2 | 1 | from django.core.mail import send_mail | |
from django.contrib.auth import authenticate, login | 3 | 2 | from django.contrib.auth import authenticate, login | |
from django.contrib.auth.tokens import default_token_generator | 4 | 3 | from django.contrib.auth.tokens import default_token_generator | |
from rest_framework.views import APIView | 5 | 4 | from rest_framework.views import APIView | |
from rest_framework.response import Response | 6 | 5 | from rest_framework.response import Response | |
from rest_framework import status | 7 | 6 | from rest_framework import status | |
from rest_framework.exceptions import ValidationError, NotFound | 8 | 7 | from rest_framework.exceptions import ValidationError, NotFound | |
from flashcards.serializers import * | 9 | 8 | from flashcards.serializers import * | |
10 | 9 | |||
11 | 10 | |||
class UserDetail(APIView): | 12 | 11 | class UserDetail(APIView): | |
def patch(self, request, format=None): | 13 | 12 | def patch(self, request, format=None): | |
""" | 14 | 13 | """ | |
Updates a user's password after they enter a valid old password. | 15 | 14 | Updates a user's password after they enter a valid old password. | |
TODO: email verification | 16 | 15 | TODO: email verification | |
""" | 17 | 16 | """ | |
18 | 17 | |||
if 'old_password' not in request.data: | 19 | 18 | if 'old_password' not in request.data: | |
raise ValidationError('Old password is required') | 20 | 19 | raise ValidationError('Old password is required') | |
if 'new_password' not in request.data: | 21 | 20 | if 'new_password' not in request.data: | |
raise ValidationError('New password is required') | 22 | 21 | raise ValidationError('New password is required') | |
if not request.data['new_password']: | 23 | 22 | if not request.data['new_password']: | |
raise ValidationError('Password cannot be blank') | 24 | 23 | raise ValidationError('Password cannot be blank') | |
25 | 24 | |||
currentuser = request.user | 26 | 25 | currentuser = request.user | |
27 | 26 | |||
if not currentuser.check_password(request.data['old_password']): | 28 | 27 | if not currentuser.check_password(request.data['old_password']): | |
raise ValidationError('Invalid old password') | 29 | 28 | raise ValidationError('Invalid old password') | |
30 | 29 | |||
currentuser.set_password(request.data['new_password']) | 31 | 30 | currentuser.set_password(request.data['new_password']) | |
currentuser.save() | 32 | 31 | currentuser.save() | |
33 | 32 | |||
return Response(status=status.HTTP_204_NO_CONTENT) | 34 | 33 | return Response(status=status.HTTP_204_NO_CONTENT) | |
35 | 34 | |||
def get(self, request, format=None): | 36 | 35 | def get(self, request, format=None): | |
serializer = UserSerializer(request.user) | 37 | 36 | serializer = UserSerializer(request.user) | |
return Response(serializer.data) | 38 | 37 | return Response(serializer.data) | |
39 | 38 | |||
def post(self, request, format=None): | 40 | 39 | def post(self, request, format=None): | |
if 'email' not in request.data: | 41 | 40 | if 'email' not in request.data: | |
raise ValidationError('Email is required') | 42 | 41 | raise ValidationError('Email is required') | |
if 'password' not in request.data: | 43 | 42 | if 'password' not in request.data: | |
raise ValidationError('Password is required') | 44 | 43 | raise ValidationError('Password is required') | |
45 | 44 | |||
email = request.data['email'] | 46 | 45 | email = request.data['email'] | |
user = User.objects.create_user(email, email=email) | 47 | 46 | user = User.objects.create_user(email, email=email, password=request.data['password']) | |
user.confirm_email(user.confirmation_key) | 48 | 47 | ||
body = ''' | 49 | 48 | body = ''' | |
Visit the following link to confirm your email address: | 50 | 49 | Visit the following link to confirm your email address: | |
http://flashy.cards/app/verify_email/%s | 51 | 50 | http://flashy.cards/app/verify_email/%s | |
52 | 51 | |||
If you did not register for Flashy, no action is required. | 53 | 52 | If you did not register for Flashy, no action is required. | |
''' | 54 | 53 | ''' | |
55 | 54 | |||
send_mail("Please verify your Flashy account", | 56 | 55 | send_mail("Please verify your Flashy account", | |
body % user.confirmation_key, | 57 | 56 | body % user.confirmation_key, | |
"noreply@flashy.cards", | 58 | 57 | "noreply@flashy.cards", | |
[user.email]) | 59 | 58 | [user.email]) | |
user = authenticate(username=email, password=request.data['password']) | 60 | |||
print user | 61 | |||
login(request, user) | 62 | |||
63 | 59 | |||
60 | user = authenticate(email=email, password=request.data['password']) | |||
61 | login(request, user) | |||
return Response(UserSerializer(User).data) | 64 | 62 | return Response(UserSerializer(User).data) | |
65 | 63 | |||
def delete(self, request, format=None): | 66 | 64 | def delete(self, request, format=None): | |
request.user.delete() | 67 | 65 | request.user.delete() | |
return Response(status=status.HTTP_204_NO_CONTENT) | 68 | 66 | return Response(status=status.HTTP_204_NO_CONTENT) | |
69 | 67 | |||
68 | ||||
class UserLogin(APIView): | 70 | 69 | class UserLogin(APIView): | |
""" | 71 | 70 | """ | |
Authenticates user and returns user data if valid. Handles invalid | 72 | 71 | Authenticates user and returns user data if valid. Handles invalid | |
users. | 73 | 72 | users. | |
""" | 74 | 73 | """ | |
def post(self, request, format=None): | 75 | 74 | ||
75 | def post(self, request, format=None): | |||
""" | 76 | 76 | """ | |
Returns user data if valid. | 77 | 77 | Returns user data if valid. | |
""" | 78 | 78 | """ | |
if 'email' not in request.data: | 79 | 79 | if 'email' not in request.data: | |
raise ValidationError('Email is required') | 80 | 80 | raise ValidationError('Email is required') | |
if 'password' not in request.data: | 81 | 81 | if 'password' not in request.data: | |
raise ValidationError('Password is required') | 82 | 82 | raise ValidationError('Password is required') | |
83 | 83 | |||
email = request.data['email'] | 84 | 84 | email = request.data['email'] | |
password = request.data['password'] | 85 | 85 | password = request.data['password'] | |
user = authenticate(username=email, password=password) | 86 | 86 | user = authenticate(username=email, password=password) | |
87 | 87 | |||
if user is not None: | 88 | 88 | if user is None: | |
if user.is_active: | 89 | |||
login(request, user) | 90 | |||
return Response(UserSerializer(User).data) | 91 | |||
else: | 92 | |||
raise ValidationError('Account is disabled') | 93 | |||
else: | 94 | |||
raise ValidationError('Invalid email or password') | 95 | 89 | raise ValidationError('Invalid email or password') | |
90 | if not user.is_active: | |||
91 | raise ValidationError('Account is disabled') | |||
92 | login(request, user) | |||
93 | return Response(UserSerializer(User).data) | |||
96 | 94 | |||
95 | ||||
class PasswordReset(APIView): | 97 | 96 | class PasswordReset(APIView): | |
""" | 98 | 97 | """ | |
Allows user to reset their password. | 99 | 98 | Allows user to reset their password. | |
""" | 100 | 99 | """ | |
100 | ||||
def post(self, request, format=None): | 101 | 101 | def post(self, request, format=None): | |
""" | 102 | 102 | """ | |
Send a password reset token/link to the provided email. | 103 | 103 | Send a password reset token/link to the provided email. | |
""" | 104 | 104 | """ | |
if 'email' not in request.data: | 105 | 105 | if 'email' not in request.data: | |
raise ValidationError('Email is required') | 106 | 106 | raise ValidationError('Email is required') | |
107 | 107 | |||
email = request.data['email'] | 108 | 108 | email = request.data['email'] | |
109 | 109 | |||
# Find the user since they are not logged in. | 110 | 110 | # Find the user since they are not logged in. | |
try: | 111 | 111 | try: | |
user = User.objects.get(email=email) | 112 | 112 | user = User.objects.get(email=email) | |
except User.DoesNotExist: | 113 | 113 | except User.DoesNotExist: | |
raise NotFound('Email does not exist') | 114 | 114 | raise NotFound('Email does not exist') | |
115 | 115 | |||
token = default_token_generator.make_token(user) | 116 | 116 | token = default_token_generator.make_token(user) | |
117 | 117 | |||
body = ''' | 118 | 118 | body = ''' | |
Visit the following link to reset your password: | 119 | 119 | Visit the following link to reset your password: | |
http://flashy.cards/app/reset_password/%d/%s | 120 | 120 | http://flashy.cards/app/reset_password/%d/%s | |
121 | 121 | |||
If you did not request a password reset, no action is required. | 122 | 122 | If you did not request a password reset, no action is required. | |
''' | 123 | 123 | ''' | |
124 | 124 | |||
send_mail("Please verify your Flashy account", | 125 | 125 | send_mail("Flashy password reset", | |
body % (user.pk, token), | 126 | 126 | body % (user.pk, token), | |
"noreply@flashy.cards", | 127 | 127 | "noreply@flashy.cards", |
flashy/settings.py
View file @
d8dbb1c
""" | 1 | 1 | """ | |
Django settings for flashy project. | 2 | 2 | Django settings for flashy project. | |
3 | 3 | |||
Generated by 'django-admin startproject' using Django 1.8. | 4 | 4 | Generated by 'django-admin startproject' using Django 1.8. | |
5 | 5 | |||
For more information on this file, see | 6 | 6 | For more information on this file, see | |
https://docs.djangoproject.com/en/1.8/topics/settings/ | 7 | 7 | https://docs.djangoproject.com/en/1.8/topics/settings/ | |
8 | 8 | |||
For the full list of settings and their values, see | 9 | 9 | For the full list of settings and their values, see | |
https://docs.djangoproject.com/en/1.8/ref/settings/ | 10 | 10 | https://docs.djangoproject.com/en/1.8/ref/settings/ | |
""" | 11 | 11 | """ | |
12 | 12 | |||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) | 13 | 13 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) | |
import os | 14 | 14 | import os | |
15 | 15 | |||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 16 | 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
17 | 17 | |||
# SECURITY WARNING: don't run with debug turned on in production! | 18 | 18 | # SECURITY WARNING: don't run with debug turned on in production! | |
DEBUG = True | 19 | 19 | DEBUG = True | |
20 | 20 | |||
ALLOWED_HOSTS = [] | 21 | 21 | ALLOWED_HOSTS = [] | |
22 | 22 | |||
AUTH_USER_MODEL = 'flashcards.User' | 23 | 23 | AUTH_USER_MODEL = 'flashcards.User' | |
# Application definition | 24 | 24 | # Application definition | |
25 | 25 | |||
INSTALLED_APPS = ( | 26 | 26 | INSTALLED_APPS = ( | |
'simple_email_confirmation', | 27 | 27 | 'simple_email_confirmation', | |
'flashcards', | 28 | 28 | 'flashcards', | |
'django.contrib.admin', | 29 | 29 | 'django.contrib.admin', | |
'django.contrib.admindocs', | 30 | 30 | 'django.contrib.admindocs', | |
'django.contrib.auth', | 31 | 31 | 'django.contrib.auth', | |
'django.contrib.contenttypes', | 32 | 32 | 'django.contrib.contenttypes', | |
'django.contrib.sessions', | 33 | 33 | 'django.contrib.sessions', | |
'django.contrib.messages', | 34 | 34 | 'django.contrib.messages', | |
'django.contrib.staticfiles', | 35 | 35 | 'django.contrib.staticfiles', | |
'django_ses', | 36 | 36 | 'django_ses', | |
'rest_framework', | 37 | 37 | 'rest_framework', | |
38 | 38 | |||
39 | 39 | |||
) | 40 | 40 | ) | |
41 | 41 | |||
REST_FRAMEWORK = { | 42 | 42 | REST_FRAMEWORK = { | |
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', | 43 | 43 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', | |
'PAGE_SIZE': 20 | 44 | 44 | 'PAGE_SIZE': 20 | |
} | 45 | 45 | } | |
46 | 46 | |||
MIDDLEWARE_CLASSES = ( | 47 | 47 | MIDDLEWARE_CLASSES = ( | |
'django.contrib.sessions.middleware.SessionMiddleware', | 48 | 48 | 'django.contrib.sessions.middleware.SessionMiddleware', | |
'django.middleware.common.CommonMiddleware', | 49 | 49 | 'django.middleware.common.CommonMiddleware', | |
'django.middleware.csrf.CsrfViewMiddleware', | 50 | 50 | 'django.middleware.csrf.CsrfViewMiddleware', | |
'django.contrib.auth.middleware.AuthenticationMiddleware', | 51 | 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', | |
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', | 52 | 52 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', | |
'django.contrib.messages.middleware.MessageMiddleware', | 53 | 53 | 'django.contrib.messages.middleware.MessageMiddleware', | |
'django.middleware.clickjacking.XFrameOptionsMiddleware', | 54 | 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', | |
'django.middleware.security.SecurityMiddleware', | 55 | 55 | 'django.middleware.security.SecurityMiddleware', | |
) | 56 | 56 | ) | |
57 | 57 | |||
ROOT_URLCONF = 'flashy.urls' | 58 | 58 | ROOT_URLCONF = 'flashy.urls' | |
# Authentication backends | 59 | 59 | # Authentication backends | |
AUTHENTICATION_BACKENDS = ( | 60 | 60 | AUTHENTICATION_BACKENDS = ( | |
'django.contrib.auth.backends.ModelBackend', | 61 | 61 | 'django.contrib.auth.backends.ModelBackend', | |
) | 62 | 62 | ) | |
63 | ||||
TEMPLATES = [ | 63 | 64 | TEMPLATES = [ | |
{ | 64 | 65 | { | |
'BACKEND': 'django.template.backends.django.DjangoTemplates', | 65 | 66 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', | |
'DIRS': ['templates/'], | 66 | 67 | 'DIRS': ['templates/'], | |
'APP_DIRS': True, | 67 | 68 | 'APP_DIRS': True, | |
'OPTIONS': { | 68 | 69 | 'OPTIONS': { | |
'context_processors': [ | 69 | 70 | 'context_processors': [ | |
'django.template.context_processors.debug', | 70 | 71 | 'django.template.context_processors.debug', | |
'django.template.context_processors.request', | 71 | 72 | 'django.template.context_processors.request', | |
'django.contrib.auth.context_processors.auth', | 72 | 73 | 'django.contrib.auth.context_processors.auth', | |
'django.contrib.messages.context_processors.messages', | 73 | 74 | 'django.contrib.messages.context_processors.messages', | |
], | 74 | 75 | ], | |
}, | 75 | 76 | }, | |
}, | 76 | 77 | }, | |
] | 77 | 78 | ] | |
78 | 79 | |||
WSGI_APPLICATION = 'flashy.wsgi.application' | 79 | 80 | WSGI_APPLICATION = 'flashy.wsgi.application' | |
80 | 81 | |||
81 | 82 | |||
# Database | 82 | 83 | # Database | |
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases | 83 | 84 | # https://docs.djangoproject.com/en/1.8/ref/settings/#databases | |
84 | 85 | |||
DATABASES = { | 85 | 86 | DATABASES = { | |
'default': { | 86 | 87 | 'default': { | |
'ENGINE': 'django.db.backends.sqlite3', | 87 | 88 | 'ENGINE': 'django.db.backends.sqlite3', | |
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), | 88 | 89 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), | |
} | 89 | 90 | } | |
} | 90 | 91 | } | |
91 | 92 |