diff --git a/back/Pipfile b/back/Pipfile index 54943ec..c996bfc 100644 --- a/back/Pipfile +++ b/back/Pipfile @@ -9,8 +9,9 @@ verify_ssl = true django = "==2.1.5" django-cors-headers = "==2.4.0" djangorestframework = "==3.8.2" -gunicorn = "==19.6.0" django-rest-auth = "==0.9.3" +django-allauth = "==0.37.1" +gunicorn = "==19.6.0" [requires] python_version = "3.5" diff --git a/back/Pipfile.lock b/back/Pipfile.lock index e493330..a6ed173 100644 --- a/back/Pipfile.lock +++ b/back/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d3bf402a934e168cbdc04022effcdb9ff8d4fde5b83d79bb388ad2a4c547894a" + "sha256": "b1fc6b06ec8daa4efd9573865bc6c1732ae9354309e036bfe3ce0ab76b1a3bcd" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,27 @@ ] }, "default": { + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "version": "==2018.11.29" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "defusedxml": { + "hashes": [ + "sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4", + "sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20" + ], + "version": "==0.5.0" + }, "django": { "hashes": [ "sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8", @@ -24,6 +45,13 @@ "index": "pypi", "version": "==2.1.5" }, + "django-allauth": { + "hashes": [ + "sha256:02175aa1c2ddfd935a54011d1196d70c976647fc46f603f8b8758fc395b9d277" + ], + "index": "pypi", + "version": "==0.37.1" + }, "django-cors-headers": { "hashes": [ "sha256:5545009c9b233ea7e70da7dbab7cb1c12afa01279895086f98ec243d7eab46fa", @@ -55,6 +83,27 @@ "index": "pypi", "version": "==19.6.0" }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "oauthlib": { + "hashes": [ + "sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298", + "sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e" + ], + "version": "==3.0.1" + }, + "python3-openid": { + "hashes": [ + "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa", + "sha256:628d365d687e12da12d02c6691170f4451db28d6d68d050007e4a40065868502" + ], + "version": "==3.1.0" + }, "pytz": { "hashes": [ "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", @@ -62,12 +111,33 @@ ], "version": "==2018.9" }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "version": "==2.21.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57", + "sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140" + ], + "version": "==1.2.0" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" ], "version": "==1.12.0" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" } }, "develop": {} diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 2a1a553..8074d09 100644 Binary files a/back/db.sqlite3 and b/back/db.sqlite3 differ diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py index 6fb5556..86f1b58 100644 --- a/back/reimbursinator/settings.py +++ b/back/reimbursinator/settings.py @@ -39,10 +39,15 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.sites', # 3rd party 'rest_framework', 'rest_framework.authtoken', + 'allauth', + 'allauth.account', + 'allauth.socialaccount', 'rest_auth', + 'rest_auth.registration', 'corsheaders', # local 'users', @@ -149,3 +154,25 @@ USE_TZ = True # https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' + +# Email Config + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +SITE_ID = 1 + +# Registration + +#ACCOUNT_USER_MODEL_USERNAME_FIELD = 'email' +ACCOUNT_EMAIL_REQUIRED = True +ACCOUNT_USERNAME_REQUIRED = False +ACCOUNT_AUTHENTICATION_METHOD = 'email' + +REST_AUTH_REGISTER_SERIALIZERS = { + 'REGISTER_SERIALIZER': 'users.serializers.RegisterSerializer', +} + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'allauth.account.auth_backends.AuthenticationBackend', +) diff --git a/back/reimbursinator/urls.py b/back/reimbursinator/urls.py index 62397e8..7a33b6d 100644 --- a/back/reimbursinator/urls.py +++ b/back/reimbursinator/urls.py @@ -13,5 +13,7 @@ urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/', include("backend.urls")), path('api/v1/account/', include('rest_auth.urls')), + path('api/v1/account/register/', include('rest_auth.registration.urls')), + # path('api/v1/account/register/', NameRegistrationView.as_view()), path('api-auth/', include('rest_framework.urls')), ] diff --git a/back/users/serializers.py b/back/users/serializers.py new file mode 100644 index 0000000..91416a4 --- /dev/null +++ b/back/users/serializers.py @@ -0,0 +1,47 @@ +from rest_framework import serializers +from allauth.account import app_settings as allauth_settings +from allauth.utils import email_address_exists +from allauth.account.adapter import get_adapter +from allauth.account.utils import setup_user_email +from django.utils.translation import gettext as _ + +class RegisterSerializer(serializers.Serializer): + email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED) + first_name = serializers.CharField(required=True, write_only=True) + last_name = serializers.CharField(required=True, write_only=True) + password1 = serializers.CharField(required=True, write_only=True) + password2 = serializers.CharField(required=True, write_only=True) + + def validate_email(self, email): + email = get_adapter().clean_email(email) + if allauth_settings.UNIQUE_EMAIL: + if email and email_address_exists(email): + raise serializers.ValidationError( + _("A user is already registered with this e-mail address.")) + return email + + def validate_password1(self, password): + return get_adapter().clean_password(password) + + def validate(self, data): + if data['password1'] != data['password2']: + raise serializers.ValidationError( + _("The two password fields didn't match.")) + return data + + def get_cleaned_data(self): + return { + 'first_name': self.validated_data.get('first_name', ''), + 'last_name': self.validated_data.get('last_name', ''), + 'password1': self.validated_data.get('password1', ''), + 'email': self.validated_data.get('email', ''), + } + + def save(self, request): + adapter = get_adapter() + user = adapter.new_user(request) + self.cleaned_data = self.get_cleaned_data() + adapter.save_user(request, user, self) + setup_user_email(request, user, []) + user.save() + return user diff --git a/back/users/views.py b/back/users/views.py index 91ea44a..2536b37 100644 --- a/back/users/views.py +++ b/back/users/views.py @@ -1,3 +1 @@ from django.shortcuts import render - -# Create your views here.