From ad9d05721764d8129210a7ad85fa414bcb724141 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Tue, 2 Jul 2019 23:36:26 +0300 Subject: [PATCH 01/24] feat(auth): user authentication - user registration --- Pipfile | 2 + Pipfile.lock | 25 +++++- Procfile | 2 +- app/apps.py | 5 ++ app/authentication/__init__.py | 0 app/authentication/admin.py | 3 + app/authentication/choices.py | 4 + app/authentication/migrations/0001_initial.py | 43 ++++++++++ app/authentication/migrations/__init__.py | 0 app/authentication/models.py | 85 +++++++++++++++++++ app/authentication/serializers.py | 29 +++++++ app/authentication/tests.py | 3 + app/authentication/urls.py | 17 ++++ app/authentication/views.py | 18 ++++ app/firebase_auth.py | 47 ++++++++++ dscountr/__init__.py | 0 {app => dscountr}/settings.py | 24 +++++- {app => dscountr}/urls.py | 4 +- {app => dscountr}/wsgi.py | 2 +- manage.py | 2 +- 20 files changed, 308 insertions(+), 7 deletions(-) create mode 100644 app/apps.py create mode 100644 app/authentication/__init__.py create mode 100644 app/authentication/admin.py create mode 100644 app/authentication/choices.py create mode 100644 app/authentication/migrations/0001_initial.py create mode 100644 app/authentication/migrations/__init__.py create mode 100644 app/authentication/models.py create mode 100644 app/authentication/serializers.py create mode 100644 app/authentication/tests.py create mode 100644 app/authentication/urls.py create mode 100644 app/authentication/views.py create mode 100644 app/firebase_auth.py create mode 100644 dscountr/__init__.py rename {app => dscountr}/settings.py (83%) rename {app => dscountr}/urls.py (84%) rename {app => dscountr}/wsgi.py (82%) diff --git a/Pipfile b/Pipfile index 8393ed0..5a02909 100644 --- a/Pipfile +++ b/Pipfile @@ -18,6 +18,8 @@ psycopg2 = "==2.7.5" django-cors-headers = "==3.0.2" gunicorn = "==19.9.0" django-heroku = "==0.3.1" +django-phonenumber-field = "==3.0.1" +phonenumbers = "==8.10.14" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 9ce7275..57798c2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "fa9c6780a0999e892805c25a6e66ad399ab333cf596bc617f40362b5bdb222db" + "sha256": "c6ee15b5f6ee0af891ab4fdf5a1b3469d6284e87068c3143b4cab08aaf33241b" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,13 @@ ] }, "default": { + "babel": { + "hashes": [ + "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", + "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" + ], + "version": "==2.7.0" + }, "cachecontrol": { "hashes": [ "sha256:cef77effdf51b43178f6a2d3b787e3734f98ade253fa3187f3bb7315aaa42ff7" @@ -83,6 +90,14 @@ "index": "pypi", "version": "==0.3.1" }, + "django-phonenumber-field": { + "hashes": [ + "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e", + "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97" + ], + "index": "pypi", + "version": "==3.0.1" + }, "djangorestframework": { "hashes": [ "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", @@ -246,6 +261,14 @@ ], "version": "==0.6.1" }, + "phonenumbers": { + "hashes": [ + "sha256:81757480b3553e9aa8b7442f28fc53e7c8335ef8c99c3b292bcd55b08820aa00", + "sha256:cb1d559b3f63cef4e8521f9ebeb4f41a0320f97463f3b11c15bd7d1d3e0f40db" + ], + "index": "pypi", + "version": "==8.10.14" + }, "protobuf": { "hashes": [ "sha256:03f43eac9d5b651f976e91cf46a25b75e5779d98f0f4114b0abfed83376d75f8", diff --git a/Procfile b/Procfile index b7398ac..225f1fd 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: gunicorn app.wsgi \ No newline at end of file +web: gunicorn dscountr.wsgi \ No newline at end of file diff --git a/app/apps.py b/app/apps.py new file mode 100644 index 0000000..6b5d94f --- /dev/null +++ b/app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MyappConfig(AppConfig): + name = 'app' diff --git a/app/authentication/__init__.py b/app/authentication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/authentication/admin.py b/app/authentication/admin.py new file mode 100644 index 0000000..0dcbec1 --- /dev/null +++ b/app/authentication/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register models here. diff --git a/app/authentication/choices.py b/app/authentication/choices.py new file mode 100644 index 0000000..983022b --- /dev/null +++ b/app/authentication/choices.py @@ -0,0 +1,4 @@ +GENDER_CHOICES = ( + ('M', 'Male'), + ('F', 'Female'), +) diff --git a/app/authentication/migrations/0001_initial.py b/app/authentication/migrations/0001_initial.py new file mode 100644 index 0000000..b06415b --- /dev/null +++ b/app/authentication/migrations/0001_initial.py @@ -0,0 +1,43 @@ +# Generated by Django 2.2.3 on 2019-07-02 20:00 + +import app.authentication.models +from django.db import migrations, models +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0011_update_proxy_permissions'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(db_index=True, max_length=255, unique=True)), + ('email', models.EmailField(db_index=True, max_length=254, unique=True)), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(db_index=True, max_length=128, region=None, unique=True)), + ('date_of_birth', models.DateField()), + ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=1)), + ('password', models.CharField(max_length=128)), + ('is_active', models.BooleanField(default=True)), + ('is_staff', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name_plural': 'All Users', + }, + managers=[ + ('objects', app.authentication.models.UserManager()), + ], + ), + ] diff --git a/app/authentication/migrations/__init__.py b/app/authentication/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/authentication/models.py b/app/authentication/models.py new file mode 100644 index 0000000..b23c3ca --- /dev/null +++ b/app/authentication/models.py @@ -0,0 +1,85 @@ +from django.conf import settings +from django.contrib.auth.models import ( + AbstractBaseUser, BaseUserManager, PermissionsMixin +) +from django.db import models +from django.core.exceptions import ValidationError +from decouple import config +from phonenumber_field.modelfields import PhoneNumberField +from firebase_admin import auth +from .choices import GENDER_CHOICES + + +class UserManager(BaseUserManager): + use_in_migrations = True + + def createuser(self, **fields): + email = fields.pop('email') + password = fields.get('password') + + if not email: + raise ValueError("Email address is required") + email = self.normalize_email(email) + user = self.model(email=email, **fields) + user.set_password(password) + user.save(using=self._db) + return user + + def create_superuser(self, **fields): + """ + Create and return a `User` with superuser (admin) permissions. + """ + + user = self.createuser(**fields) + user.is_superuser = True + user.is_staff = True + user.save() + + return user + + +class User(AbstractBaseUser, PermissionsMixin): + + username = models.CharField(db_index=True, max_length=255, unique=True) + email = models.EmailField(db_index=True, unique=True) + phone_number = PhoneNumberField(db_index=True, unique=True) + date_of_birth = models.DateField() + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) + password = models.CharField(max_length=128) + is_active = models.BooleanField(default=True) + is_staff = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + # The `USERNAME_FIELD` property specifies the log in field. + USERNAME_FIELD = 'phone_number' + REQUIRED_FIELDS = ['username', 'email', 'date_of_birth', ] + + # the UserManager class should manage objects of this type. + objects = UserManager() + + class Meta: + verbose_name_plural = "All Users" + + def __str__(self): + """ + Returns a string representation of this `User`. + used when a `User` is printed in the console. + """ + return self.email + + @property + def token(self): + """ + method allows us to get a user's token + """ + return self._generate_firebase_token() + + def _generate_firebase_token(self): + """ + Generates a firebase token + """ + uid = config('UID') + token = auth.create_custom_token(uid) + + return token.decode('utf-8') diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py new file mode 100644 index 0000000..9a15ded --- /dev/null +++ b/app/authentication/serializers.py @@ -0,0 +1,29 @@ +from rest_framework import serializers +from django.contrib.auth import authenticate +from rest_framework.validators import UniqueValidator +from .models import User +from firebase_admin import auth +from phonenumber_field.serializerfields import PhoneNumberField + + +class RegistrationSerializer(serializers.ModelSerializer): + password = serializers.CharField( + max_length=128, + min_length=8, + write_only=True + ) + + token = serializers.CharField(max_length=255, read_only=True) + phone_number = PhoneNumberField( + validators=[ + UniqueValidator(queryset=User.objects.all(), + message='User with this Phone Number already exists.', + )],) + + class Meta: + model = User + fields = ['id', 'email', 'username', 'password', 'token', + 'phone_number', 'date_of_birth', 'gender'] + + def create(self, validated_data): + return User.objects.createuser(**validated_data) diff --git a/app/authentication/tests.py b/app/authentication/tests.py new file mode 100644 index 0000000..47927bb --- /dev/null +++ b/app/authentication/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Write tests here. diff --git a/app/authentication/urls.py b/app/authentication/urls.py new file mode 100644 index 0000000..00d83e0 --- /dev/null +++ b/app/authentication/urls.py @@ -0,0 +1,17 @@ +from django.urls import path +from rest_framework.routers import DefaultRouter, SimpleRouter +from .views import RegistrationViewSet + +app_name = 'authentication' + + +class OptionalTrailingSlashRouter(SimpleRouter): + def __init_(self, trailing_slash='/?'): + self.trailing_slash = trailing_slash + super().__init__() + + +router = OptionalTrailingSlashRouter() +router.register('users', RegistrationViewSet, 'user') + +urlpatterns = router.urls diff --git a/app/authentication/views.py b/app/authentication/views.py new file mode 100644 index 0000000..d4c4c1a --- /dev/null +++ b/app/authentication/views.py @@ -0,0 +1,18 @@ +from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated +from rest_framework.viewsets import ModelViewSet +from .serializers import (RegistrationSerializer,) +from . import models + + +class RegistrationViewSet(ModelViewSet): + permission_classes = (AllowAny,) + serializer_class = RegistrationSerializer + queryset = models.User.objects.all() + http_method_names = ['post'] + + +class UserViewSet(ModelViewSet): + permission_classes = (IsAdminUser, IsAuthenticated) + serializer_class = RegistrationSerializer + queryset = models.User.objects.all() + http_method_names = ['post', 'get', 'patch'] diff --git a/app/firebase_auth.py b/app/firebase_auth.py new file mode 100644 index 0000000..a90ca0f --- /dev/null +++ b/app/firebase_auth.py @@ -0,0 +1,47 @@ +import logging +from django.contrib.auth import get_user_model +from rest_framework import exceptions +from rest_framework.authentication import TokenAuthentication +from decouple import config +from firebase_admin import auth, credentials, initialize_app + + +private_key = config("PRIVATE_KEY").replace("\\n", "\n") +payload = { + "type": "service_account", + "project_id": config("PROJECT_ID"), + "private_key_id": config("PRIVATE_KEY_ID"), + "private_key": private_key, + "client_email": config("CLIENT_EMAIL"), + "client_id": config("CLIENT_ID"), + "auth_uri": config("AUTH_URI"), + "token_uri": config("TOKEN_URI"), + "auth_provider_x509_cert_url": config("AUTH_PROVIDER_X509_CERT_URL"), + "client_x509_cert_url": config("CLIENT_X509_CERT_URL"), +} + +cred = credentials.Certificate(payload) +initialize_app(cred) + +User = get_user_model() +logger = logging.getLogger(__name__) + + +class FirebaseTokenAuthentication(TokenAuthentication): + def authenticate_credentials(self, key): + try: + token = auth.verify_id_token(key) + except Exception: + raise exceptions.AuthenticationFailed( + "Unable to authenticate. Invalid or expired token") + else: + email = token.get("email") + try: + user = User.objects.get(email=email) + except Exception as e: + logger.error(str(e)) + raise exceptions.AuthenticationFailed("User not found") + + if not user.is_active: + raise exceptions.AuthenticationFailed("User inactive or deleted.") + return (user, token) diff --git a/dscountr/__init__.py b/dscountr/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/settings.py b/dscountr/settings.py similarity index 83% rename from app/settings.py rename to dscountr/settings.py index ed639d0..e3cc250 100644 --- a/app/settings.py +++ b/dscountr/settings.py @@ -40,11 +40,17 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', + 'app', + 'corsheaders', + 'django_extensions', + 'app.authentication', + 'phonenumber_field', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -52,7 +58,9 @@ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -ROOT_URLCONF = 'app.urls' +CORS_ORIGIN_ALLOW_ALL = True + +ROOT_URLCONF = 'dscountr.urls' TEMPLATES = [ { @@ -70,7 +78,7 @@ }, ] -WSGI_APPLICATION = 'app.wsgi.application' +WSGI_APPLICATION = 'dscountr.wsgi.application' # Database @@ -99,6 +107,14 @@ }, ] +REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": ( + 'app.firebase_auth.FirebaseTokenAuthentication', + "rest_framework.authentication.BasicAuthentication", + "rest_framework.authentication.SessionAuthentication", + ), +} + # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ @@ -119,5 +135,9 @@ STATIC_URL = '/static/' +AUTH_USER_MODEL = 'authentication.User' + # Activate Django-Heroku. django_heroku.settings(locals()) + +del DATABASES['default']['OPTIONS']['sslmode'] diff --git a/app/urls.py b/dscountr/urls.py similarity index 84% rename from app/urls.py rename to dscountr/urls.py index 5348901..6109471 100644 --- a/app/urls.py +++ b/dscountr/urls.py @@ -14,8 +14,10 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include +from app.authentication import urls urlpatterns = [ path('admin/', admin.site.urls), + path('api/', include(urls, namespace='authentication')), ] diff --git a/app/wsgi.py b/dscountr/wsgi.py similarity index 82% rename from app/wsgi.py rename to dscountr/wsgi.py index c618da6..c759d4e 100644 --- a/app/wsgi.py +++ b/dscountr/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dscountr.settings') application = get_wsgi_application() diff --git a/manage.py b/manage.py index 648715e..215fac0 100755 --- a/manage.py +++ b/manage.py @@ -3,7 +3,7 @@ import sys if __name__ == '__main__': - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dscountr.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: From 463b2c5e2d7ea27d2ce30f5b53d3e6e8a366fb54 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Thu, 4 Jul 2019 03:25:20 +0300 Subject: [PATCH 02/24] updated dependancies in the pipenv file --- Pipfile.lock | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 57798c2..9dbbdf5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c6ee15b5f6ee0af891ab4fdf5a1b3469d6284e87068c3143b4cab08aaf33241b" + "sha256": "9ebca0b7783e49cbff48f1dc1ea9ebca91ab5ec18c07bf39460b02ad3f7b2830" }, "pipfile-spec": 6, "requires": { @@ -182,40 +182,40 @@ }, "grpcio": { "hashes": [ - "sha256:0232add03144dd3cf9b660e2718244cb8e175370dca4d3855cb4e489a7811b53", - "sha256:0f20e6dcb1b8662cdca033bb97c0a8116a5343e3ebc7f71c5fe7f89039978350", - "sha256:10b07a623d33d4966f45c85d410bc6a79c5ac6341f06c3beda6c22be12cbfe07", - "sha256:10c0476d5a52d21f402fc073745dc43b87cc8e080a1f49bbff4e1059019310fb", - "sha256:289dae0b35c59d191c524e976dd0a6f8c995d2062e72621eb866ad0f4472a635", - "sha256:2be726f16142d358a0df1e81d583d6820ee561a7856a79cca2fbe49989308be7", - "sha256:4338d2a81f5b4ca022e085040b3cfce19419a5ce44aa7e6810ac1df05365bed7", - "sha256:4c535b46f20e66bee3097583231977e721acdfcb1671d1490c99b7be8902ce18", - "sha256:557154aef70a0e979700cc9528bc8b606b668084a29a0d57dbc4b06b078a2f1c", - "sha256:5bfdd7e6647498f979dc46583723c852d97b25afe995d55aa1c76a5f9816bc1f", - "sha256:87d8943ae7aa6ca5bbad732867d7f17d2550e4966a0c15b52088e8b579422e47", - "sha256:89d8719d8de4d137678f7caa979e1b0a6fd4026f8096ceef8c2d164bbabefaf2", - "sha256:9c3f4af989ce860710ac1864dc2e867dd87e6cee51a2368df1b253596868e52f", - "sha256:9da52c3c728883aee429bb7c315049f50b2139f680cd86bb1165418e4f93a982", - "sha256:9e9736659987beab42d18525ed10d21f80a1ba8389eac03425fbfd5684e6bbf0", - "sha256:9ebcbb1a054cab362d29d3be571d43d6b9b23302d9fc4b43e5327000da1680a9", - "sha256:a93e08636623e24c939851e2e0c0140b14f524b2980c9cdc4ea52b70a871c7e0", - "sha256:ac322d86d1a079e0a118d544443ee16f320af0062c191b4754c0c6ec2fc79310", - "sha256:b1fb101459868f52df6b61e7bb13375e50badf17a160e39fe1d51ae19e53f461", - "sha256:b39aac96cceac624a23d540473835086a3ffa77c91030189988c073488434493", - "sha256:b65507bc273c6dbf539175a786a344cc0ac78d50e5584f72c6599733f8a3301f", - "sha256:be5bb6e47417e537c884a2e2ff2e1a8b2c064a998fcfdfcc67528d4e63e7ebaf", - "sha256:c92de6a28a909c4f460dc1bbbcb50d676cf0b1f40224b222761f73fdd851b522", - "sha256:c9f5962eb7fa7607b20eb0e4f59ed35829bd600fc0eacb626a6db83229a3e445", - "sha256:d00bdf9c546ed6e649f785c55b05288e8b2dbb6bf2eb74b6c579fa0d591d35bd", - "sha256:da804b1dd8293bd9d61b1e6ea989c887ba042a808a4fbdd80001cfa059aafed2", - "sha256:ead6c5aa3e807345913649c3be395aaca2bbb2d225f18b8f31f37eab225508f6", - "sha256:eb4d81550ce6f826af4ec6e8d98be347fe96291d718bf115c3f254621ae8d98d", - "sha256:ef6a18ec8fd32ec81748fe720544ea2fb2d2dc50fd6d06739d5e2eb8f0626a1c", - "sha256:fad42835656e0b6d3b7ffc900598e776722e30f43b7234a48f2576ca30f31a47", - "sha256:fb98dbfee0d963b49ae5754554028cf62e6bd695f22de16d242ba9d2f0b7339b", - "sha256:fb9cd9bb8d26dc17c2dd715a46bca3a879ec8283879b164e85863110dc6e3b2a" - ], - "version": "==1.21.1" + "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2", + "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce", + "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb", + "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e", + "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941", + "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e", + "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce", + "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf", + "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f", + "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303", + "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2", + "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf", + "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e", + "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369", + "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87", + "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e", + "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97", + "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2", + "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369", + "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67", + "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174", + "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f", + "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b", + "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e", + "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0", + "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad", + "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa", + "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03", + "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1", + "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348", + "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530", + "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc" + ], + "version": "==1.22.0" }, "gunicorn": { "hashes": [ From e2c2e6d35b5d605faf0491e6e7e6e33769ec66ac Mon Sep 17 00:00:00 2001 From: meshnesh Date: Sat, 6 Jul 2019 15:40:11 +0300 Subject: [PATCH 03/24] added alien gender --- app/authentication/choices.py | 1 + dscountr/settings.py | 1 + 2 files changed, 2 insertions(+) diff --git a/app/authentication/choices.py b/app/authentication/choices.py index 983022b..e06de7b 100644 --- a/app/authentication/choices.py +++ b/app/authentication/choices.py @@ -1,4 +1,5 @@ GENDER_CHOICES = ( ('M', 'Male'), ('F', 'Female'), + ('A', 'Alien'), ) diff --git a/dscountr/settings.py b/dscountr/settings.py index e3cc250..6508afb 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -140,4 +140,5 @@ # Activate Django-Heroku. django_heroku.settings(locals()) +print("This is the DB",DATABASES) del DATABASES['default']['OPTIONS']['sslmode'] From 94f434b0694174a98b380d33c357ba64eaf1a8de Mon Sep 17 00:00:00 2001 From: graycadeau Date: Mon, 8 Jul 2019 18:22:03 +0300 Subject: [PATCH 04/24] user profile --- Procfile | 1 + .../migrations/0002_auto_20190708_1300.py | 18 ++++++++ app/authentication/serializers.py | 45 +++++++++++++++++++ app/authentication/urls.py | 6 ++- app/authentication/views.py | 7 ++- app/firebase_auth.py | 14 +++--- app/user_profile/__init__.py | 0 app/user_profile/migrations/0001_initial.py | 32 +++++++++++++ app/user_profile/migrations/__init__.py | 0 app/user_profile/models.py | 27 +++++++++++ app/user_profile/serializers.py | 18 ++++++++ app/user_profile/views.py | 14 ++++++ dscountr/settings.py | 7 ++- 13 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 app/authentication/migrations/0002_auto_20190708_1300.py create mode 100644 app/user_profile/__init__.py create mode 100644 app/user_profile/migrations/0001_initial.py create mode 100644 app/user_profile/migrations/__init__.py create mode 100644 app/user_profile/models.py create mode 100644 app/user_profile/serializers.py create mode 100644 app/user_profile/views.py diff --git a/Procfile b/Procfile index 225f1fd..1f7e008 100644 --- a/Procfile +++ b/Procfile @@ -1 +1,2 @@ +release: python manage.py migrate web: gunicorn dscountr.wsgi \ No newline at end of file diff --git a/app/authentication/migrations/0002_auto_20190708_1300.py b/app/authentication/migrations/0002_auto_20190708_1300.py new file mode 100644 index 0000000..44ec40f --- /dev/null +++ b/app/authentication/migrations/0002_auto_20190708_1300.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-08 13:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='gender', + field=models.CharField(choices=[('M', 'Male'), ('F', 'Female'), ('A', 'Alien')], max_length=1), + ), + ] diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 9a15ded..1c5767b 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -4,6 +4,7 @@ from .models import User from firebase_admin import auth from phonenumber_field.serializerfields import PhoneNumberField +from ..user_profile.models import Profile class RegistrationSerializer(serializers.ModelSerializer): @@ -27,3 +28,47 @@ class Meta: def create(self, validated_data): return User.objects.createuser(**validated_data) + + +class LoginSerializer(serializers.ModelSerializer): + email = serializers.CharField(max_length=255) + username = serializers.CharField(max_length=255, read_only=True) + password = serializers.CharField( + max_length=128, write_only=True) + token = serializers.CharField(max_length=255, read_only=True) + + class Meta: + model = User + fields = ['email', 'username', 'password', 'token'] + + def create(self, data): + email = data.get('email') + password = data.get('password') + + if email is None: + raise serializers.ValidationError( + 'An email address is required to log in.' + ) + + if password is None: + raise serializers.ValidationError( + 'A password is required to log in.' + ) + + user = authenticate(username=email, password=password) + + if user is None: + raise serializers.ValidationError( + 'A user with this email and password was not found.' + ) + + if not user.is_active: + raise serializers.ValidationError( + 'This user has been deactivated.' + ) + + return { + 'email': user.email, + 'username': user.username, + 'token': user.token + } diff --git a/app/authentication/urls.py b/app/authentication/urls.py index 00d83e0..6879fb0 100644 --- a/app/authentication/urls.py +++ b/app/authentication/urls.py @@ -1,6 +1,7 @@ from django.urls import path from rest_framework.routers import DefaultRouter, SimpleRouter -from .views import RegistrationViewSet +from .views import RegistrationViewSet, LoginViewSet +from ..user_profile.views import UserProfileViewSet app_name = 'authentication' @@ -13,5 +14,8 @@ def __init_(self, trailing_slash='/?'): router = OptionalTrailingSlashRouter() router.register('users', RegistrationViewSet, 'user') +router.register('profiles', UserProfileViewSet, 'profile') +router.register('login', LoginViewSet, 'login') + urlpatterns = router.urls diff --git a/app/authentication/views.py b/app/authentication/views.py index d4c4c1a..4550dcf 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -1,6 +1,6 @@ from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated from rest_framework.viewsets import ModelViewSet -from .serializers import (RegistrationSerializer,) +from .serializers import (RegistrationSerializer, LoginSerializer) from . import models @@ -11,6 +11,11 @@ class RegistrationViewSet(ModelViewSet): http_method_names = ['post'] +class LoginViewSet(ModelViewSet): + permission_classes = (AllowAny,) + serializer_class = LoginSerializer + + class UserViewSet(ModelViewSet): permission_classes = (IsAdminUser, IsAuthenticated) serializer_class = RegistrationSerializer diff --git a/app/firebase_auth.py b/app/firebase_auth.py index a90ca0f..8fca5a7 100644 --- a/app/firebase_auth.py +++ b/app/firebase_auth.py @@ -14,10 +14,10 @@ "private_key": private_key, "client_email": config("CLIENT_EMAIL"), "client_id": config("CLIENT_ID"), - "auth_uri": config("AUTH_URI"), - "token_uri": config("TOKEN_URI"), - "auth_provider_x509_cert_url": config("AUTH_PROVIDER_X509_CERT_URL"), - "client_x509_cert_url": config("CLIENT_X509_CERT_URL"), + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hq70h%40dscountr-49c53.iam.gserviceaccount.com", } cred = credentials.Certificate(payload) @@ -28,10 +28,10 @@ class FirebaseTokenAuthentication(TokenAuthentication): - def authenticate_credentials(self, key): + def authenticate_credentials(self, id_token): try: - token = auth.verify_id_token(key) - except Exception: + token = auth.verify_id_token(id_token) + except Exception as e: raise exceptions.AuthenticationFailed( "Unable to authenticate. Invalid or expired token") else: diff --git a/app/user_profile/__init__.py b/app/user_profile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/user_profile/migrations/0001_initial.py b/app/user_profile/migrations/0001_initial.py new file mode 100644 index 0000000..32644d0 --- /dev/null +++ b/app/user_profile/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 2.2.3 on 2019-07-08 13:00 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django_extensions.db.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), + ('first_name', models.CharField(blank=True, max_length=30)), + ('last_name', models.CharField(blank=True, max_length=30)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-created'], + }, + ), + ] diff --git a/app/user_profile/migrations/__init__.py b/app/user_profile/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/user_profile/models.py b/app/user_profile/models.py new file mode 100644 index 0000000..98d6f81 --- /dev/null +++ b/app/user_profile/models.py @@ -0,0 +1,27 @@ +from django.db import models +from django.contrib.auth import get_user_model +from django.db.models.signals import post_save +from django.dispatch import receiver +from django_extensions.db.models import TimeStampedModel + +User = get_user_model() + + +class Profile(TimeStampedModel): + user = models.OneToOneField( + "authentication.User", related_name="profile", on_delete=models.CASCADE) + first_name = models.CharField(max_length=30, blank=True) + last_name = models.CharField(max_length=30, blank=True) + + class Meta: + ordering = ['-created', ] + + def __str__(self): + return self.user.username + + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + if created: + Profile.objects.create(user=instance) + instance.profile.save() diff --git a/app/user_profile/serializers.py b/app/user_profile/serializers.py new file mode 100644 index 0000000..3b7e31a --- /dev/null +++ b/app/user_profile/serializers.py @@ -0,0 +1,18 @@ +from rest_framework import serializers + +from .models import Profile + + +class UserProfileSerializer(serializers.ModelSerializer): + """ + Serializer class for getting user profile + """ + username = serializers.ReadOnlyField(source='fetch_username') + first_name = serializers.CharField( + allow_blank=True, required=False, min_length=1, max_length=50) + last_name = serializers.CharField( + allow_blank=True, required=False, min_length=1, max_length=50) + + class Meta: + model = Profile + fields = ['username', 'id', 'first_name', 'last_name'] diff --git a/app/user_profile/views.py b/app/user_profile/views.py new file mode 100644 index 0000000..30bec24 --- /dev/null +++ b/app/user_profile/views.py @@ -0,0 +1,14 @@ +from rest_framework.permissions import IsAdminUser, IsAuthenticated, AllowAny +from rest_framework.viewsets import ModelViewSet +from rest_framework.generics import get_object_or_404 +from .serializers import (UserProfileSerializer,) +from . import models +from ..firebase_auth import FirebaseTokenAuthentication + + +class UserProfileViewSet(ModelViewSet): + permission_classes = (AllowAny,) + serializer_class = UserProfileSerializer + authentication_classes = (FirebaseTokenAuthentication,) + queryset = models.Profile.objects.all() + http_method_names = ['get', 'patch'] diff --git a/dscountr/settings.py b/dscountr/settings.py index 6508afb..8f16a67 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -44,6 +44,7 @@ 'corsheaders', 'django_extensions', 'app.authentication', + 'app.user_profile', 'phonenumber_field', ] @@ -113,6 +114,11 @@ "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", ), + "DEFAULT_AUTHENTICATION_CLASSES": ( + 'app.firebase_auth.FirebaseTokenAuthentication', + "rest_framework.authentication.BasicAuthentication", + "rest_framework.authentication.SessionAuthentication", + ), } @@ -140,5 +146,4 @@ # Activate Django-Heroku. django_heroku.settings(locals()) -print("This is the DB",DATABASES) del DATABASES['default']['OPTIONS']['sslmode'] From 7da244be434ea40d01a60dc99114793dbabbc4b1 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Mon, 8 Jul 2019 19:03:01 +0300 Subject: [PATCH 05/24] lock pipenv --- app/authentication/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/authentication/tests.py b/app/authentication/tests.py index 47927bb..a0a0615 100644 --- a/app/authentication/tests.py +++ b/app/authentication/tests.py @@ -1,3 +1,3 @@ from django.test import TestCase -# Write tests here. +# Write tests here for the application From 57757aaa8a46ccb6aa042dd8f51b8ea7cdbd0282 Mon Sep 17 00:00:00 2001 From: Antony Date: Mon, 8 Jul 2019 19:05:54 +0300 Subject: [PATCH 06/24] Delete Pipfile.lock --- Pipfile.lock | 512 --------------------------------------------------- 1 file changed, 512 deletions(-) delete mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 9dbbdf5..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,512 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "9ebca0b7783e49cbff48f1dc1ea9ebca91ab5ec18c07bf39460b02ad3f7b2830" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "babel": { - "hashes": [ - "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", - "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" - ], - "version": "==2.7.0" - }, - "cachecontrol": { - "hashes": [ - "sha256:cef77effdf51b43178f6a2d3b787e3734f98ade253fa3187f3bb7315aaa42ff7" - ], - "version": "==0.12.5" - }, - "cachetools": { - "hashes": [ - "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae", - "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a" - ], - "version": "==3.1.1" - }, - "certifi": { - "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" - ], - "version": "==2019.6.16" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "dj-database-url": { - "hashes": [ - "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", - "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" - ], - "index": "pypi", - "version": "==0.5.0" - }, - "django": { - "hashes": [ - "sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", - "sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" - ], - "index": "pypi", - "version": "==2.2.3" - }, - "django-cors-headers": { - "hashes": [ - "sha256:5b80bf0f8d7fc6e2bcb4f40781d5ff3661961bbf1982e52daec77241dea3b890", - "sha256:ebf3e2cf25aa6993b959a8e6a87828ebb3c8fe5bc3ec4a2d6e65f3b8d9b4212c" - ], - "index": "pypi", - "version": "==3.0.2" - }, - "django-extensions": { - "hashes": [ - "sha256:097450a56fcfdef36bb4dd731b113d1b3e9a9de715fc8775e5e84ab3be50dd96", - "sha256:a1799a7eb4cf0f7aa0d111bac79047227b55a74d11741f387708023a012662f9" - ], - "index": "pypi", - "version": "==2.1.9" - }, - "django-heroku": { - "hashes": [ - "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", - "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" - ], - "index": "pypi", - "version": "==0.3.1" - }, - "django-phonenumber-field": { - "hashes": [ - "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e", - "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97" - ], - "index": "pypi", - "version": "==3.0.1" - }, - "djangorestframework": { - "hashes": [ - "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", - "sha256:c12869cfd83c33d579b17b3cb28a2ae7322a53c3ce85580c2a2ebe4e3f56c4fb" - ], - "index": "pypi", - "version": "==3.9.4" - }, - "firebase-admin": { - "hashes": [ - "sha256:3bf83d37161f00ce6cd1f046a6d4ed9de8504618b68b8af4dee5bd27e6f96251" - ], - "index": "pypi", - "version": "==2.17.0" - }, - "google-api-core": { - "extras": [ - "grpc" - ], - "hashes": [ - "sha256:72a1c8966bdbd70a72de32760368aec399fe6a5c2a6675d9476cb9ae27046de7", - "sha256:f45d74aef41e1de49ceadebf382e1291ddcbe431a8b533aff8a1140a35531465" - ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.13.0" - }, - "google-api-python-client": { - "hashes": [ - "sha256:048da0d68564380ee23b449e5a67d4666af1b3b536d2fb0a02cee1ad540fa5ec", - "sha256:5def5a485b1cbc998b8f869456c7bde0c0e6d3d0a5ea1f300b5ef57cb4b1ce8f" - ], - "version": "==1.7.9" - }, - "google-auth": { - "hashes": [ - "sha256:0f7c6a64927d34c1a474da92cfc59e552a5d3b940d3266606c6a28b72888b9e4", - "sha256:20705f6803fd2c4d1cc2dcb0df09d4dfcb9a7d51fd59e94a3a28231fd93119ed" - ], - "version": "==1.6.3" - }, - "google-auth-httplib2": { - "hashes": [ - "sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", - "sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08" - ], - "version": "==0.0.3" - }, - "google-cloud-core": { - "hashes": [ - "sha256:7b61a06de4d63780bcf7889cb17f00f5058fdd211ad86c74367408eea37d9f00", - "sha256:8f86399d8399448ccac5890239e6234f120dd619d22c41115ff548a851ec2be2" - ], - "version": "==1.0.2" - }, - "google-cloud-firestore": { - "hashes": [ - "sha256:d60aa73389d67d391f6260a1f2b88e234fda66dc35b7a3e95e54bcd0bd1d163e", - "sha256:e95742e5441f5bc1bc3dabd7277e8b62b96b241a6a9566e549df950778db2cc1" - ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.2.0" - }, - "google-cloud-storage": { - "hashes": [ - "sha256:10b8a708d71b45589e06d0dc2bcc614e1d1c921902df8d22e374af1fb346ab68", - "sha256:4a2a0e2486b1977a4f3e382ed0be118933ecb6a92dc6b2c3d0b56ef8d76ac7a9" - ], - "version": "==1.16.1" - }, - "google-resumable-media": { - "hashes": [ - "sha256:2dae98ee716efe799db3578a7b902fbf5592fc5c77d3c0906fc4ef9b1b930861", - "sha256:3e38923493ca0d7de0ad91c31acfefc393c78586db89364e91cb4f11990e51ba" - ], - "version": "==0.3.2" - }, - "googleapis-common-protos": { - "hashes": [ - "sha256:e61b8ed5e36b976b487c6e7b15f31bb10c7a0ca7bd5c0e837f4afab64b53a0c6" - ], - "version": "==1.6.0" - }, - "grpcio": { - "hashes": [ - "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2", - "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce", - "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb", - "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e", - "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941", - "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e", - "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce", - "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf", - "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f", - "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303", - "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2", - "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf", - "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e", - "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369", - "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87", - "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e", - "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97", - "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2", - "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369", - "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67", - "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174", - "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f", - "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b", - "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e", - "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0", - "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad", - "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa", - "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03", - "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1", - "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348", - "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530", - "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc" - ], - "version": "==1.22.0" - }, - "gunicorn": { - "hashes": [ - "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", - "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" - ], - "index": "pypi", - "version": "==19.9.0" - }, - "httplib2": { - "hashes": [ - "sha256:158fbd0ffbba536829d664bf3f32c4f45df41f8f791663665162dfaf21ffd075", - "sha256:d1146939d270f1f1eb8cbf8f5aa72ff37d897faccca448582bb1e180aeb4c6b2" - ], - "version": "==0.13.0" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "msgpack": { - "hashes": [ - "sha256:26cb40116111c232bc235ce131cc3b4e76549088cb154e66a2eb8ff6fcc907ec", - "sha256:300fd3f2c664a3bf473d6a952f843b4a71454f4c592ed7e74a36b205c1782d28", - "sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c", - "sha256:31f6d645ee5a97d59d3263fab9e6be76f69fa131cddc0d94091a3c8aca30d67a", - "sha256:3ce7ef7ee2546c3903ca8c934d09250531b80c6127e6478781ae31ed835aac4c", - "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972", - "sha256:62bd8e43d204580308d477a157b78d3fee2fb4c15d32578108dc5d89866036c8", - "sha256:70cebfe08fb32f83051971264466eadf183101e335d8107b80002e632f425511", - "sha256:72cb7cf85e9df5251abd7b61a1af1fb77add15f40fa7328e924a9c0b6bc7a533", - "sha256:7c55649965c35eb32c499d17dadfb8f53358b961582846e1bc06f66b9bccc556", - "sha256:86b963a5de11336ec26bc4f839327673c9796b398b9f1fe6bb6150c2a5d00f0f", - "sha256:8c73c9bcdfb526247c5e4f4f6cf581b9bb86b388df82cfcaffde0a6e7bf3b43a", - "sha256:8e68c76c6aff4849089962d25346d6784d38e02baa23ffa513cf46be72e3a540", - "sha256:97ac6b867a8f63debc64f44efdc695109d541ecc361ee2dce2c8884ab37360a1", - "sha256:9d4f546af72aa001241d74a79caec278bcc007b4bcde4099994732e98012c858", - "sha256:a28e69fe5468c9f5251c7e4e7232286d71b7dfadc74f312006ebe984433e9746", - "sha256:fd509d4aa95404ce8d86b4e32ce66d5d706fd6646c205e1c2a715d87078683a2" - ], - "version": "==0.6.1" - }, - "phonenumbers": { - "hashes": [ - "sha256:81757480b3553e9aa8b7442f28fc53e7c8335ef8c99c3b292bcd55b08820aa00", - "sha256:cb1d559b3f63cef4e8521f9ebeb4f41a0320f97463f3b11c15bd7d1d3e0f40db" - ], - "index": "pypi", - "version": "==8.10.14" - }, - "protobuf": { - "hashes": [ - "sha256:03f43eac9d5b651f976e91cf46a25b75e5779d98f0f4114b0abfed83376d75f8", - "sha256:0c94b21e6de01362f91a86b372555d22a60b59708599ca9d5032ae9fdf8e3538", - "sha256:2d2a9f30f61f4063fadd7fb68a2510a6939b43c0d6ceeec5c4704f22225da28e", - "sha256:34a0b05fca061e4abb77dd180209f68d8637115ff319f51e28a6a9382d69853a", - "sha256:358710fd0db25372edcf1150fa691f48376a134a6c69ce29f38f185eea7699e6", - "sha256:41e47198b94c27ba05a08b4a95160656105745c462af574e4bcb0807164065c0", - "sha256:8c61cc8a76e9d381c665aecc5105fa0f1878cf7db8b5cd17202603bcb386d0fc", - "sha256:a6eebc4db759e58fdac02efcd3028b811effac881d8a5bad1996e4e8ee6acb47", - "sha256:a9c12f7c98093da0a46ba76ec40ace725daa1ac4038c41e4b1466afb5c45bb01", - "sha256:cb95068492ba0859b8c9e61fa8ba206a83c64e5d0916fb4543700b2e2b214115", - "sha256:cd98476ce7bb4dcd6a7b101f5eecdc073dafea19f311e36eb8fba1a349346277", - "sha256:ce64cfbea18c535176bdaa10ba740c0fc4c6d998a3f511c17bedb0ae4b3b167c", - "sha256:dcbb59eac73fd454e8f2c5fba9e3d3320fd4707ed6a9d3ea3717924a6f0903ea", - "sha256:dd67f34458ae716029e2a71ede998e9092493b62a519236ca52e3c5202096c87", - "sha256:e3c96056eb5b7284a20e256cb0bf783c8f36ad82a4ae5434a7b7cd02384144a7", - "sha256:f612d584d7a27e2f39e7b17878430a959c1bc09a74ba09db096b468558e5e126", - "sha256:f6de8a7d6122297b81566e5bd4df37fd5d62bec14f8f90ebff8ede1c9726cd0a", - "sha256:fa529d9261682b24c2aaa683667253175c9acebe0a31105394b221090da75832" - ], - "version": "==3.8.0" - }, - "psycopg2": { - "hashes": [ - "sha256:0b9e48a1c1505699a64ac58815ca99104aacace8321e455072cee4f7fe7b2698", - "sha256:0f4c784e1b5a320efb434c66a50b8dd7e30a7dc047e8f45c0a8d2694bfe72781", - "sha256:0fdbaa32c9eb09ef09d425dc154628fca6fa69d2f7c1a33f889abb7e0efb3909", - "sha256:11fbf688d5c953c0a5ba625cc42dea9aeb2321942c7c5ed9341a68f865dc8cb1", - "sha256:19eaac4eb25ab078bd0f28304a0cb08702d120caadfe76bb1e6846ed1f68635e", - "sha256:3232ec1a3bf4dba97fbf9b03ce12e4b6c1d01ea3c85773903a67ced725728232", - "sha256:36f8f9c216fcca048006f6dd60e4d3e6f406afde26cfb99e063f137070139eaf", - "sha256:59c1a0e4f9abe970062ed35d0720935197800a7ef7a62b3a9e3a70588d9ca40b", - "sha256:6506c5ff88750948c28d41852c09c5d2a49f51f28c6d90cbf1b6808e18c64e88", - "sha256:6bc3e68ee16f571681b8c0b6d5c0a77bef3c589012352b3f0cf5520e674e9d01", - "sha256:6dbbd7aabbc861eec6b910522534894d9dbb507d5819bc982032c3ea2e974f51", - "sha256:6e737915de826650d1a5f7ff4ac6cf888a26f021a647390ca7bafdba0e85462b", - "sha256:6ed9b2cfe85abc720e8943c1808eeffd41daa73e18b7c1e1a228b0b91f768ccc", - "sha256:711ec617ba453fdfc66616db2520db3a6d9a891e3bf62ef9aba4c95bb4e61230", - "sha256:844dacdf7530c5c612718cf12bc001f59b2d9329d35b495f1ff25045161aa6af", - "sha256:86b52e146da13c896e50c5a3341a9448151f1092b1a4153e425d1e8b62fec508", - "sha256:985c06c2a0f227131733ae58d6a541a5bc8b665e7305494782bebdb74202b793", - "sha256:a86dfe45f4f9c55b1a2312ff20a59b30da8d39c0e8821d00018372a2a177098f", - "sha256:aa3cd07f7f7e3183b63d48300666f920828a9dbd7d7ec53d450df2c4953687a9", - "sha256:b1964ed645ef8317806d615d9ff006c0dadc09dfc54b99ae67f9ba7a1ec9d5d2", - "sha256:b2abbff9e4141484bb89b96eb8eae186d77bc6d5ffbec6b01783ee5c3c467351", - "sha256:cc33c3a90492e21713260095f02b12bee02b8d1f2c03a221d763ce04fa90e2e9", - "sha256:d7de3bf0986d777807611c36e809b77a13bf1888f5c8db0ebf24b47a52d10726", - "sha256:db5e3c52576cc5b93a959a03ccc3b02cb8f0af1fbbdc80645f7a215f0b864f3a", - "sha256:e168aa795ffbb11379c942cf95bf813c7db9aa55538eb61de8c6815e092416f5", - "sha256:e9ca911f8e2d3117e5241d5fa9aaa991cb22fb0792627eeada47425d706b5ec8", - "sha256:eccf962d41ca46e6326b97c8fe0a6687b58dfc1a5f6540ed071ff1474cea749e", - "sha256:efa19deae6b9e504a74347fe5e25c2cb9343766c489c2ae921b05f37338b18d1", - "sha256:f4b0460a21f784abe17b496f66e74157a6c36116fa86da8bf6aa028b9e8ad5fe", - "sha256:f93d508ca64d924d478fb11e272e09524698f0c581d9032e68958cfbdd41faef" - ], - "index": "pypi", - "version": "==2.7.5" - }, - "pyasn1": { - "hashes": [ - "sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", - "sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e" - ], - "version": "==0.4.5" - }, - "pyasn1-modules": { - "hashes": [ - "sha256:ef721f68f7951fab9b0404d42590f479e30d9005daccb1699b0a51bb4177db96", - "sha256:f309b6c94724aeaf7ca583feb1cc70430e10d7551de5e36edfc1ae6909bcfb3c" - ], - "version": "==0.2.5" - }, - "python-decouple": { - "hashes": [ - "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" - ], - "index": "pypi", - "version": "==3.1" - }, - "pytz": { - "hashes": [ - "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", - "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" - ], - "version": "==2019.1" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "version": "==2.22.0" - }, - "rsa": { - "hashes": [ - "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", - "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" - ], - "version": "==4.0" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "sqlparse": { - "hashes": [ - "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", - "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" - ], - "version": "==0.3.0" - }, - "uritemplate": { - "hashes": [ - "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", - "sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", - "sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d" - ], - "version": "==3.0.0" - }, - "urllib3": { - "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" - ], - "version": "==1.25.3" - }, - "whitenoise": { - "hashes": [ - "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", - "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" - ], - "version": "==4.1.2" - } - }, - "develop": { - "astroid": { - "hashes": [ - "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", - "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" - ], - "version": "==2.2.5" - }, - "autopep8": { - "hashes": [ - "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" - ], - "index": "pypi", - "version": "==1.4.4" - }, - "isort": { - "hashes": [ - "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", - "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" - ], - "version": "==4.3.21" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", - "sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", - "sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", - "sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", - "sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", - "sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", - "sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", - "sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", - "sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", - "sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", - "sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", - "sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", - "sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", - "sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", - "sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", - "sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", - "sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", - "sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1" - ], - "version": "==1.4.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "pycodestyle": { - "hashes": [ - "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", - "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" - ], - "version": "==2.5.0" - }, - "pylint": { - "hashes": [ - "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", - "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" - ], - "index": "pypi", - "version": "==2.3.1" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "typed-ast": { - "hashes": [ - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" - ], - "markers": "implementation_name == 'cpython'", - "version": "==1.4.0" - }, - "wrapt": { - "hashes": [ - "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" - ], - "version": "==1.11.2" - } - } -} From c2fc1135dc443d3af94ba3ef20bd75e94a22aa39 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Mon, 8 Jul 2019 19:07:58 +0300 Subject: [PATCH 07/24] added pipfile.lock --- Pipfile.lock | 512 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..9dbbdf5 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,512 @@ +{ + "_meta": { + "hash": { + "sha256": "9ebca0b7783e49cbff48f1dc1ea9ebca91ab5ec18c07bf39460b02ad3f7b2830" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "babel": { + "hashes": [ + "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", + "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" + ], + "version": "==2.7.0" + }, + "cachecontrol": { + "hashes": [ + "sha256:cef77effdf51b43178f6a2d3b787e3734f98ade253fa3187f3bb7315aaa42ff7" + ], + "version": "==0.12.5" + }, + "cachetools": { + "hashes": [ + "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae", + "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a" + ], + "version": "==3.1.1" + }, + "certifi": { + "hashes": [ + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + ], + "version": "==2019.6.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "dj-database-url": { + "hashes": [ + "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", + "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "django": { + "hashes": [ + "sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", + "sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" + ], + "index": "pypi", + "version": "==2.2.3" + }, + "django-cors-headers": { + "hashes": [ + "sha256:5b80bf0f8d7fc6e2bcb4f40781d5ff3661961bbf1982e52daec77241dea3b890", + "sha256:ebf3e2cf25aa6993b959a8e6a87828ebb3c8fe5bc3ec4a2d6e65f3b8d9b4212c" + ], + "index": "pypi", + "version": "==3.0.2" + }, + "django-extensions": { + "hashes": [ + "sha256:097450a56fcfdef36bb4dd731b113d1b3e9a9de715fc8775e5e84ab3be50dd96", + "sha256:a1799a7eb4cf0f7aa0d111bac79047227b55a74d11741f387708023a012662f9" + ], + "index": "pypi", + "version": "==2.1.9" + }, + "django-heroku": { + "hashes": [ + "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", + "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" + ], + "index": "pypi", + "version": "==0.3.1" + }, + "django-phonenumber-field": { + "hashes": [ + "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e", + "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97" + ], + "index": "pypi", + "version": "==3.0.1" + }, + "djangorestframework": { + "hashes": [ + "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", + "sha256:c12869cfd83c33d579b17b3cb28a2ae7322a53c3ce85580c2a2ebe4e3f56c4fb" + ], + "index": "pypi", + "version": "==3.9.4" + }, + "firebase-admin": { + "hashes": [ + "sha256:3bf83d37161f00ce6cd1f046a6d4ed9de8504618b68b8af4dee5bd27e6f96251" + ], + "index": "pypi", + "version": "==2.17.0" + }, + "google-api-core": { + "extras": [ + "grpc" + ], + "hashes": [ + "sha256:72a1c8966bdbd70a72de32760368aec399fe6a5c2a6675d9476cb9ae27046de7", + "sha256:f45d74aef41e1de49ceadebf382e1291ddcbe431a8b533aff8a1140a35531465" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.13.0" + }, + "google-api-python-client": { + "hashes": [ + "sha256:048da0d68564380ee23b449e5a67d4666af1b3b536d2fb0a02cee1ad540fa5ec", + "sha256:5def5a485b1cbc998b8f869456c7bde0c0e6d3d0a5ea1f300b5ef57cb4b1ce8f" + ], + "version": "==1.7.9" + }, + "google-auth": { + "hashes": [ + "sha256:0f7c6a64927d34c1a474da92cfc59e552a5d3b940d3266606c6a28b72888b9e4", + "sha256:20705f6803fd2c4d1cc2dcb0df09d4dfcb9a7d51fd59e94a3a28231fd93119ed" + ], + "version": "==1.6.3" + }, + "google-auth-httplib2": { + "hashes": [ + "sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", + "sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08" + ], + "version": "==0.0.3" + }, + "google-cloud-core": { + "hashes": [ + "sha256:7b61a06de4d63780bcf7889cb17f00f5058fdd211ad86c74367408eea37d9f00", + "sha256:8f86399d8399448ccac5890239e6234f120dd619d22c41115ff548a851ec2be2" + ], + "version": "==1.0.2" + }, + "google-cloud-firestore": { + "hashes": [ + "sha256:d60aa73389d67d391f6260a1f2b88e234fda66dc35b7a3e95e54bcd0bd1d163e", + "sha256:e95742e5441f5bc1bc3dabd7277e8b62b96b241a6a9566e549df950778db2cc1" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.2.0" + }, + "google-cloud-storage": { + "hashes": [ + "sha256:10b8a708d71b45589e06d0dc2bcc614e1d1c921902df8d22e374af1fb346ab68", + "sha256:4a2a0e2486b1977a4f3e382ed0be118933ecb6a92dc6b2c3d0b56ef8d76ac7a9" + ], + "version": "==1.16.1" + }, + "google-resumable-media": { + "hashes": [ + "sha256:2dae98ee716efe799db3578a7b902fbf5592fc5c77d3c0906fc4ef9b1b930861", + "sha256:3e38923493ca0d7de0ad91c31acfefc393c78586db89364e91cb4f11990e51ba" + ], + "version": "==0.3.2" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:e61b8ed5e36b976b487c6e7b15f31bb10c7a0ca7bd5c0e837f4afab64b53a0c6" + ], + "version": "==1.6.0" + }, + "grpcio": { + "hashes": [ + "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2", + "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce", + "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb", + "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e", + "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941", + "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e", + "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce", + "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf", + "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f", + "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303", + "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2", + "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf", + "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e", + "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369", + "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87", + "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e", + "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97", + "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2", + "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369", + "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67", + "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174", + "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f", + "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b", + "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e", + "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0", + "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad", + "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa", + "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03", + "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1", + "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348", + "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530", + "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc" + ], + "version": "==1.22.0" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, + "httplib2": { + "hashes": [ + "sha256:158fbd0ffbba536829d664bf3f32c4f45df41f8f791663665162dfaf21ffd075", + "sha256:d1146939d270f1f1eb8cbf8f5aa72ff37d897faccca448582bb1e180aeb4c6b2" + ], + "version": "==0.13.0" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "msgpack": { + "hashes": [ + "sha256:26cb40116111c232bc235ce131cc3b4e76549088cb154e66a2eb8ff6fcc907ec", + "sha256:300fd3f2c664a3bf473d6a952f843b4a71454f4c592ed7e74a36b205c1782d28", + "sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c", + "sha256:31f6d645ee5a97d59d3263fab9e6be76f69fa131cddc0d94091a3c8aca30d67a", + "sha256:3ce7ef7ee2546c3903ca8c934d09250531b80c6127e6478781ae31ed835aac4c", + "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972", + "sha256:62bd8e43d204580308d477a157b78d3fee2fb4c15d32578108dc5d89866036c8", + "sha256:70cebfe08fb32f83051971264466eadf183101e335d8107b80002e632f425511", + "sha256:72cb7cf85e9df5251abd7b61a1af1fb77add15f40fa7328e924a9c0b6bc7a533", + "sha256:7c55649965c35eb32c499d17dadfb8f53358b961582846e1bc06f66b9bccc556", + "sha256:86b963a5de11336ec26bc4f839327673c9796b398b9f1fe6bb6150c2a5d00f0f", + "sha256:8c73c9bcdfb526247c5e4f4f6cf581b9bb86b388df82cfcaffde0a6e7bf3b43a", + "sha256:8e68c76c6aff4849089962d25346d6784d38e02baa23ffa513cf46be72e3a540", + "sha256:97ac6b867a8f63debc64f44efdc695109d541ecc361ee2dce2c8884ab37360a1", + "sha256:9d4f546af72aa001241d74a79caec278bcc007b4bcde4099994732e98012c858", + "sha256:a28e69fe5468c9f5251c7e4e7232286d71b7dfadc74f312006ebe984433e9746", + "sha256:fd509d4aa95404ce8d86b4e32ce66d5d706fd6646c205e1c2a715d87078683a2" + ], + "version": "==0.6.1" + }, + "phonenumbers": { + "hashes": [ + "sha256:81757480b3553e9aa8b7442f28fc53e7c8335ef8c99c3b292bcd55b08820aa00", + "sha256:cb1d559b3f63cef4e8521f9ebeb4f41a0320f97463f3b11c15bd7d1d3e0f40db" + ], + "index": "pypi", + "version": "==8.10.14" + }, + "protobuf": { + "hashes": [ + "sha256:03f43eac9d5b651f976e91cf46a25b75e5779d98f0f4114b0abfed83376d75f8", + "sha256:0c94b21e6de01362f91a86b372555d22a60b59708599ca9d5032ae9fdf8e3538", + "sha256:2d2a9f30f61f4063fadd7fb68a2510a6939b43c0d6ceeec5c4704f22225da28e", + "sha256:34a0b05fca061e4abb77dd180209f68d8637115ff319f51e28a6a9382d69853a", + "sha256:358710fd0db25372edcf1150fa691f48376a134a6c69ce29f38f185eea7699e6", + "sha256:41e47198b94c27ba05a08b4a95160656105745c462af574e4bcb0807164065c0", + "sha256:8c61cc8a76e9d381c665aecc5105fa0f1878cf7db8b5cd17202603bcb386d0fc", + "sha256:a6eebc4db759e58fdac02efcd3028b811effac881d8a5bad1996e4e8ee6acb47", + "sha256:a9c12f7c98093da0a46ba76ec40ace725daa1ac4038c41e4b1466afb5c45bb01", + "sha256:cb95068492ba0859b8c9e61fa8ba206a83c64e5d0916fb4543700b2e2b214115", + "sha256:cd98476ce7bb4dcd6a7b101f5eecdc073dafea19f311e36eb8fba1a349346277", + "sha256:ce64cfbea18c535176bdaa10ba740c0fc4c6d998a3f511c17bedb0ae4b3b167c", + "sha256:dcbb59eac73fd454e8f2c5fba9e3d3320fd4707ed6a9d3ea3717924a6f0903ea", + "sha256:dd67f34458ae716029e2a71ede998e9092493b62a519236ca52e3c5202096c87", + "sha256:e3c96056eb5b7284a20e256cb0bf783c8f36ad82a4ae5434a7b7cd02384144a7", + "sha256:f612d584d7a27e2f39e7b17878430a959c1bc09a74ba09db096b468558e5e126", + "sha256:f6de8a7d6122297b81566e5bd4df37fd5d62bec14f8f90ebff8ede1c9726cd0a", + "sha256:fa529d9261682b24c2aaa683667253175c9acebe0a31105394b221090da75832" + ], + "version": "==3.8.0" + }, + "psycopg2": { + "hashes": [ + "sha256:0b9e48a1c1505699a64ac58815ca99104aacace8321e455072cee4f7fe7b2698", + "sha256:0f4c784e1b5a320efb434c66a50b8dd7e30a7dc047e8f45c0a8d2694bfe72781", + "sha256:0fdbaa32c9eb09ef09d425dc154628fca6fa69d2f7c1a33f889abb7e0efb3909", + "sha256:11fbf688d5c953c0a5ba625cc42dea9aeb2321942c7c5ed9341a68f865dc8cb1", + "sha256:19eaac4eb25ab078bd0f28304a0cb08702d120caadfe76bb1e6846ed1f68635e", + "sha256:3232ec1a3bf4dba97fbf9b03ce12e4b6c1d01ea3c85773903a67ced725728232", + "sha256:36f8f9c216fcca048006f6dd60e4d3e6f406afde26cfb99e063f137070139eaf", + "sha256:59c1a0e4f9abe970062ed35d0720935197800a7ef7a62b3a9e3a70588d9ca40b", + "sha256:6506c5ff88750948c28d41852c09c5d2a49f51f28c6d90cbf1b6808e18c64e88", + "sha256:6bc3e68ee16f571681b8c0b6d5c0a77bef3c589012352b3f0cf5520e674e9d01", + "sha256:6dbbd7aabbc861eec6b910522534894d9dbb507d5819bc982032c3ea2e974f51", + "sha256:6e737915de826650d1a5f7ff4ac6cf888a26f021a647390ca7bafdba0e85462b", + "sha256:6ed9b2cfe85abc720e8943c1808eeffd41daa73e18b7c1e1a228b0b91f768ccc", + "sha256:711ec617ba453fdfc66616db2520db3a6d9a891e3bf62ef9aba4c95bb4e61230", + "sha256:844dacdf7530c5c612718cf12bc001f59b2d9329d35b495f1ff25045161aa6af", + "sha256:86b52e146da13c896e50c5a3341a9448151f1092b1a4153e425d1e8b62fec508", + "sha256:985c06c2a0f227131733ae58d6a541a5bc8b665e7305494782bebdb74202b793", + "sha256:a86dfe45f4f9c55b1a2312ff20a59b30da8d39c0e8821d00018372a2a177098f", + "sha256:aa3cd07f7f7e3183b63d48300666f920828a9dbd7d7ec53d450df2c4953687a9", + "sha256:b1964ed645ef8317806d615d9ff006c0dadc09dfc54b99ae67f9ba7a1ec9d5d2", + "sha256:b2abbff9e4141484bb89b96eb8eae186d77bc6d5ffbec6b01783ee5c3c467351", + "sha256:cc33c3a90492e21713260095f02b12bee02b8d1f2c03a221d763ce04fa90e2e9", + "sha256:d7de3bf0986d777807611c36e809b77a13bf1888f5c8db0ebf24b47a52d10726", + "sha256:db5e3c52576cc5b93a959a03ccc3b02cb8f0af1fbbdc80645f7a215f0b864f3a", + "sha256:e168aa795ffbb11379c942cf95bf813c7db9aa55538eb61de8c6815e092416f5", + "sha256:e9ca911f8e2d3117e5241d5fa9aaa991cb22fb0792627eeada47425d706b5ec8", + "sha256:eccf962d41ca46e6326b97c8fe0a6687b58dfc1a5f6540ed071ff1474cea749e", + "sha256:efa19deae6b9e504a74347fe5e25c2cb9343766c489c2ae921b05f37338b18d1", + "sha256:f4b0460a21f784abe17b496f66e74157a6c36116fa86da8bf6aa028b9e8ad5fe", + "sha256:f93d508ca64d924d478fb11e272e09524698f0c581d9032e68958cfbdd41faef" + ], + "index": "pypi", + "version": "==2.7.5" + }, + "pyasn1": { + "hashes": [ + "sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", + "sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e" + ], + "version": "==0.4.5" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:ef721f68f7951fab9b0404d42590f479e30d9005daccb1699b0a51bb4177db96", + "sha256:f309b6c94724aeaf7ca583feb1cc70430e10d7551de5e36edfc1ae6909bcfb3c" + ], + "version": "==0.2.5" + }, + "python-decouple": { + "hashes": [ + "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" + ], + "index": "pypi", + "version": "==3.1" + }, + "pytz": { + "hashes": [ + "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", + "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" + ], + "version": "==2019.1" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "version": "==2.22.0" + }, + "rsa": { + "hashes": [ + "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", + "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" + ], + "version": "==4.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, + "uritemplate": { + "hashes": [ + "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", + "sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", + "sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d" + ], + "version": "==3.0.0" + }, + "urllib3": { + "hashes": [ + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + ], + "version": "==1.25.3" + }, + "whitenoise": { + "hashes": [ + "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", + "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" + ], + "version": "==4.1.2" + } + }, + "develop": { + "astroid": { + "hashes": [ + "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", + "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" + ], + "version": "==2.2.5" + }, + "autopep8": { + "hashes": [ + "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", + "sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", + "sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", + "sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", + "sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", + "sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", + "sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", + "sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", + "sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", + "sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", + "sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", + "sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", + "sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", + "sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", + "sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", + "sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", + "sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", + "sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1" + ], + "version": "==1.4.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "typed-ast": { + "hashes": [ + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "markers": "implementation_name == 'cpython'", + "version": "==1.4.0" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + } + } +} From 76fb0708b9cb79527b070955d4734e35db673b1f Mon Sep 17 00:00:00 2001 From: meshnesh Date: Mon, 8 Jul 2019 19:25:11 +0300 Subject: [PATCH 08/24] fixing failing heroku error --- app/authentication/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/authentication/models.py b/app/authentication/models.py index b23c3ca..5de2d1b 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -79,7 +79,7 @@ def _generate_firebase_token(self): """ Generates a firebase token """ - uid = config('UID') + uid = config('some-uid') token = auth.create_custom_token(uid) return token.decode('utf-8') From a15e6fa10aa493371825add86cdf19b66512d364 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Mon, 8 Jul 2019 20:03:13 +0300 Subject: [PATCH 09/24] fixing failing heroku error --- app/authentication/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/authentication/models.py b/app/authentication/models.py index 5de2d1b..0e08a8b 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -79,7 +79,7 @@ def _generate_firebase_token(self): """ Generates a firebase token """ - uid = config('some-uid') + uid = 'some-uid' token = auth.create_custom_token(uid) return token.decode('utf-8') From 13a3d8ce6e7bfc94999442498dc331653e85f50a Mon Sep 17 00:00:00 2001 From: graycadeau Date: Thu, 11 Jul 2019 09:01:23 +0300 Subject: [PATCH 10/24] firebase-auth --- app/authentication/serializers.py | 15 --------------- app/firebase_auth.py | 8 +------- dscountr/settings.py | 5 ----- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 1c5767b..51cb2fb 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -45,16 +45,6 @@ def create(self, data): email = data.get('email') password = data.get('password') - if email is None: - raise serializers.ValidationError( - 'An email address is required to log in.' - ) - - if password is None: - raise serializers.ValidationError( - 'A password is required to log in.' - ) - user = authenticate(username=email, password=password) if user is None: @@ -62,11 +52,6 @@ def create(self, data): 'A user with this email and password was not found.' ) - if not user.is_active: - raise serializers.ValidationError( - 'This user has been deactivated.' - ) - return { 'email': user.email, 'username': user.username, diff --git a/app/firebase_auth.py b/app/firebase_auth.py index 8fca5a7..7ac20d7 100644 --- a/app/firebase_auth.py +++ b/app/firebase_auth.py @@ -10,14 +10,9 @@ payload = { "type": "service_account", "project_id": config("PROJECT_ID"), - "private_key_id": config("PRIVATE_KEY_ID"), "private_key": private_key, "client_email": config("CLIENT_EMAIL"), - "client_id": config("CLIENT_ID"), - "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hq70h%40dscountr-49c53.iam.gserviceaccount.com", } cred = credentials.Certificate(payload) @@ -32,8 +27,7 @@ def authenticate_credentials(self, id_token): try: token = auth.verify_id_token(id_token) except Exception as e: - raise exceptions.AuthenticationFailed( - "Unable to authenticate. Invalid or expired token") + raise exceptions.AuthenticationFailed() else: email = token.get("email") try: diff --git a/dscountr/settings.py b/dscountr/settings.py index 8f16a67..41d7eb6 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -114,11 +114,6 @@ "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", ), - "DEFAULT_AUTHENTICATION_CLASSES": ( - 'app.firebase_auth.FirebaseTokenAuthentication', - "rest_framework.authentication.BasicAuthentication", - "rest_framework.authentication.SessionAuthentication", - ), } From 4a900b233e95aabb57b495da4c249237250c149e Mon Sep 17 00:00:00 2001 From: graycadeau Date: Thu, 11 Jul 2019 18:46:22 +0300 Subject: [PATCH 11/24] adjust auth --- app/auth_backend.py | 22 ++++++++++ .../migrations/0003_auto_20190711_1054.py | 18 ++++++++ .../migrations/0004_auto_20190711_1539.py | 18 ++++++++ app/authentication/models.py | 17 ++++--- app/authentication/serializers.py | 44 ++++++++----------- app/authentication/urls.py | 1 + app/authentication/views.py | 1 + dscountr/settings.py | 4 ++ 8 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 app/auth_backend.py create mode 100644 app/authentication/migrations/0003_auto_20190711_1054.py create mode 100644 app/authentication/migrations/0004_auto_20190711_1539.py diff --git a/app/auth_backend.py b/app/auth_backend.py new file mode 100644 index 0000000..bdc6d80 --- /dev/null +++ b/app/auth_backend.py @@ -0,0 +1,22 @@ +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth import get_user_model + +User = get_user_model() + + +class PasswordlessAuthBackend(ModelBackend): + """Log in to Django without providing a password. + + """ + + def authenticate(self, username=None): + try: + return User.objects.get(username=username) + except User.DoesNotExist: + return None + + def get_user(self, user_id): + try: + return User.objects.get(pk=user_id) + except User.DoesNotExist: + return None diff --git a/app/authentication/migrations/0003_auto_20190711_1054.py b/app/authentication/migrations/0003_auto_20190711_1054.py new file mode 100644 index 0000000..3ff11c6 --- /dev/null +++ b/app/authentication/migrations/0003_auto_20190711_1054.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-11 10:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0002_auto_20190708_1300'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='password', + field=models.CharField(max_length=128, verbose_name='password'), + ), + ] diff --git a/app/authentication/migrations/0004_auto_20190711_1539.py b/app/authentication/migrations/0004_auto_20190711_1539.py new file mode 100644 index 0000000..3d9748a --- /dev/null +++ b/app/authentication/migrations/0004_auto_20190711_1539.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-11 15:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0003_auto_20190711_1054'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='username', + field=models.CharField(blank=True, db_index=True, max_length=255, null=True, unique=True), + ), + ] diff --git a/app/authentication/models.py b/app/authentication/models.py index 0e08a8b..7af31b5 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -15,13 +15,20 @@ class UserManager(BaseUserManager): def createuser(self, **fields): email = fields.pop('email') - password = fields.get('password') if not email: raise ValueError("Email address is required") email = self.normalize_email(email) user = self.model(email=email, **fields) - user.set_password(password) + user.save(using=self._db) + return user + + def create_staffuser(self, **fields): + """ + Create and return a `User` with superuser (admin) permissions. + """ + user = self.createuser(**fields) + user.is_staff = True user.save(using=self._db) return user @@ -40,12 +47,12 @@ def create_superuser(self, **fields): class User(AbstractBaseUser, PermissionsMixin): - username = models.CharField(db_index=True, max_length=255, unique=True) + username = models.CharField( + db_index=True, max_length=255, unique=True, blank=True, null=True) email = models.EmailField(db_index=True, unique=True) phone_number = PhoneNumberField(db_index=True, unique=True) date_of_birth = models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) - password = models.CharField(max_length=128) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) @@ -53,7 +60,7 @@ class User(AbstractBaseUser, PermissionsMixin): # The `USERNAME_FIELD` property specifies the log in field. USERNAME_FIELD = 'phone_number' - REQUIRED_FIELDS = ['username', 'email', 'date_of_birth', ] + REQUIRED_FIELDS = ['email', 'date_of_birth', ] # the UserManager class should manage objects of this type. objects = UserManager() diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 51cb2fb..756a593 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -1,3 +1,4 @@ +import json from rest_framework import serializers from django.contrib.auth import authenticate from rest_framework.validators import UniqueValidator @@ -5,16 +6,10 @@ from firebase_admin import auth from phonenumber_field.serializerfields import PhoneNumberField from ..user_profile.models import Profile +from ..auth_backend import PasswordlessAuthBackend class RegistrationSerializer(serializers.ModelSerializer): - password = serializers.CharField( - max_length=128, - min_length=8, - write_only=True - ) - - token = serializers.CharField(max_length=255, read_only=True) phone_number = PhoneNumberField( validators=[ UniqueValidator(queryset=User.objects.all(), @@ -23,37 +18,34 @@ class RegistrationSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'email', 'username', 'password', 'token', + fields = ['id', 'email', 'username', 'phone_number', 'date_of_birth', 'gender'] def create(self, validated_data): return User.objects.createuser(**validated_data) -class LoginSerializer(serializers.ModelSerializer): - email = serializers.CharField(max_length=255) - username = serializers.CharField(max_length=255, read_only=True) - password = serializers.CharField( - max_length=128, write_only=True) +class LoginSerializer(serializers.Serializer): + phone_number = PhoneNumberField() + email = serializers.CharField(max_length=255, write_only=True) + password = serializers.CharField(max_length=128, write_only=True) token = serializers.CharField(max_length=255, read_only=True) class Meta: model = User - fields = ['email', 'username', 'password', 'token'] + fields = ['phone_number', 'username', 'token'] - def create(self, data): - email = data.get('email') + def validate(self, data): + print('<><><><><><>', data) + + phone_number = data.get('phone_number') password = data.get('password') + email = data.get('email') - user = authenticate(username=email, password=password) + user = authenticate(username=phone_number, password=password) + print('//////', user.__dir__()) if user is None: - raise serializers.ValidationError( - 'A user with this email and password was not found.' - ) - - return { - 'email': user.email, - 'username': user.username, - 'token': user.token - } + raise serializers.ValidationError() + + return data diff --git a/app/authentication/urls.py b/app/authentication/urls.py index 6879fb0..f6a9497 100644 --- a/app/authentication/urls.py +++ b/app/authentication/urls.py @@ -1,3 +1,4 @@ +from django.conf.urls import include from django.urls import path from rest_framework.routers import DefaultRouter, SimpleRouter from .views import RegistrationViewSet, LoginViewSet diff --git a/app/authentication/views.py b/app/authentication/views.py index 4550dcf..3d395be 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -14,6 +14,7 @@ class RegistrationViewSet(ModelViewSet): class LoginViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = LoginSerializer + queryset = models.User.objects.all() class UserViewSet(ModelViewSet): diff --git a/dscountr/settings.py b/dscountr/settings.py index 41d7eb6..31d45aa 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -89,6 +89,10 @@ 'default': dj_database_url.config() } +# AUTHENTICATION_BACKENDS = ( +# # ... your other backends +# 'app.auth_backend.PasswordlessAuthBackend', +# ) # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators From 062d51bc939c431ad86e0cd7f1fa5ea7781e3240 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Fri, 12 Jul 2019 00:08:24 +0300 Subject: [PATCH 12/24] login --- Pipfile | 2 + Pipfile.lock | 24 ++++++-- app/auth_backend.py | 1 + .../migrations/0005_auto_20190711_1828.py | 18 ++++++ .../migrations/0006_auto_20190711_1933.py | 18 ++++++ app/authentication/models.py | 13 ++++- app/authentication/serializers.py | 20 +------ app/authentication/urls.py | 8 ++- app/authentication/views.py | 19 ++++++- app/filters.py | 55 +++++++++++++++++++ app/user_profile/views.py | 1 - dscountr/settings.py | 41 +++++++------- 12 files changed, 173 insertions(+), 47 deletions(-) create mode 100644 app/authentication/migrations/0005_auto_20190711_1828.py create mode 100644 app/authentication/migrations/0006_auto_20190711_1933.py create mode 100644 app/filters.py diff --git a/Pipfile b/Pipfile index 5a02909..49cde31 100644 --- a/Pipfile +++ b/Pipfile @@ -20,6 +20,8 @@ gunicorn = "==19.9.0" django-heroku = "==0.3.1" django-phonenumber-field = "==3.0.1" phonenumbers = "==8.10.14" +pyjwt = "==1.7.1" +django-filter = "==2.1.0" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 9dbbdf5..8ae6c65 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9ebca0b7783e49cbff48f1dc1ea9ebca91ab5ec18c07bf39460b02ad3f7b2830" + "sha256": "03a01ea2efb22e6a4c2c4e2efb8b3991b3f464364720f3d48384dee1cd13de33" }, "pipfile-spec": 6, "requires": { @@ -82,6 +82,14 @@ "index": "pypi", "version": "==2.1.9" }, + "django-filter": { + "hashes": [ + "sha256:3dafb7d2810790498895c22a1f31b2375795910680ac9c1432821cbedb1e176d", + "sha256:a3014de317bef0cd43075a0f08dfa1d319a7ccc5733c3901fb860da70b0dda68" + ], + "index": "pypi", + "version": "==2.1.0" + }, "django-heroku": { "hashes": [ "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", @@ -154,11 +162,11 @@ }, "google-cloud-firestore": { "hashes": [ - "sha256:d60aa73389d67d391f6260a1f2b88e234fda66dc35b7a3e95e54bcd0bd1d163e", - "sha256:e95742e5441f5bc1bc3dabd7277e8b62b96b241a6a9566e549df950778db2cc1" + "sha256:8889f9f33f62ff5fe7ee4bfbe4f430ad40fb51eb860f65fccfbebecb5a225f2e", + "sha256:fdbc111b7e4ae99f0cd3826464f8394ecc163cb727362905ef14bef5229bf5ba" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.2.0" + "version": "==1.3.0" }, "google-cloud-storage": { "hashes": [ @@ -342,6 +350,14 @@ ], "version": "==0.2.5" }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "index": "pypi", + "version": "==1.7.1" + }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" diff --git a/app/auth_backend.py b/app/auth_backend.py index bdc6d80..11996d6 100644 --- a/app/auth_backend.py +++ b/app/auth_backend.py @@ -1,5 +1,6 @@ from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model +from django.conf import settings User = get_user_model() diff --git a/app/authentication/migrations/0005_auto_20190711_1828.py b/app/authentication/migrations/0005_auto_20190711_1828.py new file mode 100644 index 0000000..a46d6fb --- /dev/null +++ b/app/authentication/migrations/0005_auto_20190711_1828.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-11 18:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0004_auto_20190711_1539'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='password', + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/app/authentication/migrations/0006_auto_20190711_1933.py b/app/authentication/migrations/0006_auto_20190711_1933.py new file mode 100644 index 0000000..490927f --- /dev/null +++ b/app/authentication/migrations/0006_auto_20190711_1933.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-11 19:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0005_auto_20190711_1828'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='password', + field=models.CharField(default='!1xKZFUMiyDaS7Exy0CurdiaQ1Pp88xxHpN0kw3pb', max_length=255), + ), + ] diff --git a/app/authentication/models.py b/app/authentication/models.py index 7af31b5..550dcf5 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -1,3 +1,5 @@ +import jwt +from datetime import datetime, timedelta from django.conf import settings from django.contrib.auth.models import ( AbstractBaseUser, BaseUserManager, PermissionsMixin @@ -53,6 +55,7 @@ class User(AbstractBaseUser, PermissionsMixin): phone_number = PhoneNumberField(db_index=True, unique=True) date_of_birth = models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) + password = models.CharField(max_length=255, default=config('P_WORD')) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) @@ -86,7 +89,11 @@ def _generate_firebase_token(self): """ Generates a firebase token """ - uid = 'some-uid' - token = auth.create_custom_token(uid) - + user_details = {'email': self.email} + token = jwt.encode( + { + 'user_data': user_details, + 'exp': datetime.now() + timedelta(hours=24) + }, settings.SECRET_KEY, algorithm='HS256' + ) return token.decode('utf-8') diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 756a593..53c36a2 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -7,6 +7,7 @@ from phonenumber_field.serializerfields import PhoneNumberField from ..user_profile.models import Profile from ..auth_backend import PasswordlessAuthBackend +from decouple import config class RegistrationSerializer(serializers.ModelSerializer): @@ -27,25 +28,8 @@ def create(self, validated_data): class LoginSerializer(serializers.Serializer): phone_number = PhoneNumberField() - email = serializers.CharField(max_length=255, write_only=True) - password = serializers.CharField(max_length=128, write_only=True) token = serializers.CharField(max_length=255, read_only=True) class Meta: model = User - fields = ['phone_number', 'username', 'token'] - - def validate(self, data): - print('<><><><><><>', data) - - phone_number = data.get('phone_number') - password = data.get('password') - email = data.get('email') - - user = authenticate(username=phone_number, password=password) - print('//////', user.__dir__()) - - if user is None: - raise serializers.ValidationError() - - return data + fields = ['id', 'phone_number', 'token'] diff --git a/app/authentication/urls.py b/app/authentication/urls.py index f6a9497..e490e0d 100644 --- a/app/authentication/urls.py +++ b/app/authentication/urls.py @@ -14,9 +14,15 @@ def __init_(self, trailing_slash='/?'): router = OptionalTrailingSlashRouter() + +# users router.register('users', RegistrationViewSet, 'user') router.register('profiles', UserProfileViewSet, 'profile') router.register('login', LoginViewSet, 'login') -urlpatterns = router.urls +urlpatterns = [ + # path("login/", LoginViewSet.as_view({'post': 'post'}), name="login"), +] + +urlpatterns += router.urls diff --git a/app/authentication/views.py b/app/authentication/views.py index 3d395be..88afad9 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -1,7 +1,11 @@ +from rest_framework import status from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated -from rest_framework.viewsets import ModelViewSet +from rest_framework.viewsets import ModelViewSet, GenericViewSet +from rest_framework.response import Response +from rest_framework.generics import get_object_or_404 from .serializers import (RegistrationSerializer, LoginSerializer) from . import models +from ..filters import UserFilter class RegistrationViewSet(ModelViewSet): @@ -15,6 +19,19 @@ class LoginViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = LoginSerializer queryset = models.User.objects.all() + filterset_class = UserFilter + http_method_names = ['get', ] + + # def get_object(self): + # print(self.kwargs) + # user = self.request.user + # pn = models.User.objects.filter(email=user) + # print(pn) + # queryset = models.User.objects.filter( + # id=2999, phone_number__startswith='+') + # print('<><><><>', queryset) + # obj = get_object_or_404(queryset, id=self.kwargs["pk"]) + # return obj class UserViewSet(ModelViewSet): diff --git a/app/filters.py b/app/filters.py new file mode 100644 index 0000000..f0e567a --- /dev/null +++ b/app/filters.py @@ -0,0 +1,55 @@ +# Standard Library +import functools +import logging +import operator + +# Third-Party Imports +from django.db.models import Q +from django_filters import rest_framework as filters + +# App Imports +from .authentication.models import User + +logger = logging.getLogger(__name__) + +NULL_VALUE = "unspecified" + + +class BaseFilter(filters.FilterSet): + def filter_contains_with_multiple_query_values(self, queryset, name, value): + options = set(value.split(",")) + null_lookup = {} + if NULL_VALUE in options: + options.remove(NULL_VALUE) + null_lookup = {"__".join([name, "isnull"]): True} + if options: + lookup = functools.reduce( + operator.or_, + {Q(**{"__".join([name, "icontains"]): item}) + for item in options}, + ) + else: + lookup = Q(**{}) + + return queryset.filter(Q(lookup | Q(**null_lookup))) + + def filter_exact_with_multiple_query_values(self, queryset, name, value): + options = set(value.split(",")) + null_lookup = {} + if NULL_VALUE in options: + options.remove(NULL_VALUE) + null_lookup = {"__".join([name, "isnull"]): True} + lookup = {"__".join([name, "in"]): options} + return queryset.filter(Q(**lookup) | Q(**null_lookup)) + + +class UserFilter(BaseFilter): + phone_number = filters.CharFilter( + field_name="phone_number", + lookup_expr="iexact", + method="filter_exact_with_multiple_query_values", + ) + + class Meta: + model = User + fields = ["phone_number", ] diff --git a/app/user_profile/views.py b/app/user_profile/views.py index 30bec24..b35531e 100644 --- a/app/user_profile/views.py +++ b/app/user_profile/views.py @@ -1,6 +1,5 @@ from rest_framework.permissions import IsAdminUser, IsAuthenticated, AllowAny from rest_framework.viewsets import ModelViewSet -from rest_framework.generics import get_object_or_404 from .serializers import (UserProfileSerializer,) from . import models from ..firebase_auth import FirebaseTokenAuthentication diff --git a/dscountr/settings.py b/dscountr/settings.py index 31d45aa..5bc40e9 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -46,6 +46,7 @@ 'app.authentication', 'app.user_profile', 'phonenumber_field', + "django_filters", ] MIDDLEWARE = [ @@ -89,35 +90,37 @@ 'default': dj_database_url.config() } -# AUTHENTICATION_BACKENDS = ( -# # ... your other backends -# 'app.auth_backend.PasswordlessAuthBackend', -# ) +AUTHENTICATION_BACKENDS = ( + # ... your other backends + 'app.auth_backend.PasswordlessAuthBackend', + 'django.contrib.auth.backends.ModelBackend', +) # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] +# AUTH_PASSWORD_VALIDATORS = [ +# { +# 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', +# }, +# { +# 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', +# }, +# { +# 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', +# }, +# { +# 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', +# }, +# ] REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( - 'app.firebase_auth.FirebaseTokenAuthentication', + # 'app.firebase_auth.FirebaseTokenAuthentication', "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", ), + "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), } From 41a27f4eee8d355ef2cf6d619570b842d292496d Mon Sep 17 00:00:00 2001 From: Antony Date: Fri, 12 Jul 2019 19:12:14 +0300 Subject: [PATCH 13/24] Delete Pipfile.lock --- Pipfile.lock | 528 --------------------------------------------------- 1 file changed, 528 deletions(-) delete mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 8ae6c65..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,528 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "03a01ea2efb22e6a4c2c4e2efb8b3991b3f464364720f3d48384dee1cd13de33" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "babel": { - "hashes": [ - "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", - "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" - ], - "version": "==2.7.0" - }, - "cachecontrol": { - "hashes": [ - "sha256:cef77effdf51b43178f6a2d3b787e3734f98ade253fa3187f3bb7315aaa42ff7" - ], - "version": "==0.12.5" - }, - "cachetools": { - "hashes": [ - "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae", - "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a" - ], - "version": "==3.1.1" - }, - "certifi": { - "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" - ], - "version": "==2019.6.16" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "dj-database-url": { - "hashes": [ - "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", - "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" - ], - "index": "pypi", - "version": "==0.5.0" - }, - "django": { - "hashes": [ - "sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", - "sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" - ], - "index": "pypi", - "version": "==2.2.3" - }, - "django-cors-headers": { - "hashes": [ - "sha256:5b80bf0f8d7fc6e2bcb4f40781d5ff3661961bbf1982e52daec77241dea3b890", - "sha256:ebf3e2cf25aa6993b959a8e6a87828ebb3c8fe5bc3ec4a2d6e65f3b8d9b4212c" - ], - "index": "pypi", - "version": "==3.0.2" - }, - "django-extensions": { - "hashes": [ - "sha256:097450a56fcfdef36bb4dd731b113d1b3e9a9de715fc8775e5e84ab3be50dd96", - "sha256:a1799a7eb4cf0f7aa0d111bac79047227b55a74d11741f387708023a012662f9" - ], - "index": "pypi", - "version": "==2.1.9" - }, - "django-filter": { - "hashes": [ - "sha256:3dafb7d2810790498895c22a1f31b2375795910680ac9c1432821cbedb1e176d", - "sha256:a3014de317bef0cd43075a0f08dfa1d319a7ccc5733c3901fb860da70b0dda68" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "django-heroku": { - "hashes": [ - "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", - "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" - ], - "index": "pypi", - "version": "==0.3.1" - }, - "django-phonenumber-field": { - "hashes": [ - "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e", - "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97" - ], - "index": "pypi", - "version": "==3.0.1" - }, - "djangorestframework": { - "hashes": [ - "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", - "sha256:c12869cfd83c33d579b17b3cb28a2ae7322a53c3ce85580c2a2ebe4e3f56c4fb" - ], - "index": "pypi", - "version": "==3.9.4" - }, - "firebase-admin": { - "hashes": [ - "sha256:3bf83d37161f00ce6cd1f046a6d4ed9de8504618b68b8af4dee5bd27e6f96251" - ], - "index": "pypi", - "version": "==2.17.0" - }, - "google-api-core": { - "extras": [ - "grpc" - ], - "hashes": [ - "sha256:72a1c8966bdbd70a72de32760368aec399fe6a5c2a6675d9476cb9ae27046de7", - "sha256:f45d74aef41e1de49ceadebf382e1291ddcbe431a8b533aff8a1140a35531465" - ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.13.0" - }, - "google-api-python-client": { - "hashes": [ - "sha256:048da0d68564380ee23b449e5a67d4666af1b3b536d2fb0a02cee1ad540fa5ec", - "sha256:5def5a485b1cbc998b8f869456c7bde0c0e6d3d0a5ea1f300b5ef57cb4b1ce8f" - ], - "version": "==1.7.9" - }, - "google-auth": { - "hashes": [ - "sha256:0f7c6a64927d34c1a474da92cfc59e552a5d3b940d3266606c6a28b72888b9e4", - "sha256:20705f6803fd2c4d1cc2dcb0df09d4dfcb9a7d51fd59e94a3a28231fd93119ed" - ], - "version": "==1.6.3" - }, - "google-auth-httplib2": { - "hashes": [ - "sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", - "sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08" - ], - "version": "==0.0.3" - }, - "google-cloud-core": { - "hashes": [ - "sha256:7b61a06de4d63780bcf7889cb17f00f5058fdd211ad86c74367408eea37d9f00", - "sha256:8f86399d8399448ccac5890239e6234f120dd619d22c41115ff548a851ec2be2" - ], - "version": "==1.0.2" - }, - "google-cloud-firestore": { - "hashes": [ - "sha256:8889f9f33f62ff5fe7ee4bfbe4f430ad40fb51eb860f65fccfbebecb5a225f2e", - "sha256:fdbc111b7e4ae99f0cd3826464f8394ecc163cb727362905ef14bef5229bf5ba" - ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.3.0" - }, - "google-cloud-storage": { - "hashes": [ - "sha256:10b8a708d71b45589e06d0dc2bcc614e1d1c921902df8d22e374af1fb346ab68", - "sha256:4a2a0e2486b1977a4f3e382ed0be118933ecb6a92dc6b2c3d0b56ef8d76ac7a9" - ], - "version": "==1.16.1" - }, - "google-resumable-media": { - "hashes": [ - "sha256:2dae98ee716efe799db3578a7b902fbf5592fc5c77d3c0906fc4ef9b1b930861", - "sha256:3e38923493ca0d7de0ad91c31acfefc393c78586db89364e91cb4f11990e51ba" - ], - "version": "==0.3.2" - }, - "googleapis-common-protos": { - "hashes": [ - "sha256:e61b8ed5e36b976b487c6e7b15f31bb10c7a0ca7bd5c0e837f4afab64b53a0c6" - ], - "version": "==1.6.0" - }, - "grpcio": { - "hashes": [ - "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2", - "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce", - "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb", - "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e", - "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941", - "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e", - "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce", - "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf", - "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f", - "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303", - "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2", - "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf", - "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e", - "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369", - "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87", - "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e", - "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97", - "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2", - "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369", - "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67", - "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174", - "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f", - "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b", - "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e", - "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0", - "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad", - "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa", - "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03", - "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1", - "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348", - "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530", - "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc" - ], - "version": "==1.22.0" - }, - "gunicorn": { - "hashes": [ - "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", - "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" - ], - "index": "pypi", - "version": "==19.9.0" - }, - "httplib2": { - "hashes": [ - "sha256:158fbd0ffbba536829d664bf3f32c4f45df41f8f791663665162dfaf21ffd075", - "sha256:d1146939d270f1f1eb8cbf8f5aa72ff37d897faccca448582bb1e180aeb4c6b2" - ], - "version": "==0.13.0" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "msgpack": { - "hashes": [ - "sha256:26cb40116111c232bc235ce131cc3b4e76549088cb154e66a2eb8ff6fcc907ec", - "sha256:300fd3f2c664a3bf473d6a952f843b4a71454f4c592ed7e74a36b205c1782d28", - "sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c", - "sha256:31f6d645ee5a97d59d3263fab9e6be76f69fa131cddc0d94091a3c8aca30d67a", - "sha256:3ce7ef7ee2546c3903ca8c934d09250531b80c6127e6478781ae31ed835aac4c", - "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972", - "sha256:62bd8e43d204580308d477a157b78d3fee2fb4c15d32578108dc5d89866036c8", - "sha256:70cebfe08fb32f83051971264466eadf183101e335d8107b80002e632f425511", - "sha256:72cb7cf85e9df5251abd7b61a1af1fb77add15f40fa7328e924a9c0b6bc7a533", - "sha256:7c55649965c35eb32c499d17dadfb8f53358b961582846e1bc06f66b9bccc556", - "sha256:86b963a5de11336ec26bc4f839327673c9796b398b9f1fe6bb6150c2a5d00f0f", - "sha256:8c73c9bcdfb526247c5e4f4f6cf581b9bb86b388df82cfcaffde0a6e7bf3b43a", - "sha256:8e68c76c6aff4849089962d25346d6784d38e02baa23ffa513cf46be72e3a540", - "sha256:97ac6b867a8f63debc64f44efdc695109d541ecc361ee2dce2c8884ab37360a1", - "sha256:9d4f546af72aa001241d74a79caec278bcc007b4bcde4099994732e98012c858", - "sha256:a28e69fe5468c9f5251c7e4e7232286d71b7dfadc74f312006ebe984433e9746", - "sha256:fd509d4aa95404ce8d86b4e32ce66d5d706fd6646c205e1c2a715d87078683a2" - ], - "version": "==0.6.1" - }, - "phonenumbers": { - "hashes": [ - "sha256:81757480b3553e9aa8b7442f28fc53e7c8335ef8c99c3b292bcd55b08820aa00", - "sha256:cb1d559b3f63cef4e8521f9ebeb4f41a0320f97463f3b11c15bd7d1d3e0f40db" - ], - "index": "pypi", - "version": "==8.10.14" - }, - "protobuf": { - "hashes": [ - "sha256:03f43eac9d5b651f976e91cf46a25b75e5779d98f0f4114b0abfed83376d75f8", - "sha256:0c94b21e6de01362f91a86b372555d22a60b59708599ca9d5032ae9fdf8e3538", - "sha256:2d2a9f30f61f4063fadd7fb68a2510a6939b43c0d6ceeec5c4704f22225da28e", - "sha256:34a0b05fca061e4abb77dd180209f68d8637115ff319f51e28a6a9382d69853a", - "sha256:358710fd0db25372edcf1150fa691f48376a134a6c69ce29f38f185eea7699e6", - "sha256:41e47198b94c27ba05a08b4a95160656105745c462af574e4bcb0807164065c0", - "sha256:8c61cc8a76e9d381c665aecc5105fa0f1878cf7db8b5cd17202603bcb386d0fc", - "sha256:a6eebc4db759e58fdac02efcd3028b811effac881d8a5bad1996e4e8ee6acb47", - "sha256:a9c12f7c98093da0a46ba76ec40ace725daa1ac4038c41e4b1466afb5c45bb01", - "sha256:cb95068492ba0859b8c9e61fa8ba206a83c64e5d0916fb4543700b2e2b214115", - "sha256:cd98476ce7bb4dcd6a7b101f5eecdc073dafea19f311e36eb8fba1a349346277", - "sha256:ce64cfbea18c535176bdaa10ba740c0fc4c6d998a3f511c17bedb0ae4b3b167c", - "sha256:dcbb59eac73fd454e8f2c5fba9e3d3320fd4707ed6a9d3ea3717924a6f0903ea", - "sha256:dd67f34458ae716029e2a71ede998e9092493b62a519236ca52e3c5202096c87", - "sha256:e3c96056eb5b7284a20e256cb0bf783c8f36ad82a4ae5434a7b7cd02384144a7", - "sha256:f612d584d7a27e2f39e7b17878430a959c1bc09a74ba09db096b468558e5e126", - "sha256:f6de8a7d6122297b81566e5bd4df37fd5d62bec14f8f90ebff8ede1c9726cd0a", - "sha256:fa529d9261682b24c2aaa683667253175c9acebe0a31105394b221090da75832" - ], - "version": "==3.8.0" - }, - "psycopg2": { - "hashes": [ - "sha256:0b9e48a1c1505699a64ac58815ca99104aacace8321e455072cee4f7fe7b2698", - "sha256:0f4c784e1b5a320efb434c66a50b8dd7e30a7dc047e8f45c0a8d2694bfe72781", - "sha256:0fdbaa32c9eb09ef09d425dc154628fca6fa69d2f7c1a33f889abb7e0efb3909", - "sha256:11fbf688d5c953c0a5ba625cc42dea9aeb2321942c7c5ed9341a68f865dc8cb1", - "sha256:19eaac4eb25ab078bd0f28304a0cb08702d120caadfe76bb1e6846ed1f68635e", - "sha256:3232ec1a3bf4dba97fbf9b03ce12e4b6c1d01ea3c85773903a67ced725728232", - "sha256:36f8f9c216fcca048006f6dd60e4d3e6f406afde26cfb99e063f137070139eaf", - "sha256:59c1a0e4f9abe970062ed35d0720935197800a7ef7a62b3a9e3a70588d9ca40b", - "sha256:6506c5ff88750948c28d41852c09c5d2a49f51f28c6d90cbf1b6808e18c64e88", - "sha256:6bc3e68ee16f571681b8c0b6d5c0a77bef3c589012352b3f0cf5520e674e9d01", - "sha256:6dbbd7aabbc861eec6b910522534894d9dbb507d5819bc982032c3ea2e974f51", - "sha256:6e737915de826650d1a5f7ff4ac6cf888a26f021a647390ca7bafdba0e85462b", - "sha256:6ed9b2cfe85abc720e8943c1808eeffd41daa73e18b7c1e1a228b0b91f768ccc", - "sha256:711ec617ba453fdfc66616db2520db3a6d9a891e3bf62ef9aba4c95bb4e61230", - "sha256:844dacdf7530c5c612718cf12bc001f59b2d9329d35b495f1ff25045161aa6af", - "sha256:86b52e146da13c896e50c5a3341a9448151f1092b1a4153e425d1e8b62fec508", - "sha256:985c06c2a0f227131733ae58d6a541a5bc8b665e7305494782bebdb74202b793", - "sha256:a86dfe45f4f9c55b1a2312ff20a59b30da8d39c0e8821d00018372a2a177098f", - "sha256:aa3cd07f7f7e3183b63d48300666f920828a9dbd7d7ec53d450df2c4953687a9", - "sha256:b1964ed645ef8317806d615d9ff006c0dadc09dfc54b99ae67f9ba7a1ec9d5d2", - "sha256:b2abbff9e4141484bb89b96eb8eae186d77bc6d5ffbec6b01783ee5c3c467351", - "sha256:cc33c3a90492e21713260095f02b12bee02b8d1f2c03a221d763ce04fa90e2e9", - "sha256:d7de3bf0986d777807611c36e809b77a13bf1888f5c8db0ebf24b47a52d10726", - "sha256:db5e3c52576cc5b93a959a03ccc3b02cb8f0af1fbbdc80645f7a215f0b864f3a", - "sha256:e168aa795ffbb11379c942cf95bf813c7db9aa55538eb61de8c6815e092416f5", - "sha256:e9ca911f8e2d3117e5241d5fa9aaa991cb22fb0792627eeada47425d706b5ec8", - "sha256:eccf962d41ca46e6326b97c8fe0a6687b58dfc1a5f6540ed071ff1474cea749e", - "sha256:efa19deae6b9e504a74347fe5e25c2cb9343766c489c2ae921b05f37338b18d1", - "sha256:f4b0460a21f784abe17b496f66e74157a6c36116fa86da8bf6aa028b9e8ad5fe", - "sha256:f93d508ca64d924d478fb11e272e09524698f0c581d9032e68958cfbdd41faef" - ], - "index": "pypi", - "version": "==2.7.5" - }, - "pyasn1": { - "hashes": [ - "sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", - "sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e" - ], - "version": "==0.4.5" - }, - "pyasn1-modules": { - "hashes": [ - "sha256:ef721f68f7951fab9b0404d42590f479e30d9005daccb1699b0a51bb4177db96", - "sha256:f309b6c94724aeaf7ca583feb1cc70430e10d7551de5e36edfc1ae6909bcfb3c" - ], - "version": "==0.2.5" - }, - "pyjwt": { - "hashes": [ - "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", - "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" - ], - "index": "pypi", - "version": "==1.7.1" - }, - "python-decouple": { - "hashes": [ - "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" - ], - "index": "pypi", - "version": "==3.1" - }, - "pytz": { - "hashes": [ - "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", - "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" - ], - "version": "==2019.1" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "version": "==2.22.0" - }, - "rsa": { - "hashes": [ - "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", - "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" - ], - "version": "==4.0" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "sqlparse": { - "hashes": [ - "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", - "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" - ], - "version": "==0.3.0" - }, - "uritemplate": { - "hashes": [ - "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", - "sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", - "sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d" - ], - "version": "==3.0.0" - }, - "urllib3": { - "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" - ], - "version": "==1.25.3" - }, - "whitenoise": { - "hashes": [ - "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", - "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" - ], - "version": "==4.1.2" - } - }, - "develop": { - "astroid": { - "hashes": [ - "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", - "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" - ], - "version": "==2.2.5" - }, - "autopep8": { - "hashes": [ - "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" - ], - "index": "pypi", - "version": "==1.4.4" - }, - "isort": { - "hashes": [ - "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", - "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" - ], - "version": "==4.3.21" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", - "sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", - "sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", - "sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", - "sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", - "sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", - "sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", - "sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", - "sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", - "sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", - "sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", - "sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", - "sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", - "sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", - "sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", - "sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", - "sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", - "sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1" - ], - "version": "==1.4.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "pycodestyle": { - "hashes": [ - "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", - "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" - ], - "version": "==2.5.0" - }, - "pylint": { - "hashes": [ - "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", - "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" - ], - "index": "pypi", - "version": "==2.3.1" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "typed-ast": { - "hashes": [ - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" - ], - "markers": "implementation_name == 'cpython'", - "version": "==1.4.0" - }, - "wrapt": { - "hashes": [ - "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" - ], - "version": "==1.11.2" - } - } -} From 4133062f8515c6c076fae43ab2d79e1f028543c0 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Fri, 12 Jul 2019 19:16:06 +0300 Subject: [PATCH 14/24] updating Pipfile.lock --- Pipfile.lock | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..7d146d8 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,528 @@ +{ + "_meta": { + "hash": { + "sha256": "8598a500a7165a35194927dac2119289b3187a403bd9cba5e9bdaf140678cec8" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "babel": { + "hashes": [ + "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", + "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" + ], + "version": "==2.7.0" + }, + "cachecontrol": { + "hashes": [ + "sha256:cef77effdf51b43178f6a2d3b787e3734f98ade253fa3187f3bb7315aaa42ff7" + ], + "version": "==0.12.5" + }, + "cachetools": { + "hashes": [ + "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae", + "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a" + ], + "version": "==3.1.1" + }, + "certifi": { + "hashes": [ + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + ], + "version": "==2019.6.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "dj-database-url": { + "hashes": [ + "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", + "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "django": { + "hashes": [ + "sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", + "sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" + ], + "index": "pypi", + "version": "==2.2.3" + }, + "django-cors-headers": { + "hashes": [ + "sha256:5b80bf0f8d7fc6e2bcb4f40781d5ff3661961bbf1982e52daec77241dea3b890", + "sha256:ebf3e2cf25aa6993b959a8e6a87828ebb3c8fe5bc3ec4a2d6e65f3b8d9b4212c" + ], + "index": "pypi", + "version": "==3.0.2" + }, + "django-extensions": { + "hashes": [ + "sha256:097450a56fcfdef36bb4dd731b113d1b3e9a9de715fc8775e5e84ab3be50dd96", + "sha256:a1799a7eb4cf0f7aa0d111bac79047227b55a74d11741f387708023a012662f9" + ], + "index": "pypi", + "version": "==2.1.9" + }, + "django-filter": { + "hashes": [ + "sha256:3dafb7d2810790498895c22a1f31b2375795910680ac9c1432821cbedb1e176d", + "sha256:a3014de317bef0cd43075a0f08dfa1d319a7ccc5733c3901fb860da70b0dda68" + ], + "index": "pypi", + "version": "==2.1.0" + }, + "django-heroku": { + "hashes": [ + "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", + "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" + ], + "index": "pypi", + "version": "==0.3.1" + }, + "django-phonenumber-field": { + "hashes": [ + "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e", + "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97" + ], + "index": "pypi", + "version": "==3.0.1" + }, + "djangorestframework": { + "hashes": [ + "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", + "sha256:c12869cfd83c33d579b17b3cb28a2ae7322a53c3ce85580c2a2ebe4e3f56c4fb" + ], + "index": "pypi", + "version": "==3.9.4" + }, + "firebase-admin": { + "hashes": [ + "sha256:3bf83d37161f00ce6cd1f046a6d4ed9de8504618b68b8af4dee5bd27e6f96251" + ], + "index": "pypi", + "version": "==2.17.0" + }, + "google-api-core": { + "extras": [ + "grpc" + ], + "hashes": [ + "sha256:72a1c8966bdbd70a72de32760368aec399fe6a5c2a6675d9476cb9ae27046de7", + "sha256:f45d74aef41e1de49ceadebf382e1291ddcbe431a8b533aff8a1140a35531465" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.13.0" + }, + "google-api-python-client": { + "hashes": [ + "sha256:048da0d68564380ee23b449e5a67d4666af1b3b536d2fb0a02cee1ad540fa5ec", + "sha256:5def5a485b1cbc998b8f869456c7bde0c0e6d3d0a5ea1f300b5ef57cb4b1ce8f" + ], + "version": "==1.7.9" + }, + "google-auth": { + "hashes": [ + "sha256:0f7c6a64927d34c1a474da92cfc59e552a5d3b940d3266606c6a28b72888b9e4", + "sha256:20705f6803fd2c4d1cc2dcb0df09d4dfcb9a7d51fd59e94a3a28231fd93119ed" + ], + "version": "==1.6.3" + }, + "google-auth-httplib2": { + "hashes": [ + "sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", + "sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08" + ], + "version": "==0.0.3" + }, + "google-cloud-core": { + "hashes": [ + "sha256:7b61a06de4d63780bcf7889cb17f00f5058fdd211ad86c74367408eea37d9f00", + "sha256:8f86399d8399448ccac5890239e6234f120dd619d22c41115ff548a851ec2be2" + ], + "version": "==1.0.2" + }, + "google-cloud-firestore": { + "hashes": [ + "sha256:8889f9f33f62ff5fe7ee4bfbe4f430ad40fb51eb860f65fccfbebecb5a225f2e", + "sha256:fdbc111b7e4ae99f0cd3826464f8394ecc163cb727362905ef14bef5229bf5ba" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.3.0" + }, + "google-cloud-storage": { + "hashes": [ + "sha256:10b8a708d71b45589e06d0dc2bcc614e1d1c921902df8d22e374af1fb346ab68", + "sha256:4a2a0e2486b1977a4f3e382ed0be118933ecb6a92dc6b2c3d0b56ef8d76ac7a9" + ], + "version": "==1.16.1" + }, + "google-resumable-media": { + "hashes": [ + "sha256:2dae98ee716efe799db3578a7b902fbf5592fc5c77d3c0906fc4ef9b1b930861", + "sha256:3e38923493ca0d7de0ad91c31acfefc393c78586db89364e91cb4f11990e51ba" + ], + "version": "==0.3.2" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:e61b8ed5e36b976b487c6e7b15f31bb10c7a0ca7bd5c0e837f4afab64b53a0c6" + ], + "version": "==1.6.0" + }, + "grpcio": { + "hashes": [ + "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2", + "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce", + "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb", + "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e", + "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941", + "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e", + "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce", + "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf", + "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f", + "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303", + "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2", + "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf", + "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e", + "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369", + "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87", + "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e", + "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97", + "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2", + "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369", + "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67", + "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174", + "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f", + "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b", + "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e", + "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0", + "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad", + "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa", + "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03", + "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1", + "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348", + "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530", + "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc" + ], + "version": "==1.22.0" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, + "httplib2": { + "hashes": [ + "sha256:158fbd0ffbba536829d664bf3f32c4f45df41f8f791663665162dfaf21ffd075", + "sha256:d1146939d270f1f1eb8cbf8f5aa72ff37d897faccca448582bb1e180aeb4c6b2" + ], + "version": "==0.13.0" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "msgpack": { + "hashes": [ + "sha256:26cb40116111c232bc235ce131cc3b4e76549088cb154e66a2eb8ff6fcc907ec", + "sha256:300fd3f2c664a3bf473d6a952f843b4a71454f4c592ed7e74a36b205c1782d28", + "sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c", + "sha256:31f6d645ee5a97d59d3263fab9e6be76f69fa131cddc0d94091a3c8aca30d67a", + "sha256:3ce7ef7ee2546c3903ca8c934d09250531b80c6127e6478781ae31ed835aac4c", + "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972", + "sha256:62bd8e43d204580308d477a157b78d3fee2fb4c15d32578108dc5d89866036c8", + "sha256:70cebfe08fb32f83051971264466eadf183101e335d8107b80002e632f425511", + "sha256:72cb7cf85e9df5251abd7b61a1af1fb77add15f40fa7328e924a9c0b6bc7a533", + "sha256:7c55649965c35eb32c499d17dadfb8f53358b961582846e1bc06f66b9bccc556", + "sha256:86b963a5de11336ec26bc4f839327673c9796b398b9f1fe6bb6150c2a5d00f0f", + "sha256:8c73c9bcdfb526247c5e4f4f6cf581b9bb86b388df82cfcaffde0a6e7bf3b43a", + "sha256:8e68c76c6aff4849089962d25346d6784d38e02baa23ffa513cf46be72e3a540", + "sha256:97ac6b867a8f63debc64f44efdc695109d541ecc361ee2dce2c8884ab37360a1", + "sha256:9d4f546af72aa001241d74a79caec278bcc007b4bcde4099994732e98012c858", + "sha256:a28e69fe5468c9f5251c7e4e7232286d71b7dfadc74f312006ebe984433e9746", + "sha256:fd509d4aa95404ce8d86b4e32ce66d5d706fd6646c205e1c2a715d87078683a2" + ], + "version": "==0.6.1" + }, + "phonenumbers": { + "hashes": [ + "sha256:81757480b3553e9aa8b7442f28fc53e7c8335ef8c99c3b292bcd55b08820aa00", + "sha256:cb1d559b3f63cef4e8521f9ebeb4f41a0320f97463f3b11c15bd7d1d3e0f40db" + ], + "index": "pypi", + "version": "==8.10.14" + }, + "protobuf": { + "hashes": [ + "sha256:05c36022fef3c7d3562ac22402965c0c2b9fe8421f459bb377323598996e407f", + "sha256:139b7eadcca0a861d60b523cb37d9475505e0dfb07972436b15407c2b968d87e", + "sha256:15f683006cb77fb849b1f561e509b03dd2b7dcc749086b8dd1831090d0ba4740", + "sha256:2ad566b7b7cdd8717c7af1825e19f09e8fef2787b77fcb979588944657679604", + "sha256:35cfcf97642ef62108e10a9431c77733ec7eaab8e32fe4653de20403429907cb", + "sha256:387822859ecdd012fdc25ec879f7f487da6e1d5b1ae6115e227e6be208836f71", + "sha256:4df14cbe1e7134afcfdbb9f058949e31c466de27d9b2f7fb4da9e0b67231b538", + "sha256:586c4ca37a7146d4822c700059f150ac3445ce0aef6f3ea258640838bb892dc2", + "sha256:58b11e530e954d29ab3180c48dc558a409f705bf16739fd4e0d3e07924ad7add", + "sha256:63c8c98ccb8c95f41c18fb829aeeab21c6249adee4ed75354125bdc44488f30e", + "sha256:72edcbacd0c73eef507d2ff1af99a6c27df18e66a3ff4351e401182e4de62b03", + "sha256:83dc8a561b3b954fd7002c690bb83278b8d1742a1e28abba9aaef28b0c8b437d", + "sha256:913171ecc84c2726b86574e40549a0ea619d569657c5a5ff782a3be7d81401a5", + "sha256:aabb7c741d3416671c3e6fe7c52970a226e6a8274417a97d7d795f953fadef36", + "sha256:b3452bbda12b1cbe2187d416779de07b2ab4c497d83a050e43c344778763721d", + "sha256:c5d5b8d4a9212338297fa1fa44589f69b470c0ba1d38168b432d577176b386a8", + "sha256:d86ee389c2c4fc3cebabb8ce83a8e97b6b3b5dc727b7419c1ccdc7b6e545a233", + "sha256:f2db8c754de788ab8be5e108e1e967c774c0942342b4f8aaaf14063889a6cfdc" + ], + "version": "==3.9.0" + }, + "psycopg2": { + "hashes": [ + "sha256:0b9e48a1c1505699a64ac58815ca99104aacace8321e455072cee4f7fe7b2698", + "sha256:0f4c784e1b5a320efb434c66a50b8dd7e30a7dc047e8f45c0a8d2694bfe72781", + "sha256:0fdbaa32c9eb09ef09d425dc154628fca6fa69d2f7c1a33f889abb7e0efb3909", + "sha256:11fbf688d5c953c0a5ba625cc42dea9aeb2321942c7c5ed9341a68f865dc8cb1", + "sha256:19eaac4eb25ab078bd0f28304a0cb08702d120caadfe76bb1e6846ed1f68635e", + "sha256:3232ec1a3bf4dba97fbf9b03ce12e4b6c1d01ea3c85773903a67ced725728232", + "sha256:36f8f9c216fcca048006f6dd60e4d3e6f406afde26cfb99e063f137070139eaf", + "sha256:59c1a0e4f9abe970062ed35d0720935197800a7ef7a62b3a9e3a70588d9ca40b", + "sha256:6506c5ff88750948c28d41852c09c5d2a49f51f28c6d90cbf1b6808e18c64e88", + "sha256:6bc3e68ee16f571681b8c0b6d5c0a77bef3c589012352b3f0cf5520e674e9d01", + "sha256:6dbbd7aabbc861eec6b910522534894d9dbb507d5819bc982032c3ea2e974f51", + "sha256:6e737915de826650d1a5f7ff4ac6cf888a26f021a647390ca7bafdba0e85462b", + "sha256:6ed9b2cfe85abc720e8943c1808eeffd41daa73e18b7c1e1a228b0b91f768ccc", + "sha256:711ec617ba453fdfc66616db2520db3a6d9a891e3bf62ef9aba4c95bb4e61230", + "sha256:844dacdf7530c5c612718cf12bc001f59b2d9329d35b495f1ff25045161aa6af", + "sha256:86b52e146da13c896e50c5a3341a9448151f1092b1a4153e425d1e8b62fec508", + "sha256:985c06c2a0f227131733ae58d6a541a5bc8b665e7305494782bebdb74202b793", + "sha256:a86dfe45f4f9c55b1a2312ff20a59b30da8d39c0e8821d00018372a2a177098f", + "sha256:aa3cd07f7f7e3183b63d48300666f920828a9dbd7d7ec53d450df2c4953687a9", + "sha256:b1964ed645ef8317806d615d9ff006c0dadc09dfc54b99ae67f9ba7a1ec9d5d2", + "sha256:b2abbff9e4141484bb89b96eb8eae186d77bc6d5ffbec6b01783ee5c3c467351", + "sha256:cc33c3a90492e21713260095f02b12bee02b8d1f2c03a221d763ce04fa90e2e9", + "sha256:d7de3bf0986d777807611c36e809b77a13bf1888f5c8db0ebf24b47a52d10726", + "sha256:db5e3c52576cc5b93a959a03ccc3b02cb8f0af1fbbdc80645f7a215f0b864f3a", + "sha256:e168aa795ffbb11379c942cf95bf813c7db9aa55538eb61de8c6815e092416f5", + "sha256:e9ca911f8e2d3117e5241d5fa9aaa991cb22fb0792627eeada47425d706b5ec8", + "sha256:eccf962d41ca46e6326b97c8fe0a6687b58dfc1a5f6540ed071ff1474cea749e", + "sha256:efa19deae6b9e504a74347fe5e25c2cb9343766c489c2ae921b05f37338b18d1", + "sha256:f4b0460a21f784abe17b496f66e74157a6c36116fa86da8bf6aa028b9e8ad5fe", + "sha256:f93d508ca64d924d478fb11e272e09524698f0c581d9032e68958cfbdd41faef" + ], + "index": "pypi", + "version": "==2.7.5" + }, + "pyasn1": { + "hashes": [ + "sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", + "sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e" + ], + "version": "==0.4.5" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:ef721f68f7951fab9b0404d42590f479e30d9005daccb1699b0a51bb4177db96", + "sha256:f309b6c94724aeaf7ca583feb1cc70430e10d7551de5e36edfc1ae6909bcfb3c" + ], + "version": "==0.2.5" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "index": "pypi", + "version": "==1.7.1" + }, + "python-decouple": { + "hashes": [ + "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" + ], + "index": "pypi", + "version": "==3.1" + }, + "pytz": { + "hashes": [ + "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", + "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" + ], + "version": "==2019.1" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "version": "==2.22.0" + }, + "rsa": { + "hashes": [ + "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", + "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" + ], + "version": "==4.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, + "uritemplate": { + "hashes": [ + "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", + "sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", + "sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d" + ], + "version": "==3.0.0" + }, + "urllib3": { + "hashes": [ + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + ], + "version": "==1.25.3" + }, + "whitenoise": { + "hashes": [ + "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", + "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" + ], + "version": "==4.1.2" + } + }, + "develop": { + "astroid": { + "hashes": [ + "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", + "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" + ], + "version": "==2.2.5" + }, + "autopep8": { + "hashes": [ + "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", + "sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", + "sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", + "sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", + "sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", + "sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", + "sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", + "sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", + "sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", + "sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", + "sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", + "sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", + "sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", + "sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", + "sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", + "sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", + "sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", + "sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1" + ], + "version": "==1.4.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "typed-ast": { + "hashes": [ + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "markers": "implementation_name == 'cpython'", + "version": "==1.4.0" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + } + } +} From 9db86961e251117d963767adc36bed8229165a78 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Sat, 13 Jul 2019 21:34:51 +0300 Subject: [PATCH 15/24] Implement User login with get request --- app/authentication/serializers.py | 1 + app/authentication/views.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 53c36a2..1171f38 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -28,6 +28,7 @@ def create(self, validated_data): class LoginSerializer(serializers.Serializer): phone_number = PhoneNumberField() + email = serializers.CharField(max_length=255, read_only=True) token = serializers.CharField(max_length=255, read_only=True) class Meta: diff --git a/app/authentication/views.py b/app/authentication/views.py index 88afad9..716d7cd 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -22,6 +22,23 @@ class LoginViewSet(ModelViewSet): filterset_class = UserFilter http_method_names = ['get', ] + DEFAULT_LOGIN_DATA = \ + dict([(field, "") for field in LoginSerializer.Meta.fields]) + + def list(self, request, *args, **kwargs): + print(dir(request)) + print(args, kwargs, request.content_type, request.data, request.query_params) + phone_number = request.query_params.get("phone_number", "") + print(phone_number) + if not phone_number: + data = self.DEFAULT_LOGIN_DATA + else: + user = models.User.objects.get_by_natural_key(phone_number) + data = LoginSerializer(user).data + + return Response(data) + + # def get_object(self): # print(self.kwargs) # user = self.request.user From 851420835cc72d0b60c933dc25ae1a1c0c9da090 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Tue, 16 Jul 2019 12:37:30 +0300 Subject: [PATCH 16/24] alters User model fields --- .../migrations/0007_auto_20190716_0917.py | 29 +++++++++++++++++++ app/authentication/models.py | 4 +-- app/authentication/serializers.py | 6 ++-- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 app/authentication/migrations/0007_auto_20190716_0917.py diff --git a/app/authentication/migrations/0007_auto_20190716_0917.py b/app/authentication/migrations/0007_auto_20190716_0917.py new file mode 100644 index 0000000..1526873 --- /dev/null +++ b/app/authentication/migrations/0007_auto_20190716_0917.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.3 on 2019-07-16 09:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0006_auto_20190711_1933'), + ] + + operations = [ + migrations.RemoveField( + model_name='user', + name='username', + ), + migrations.AddField( + model_name='user', + name='first_name', + field=models.CharField(default='default', max_length=50), + preserve_default=False, + ), + migrations.AddField( + model_name='user', + name='last_name', + field=models.CharField(default='default', max_length=50), + preserve_default=False, + ), + ] diff --git a/app/authentication/models.py b/app/authentication/models.py index 550dcf5..1e5f611 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -49,8 +49,8 @@ def create_superuser(self, **fields): class User(AbstractBaseUser, PermissionsMixin): - username = models.CharField( - db_index=True, max_length=255, unique=True, blank=True, null=True) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) email = models.EmailField(db_index=True, unique=True) phone_number = PhoneNumberField(db_index=True, unique=True) date_of_birth = models.DateField() diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 1171f38..eef0dd5 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -19,7 +19,7 @@ class RegistrationSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'email', 'username', + fields = ['id', 'first_name', 'last_name', 'email', 'phone_number', 'date_of_birth', 'gender'] def create(self, validated_data): @@ -30,7 +30,9 @@ class LoginSerializer(serializers.Serializer): phone_number = PhoneNumberField() email = serializers.CharField(max_length=255, read_only=True) token = serializers.CharField(max_length=255, read_only=True) + first_name = serializers.CharField(max_length=50, read_only=True) + last_name = serializers.CharField(max_length=50, read_only=True) class Meta: model = User - fields = ['id', 'phone_number', 'token'] + fields = ['id', 'first_name', 'last_name', 'phone_number', 'token'] From 9d4ac8319c40a648347622c4bfb99b6568fa598e Mon Sep 17 00:00:00 2001 From: graycadeau Date: Tue, 16 Jul 2019 17:09:35 +0300 Subject: [PATCH 17/24] user profile --- app/authentication/models.py | 2 +- app/authentication/views.py | 19 ++------------- .../migrations/0002_auto_20190716_1039.py | 23 +++++++++++++++++++ .../migrations/0003_auto_20190716_1304.py | 20 ++++++++++++++++ .../migrations/0004_auto_20190716_1405.py | 20 ++++++++++++++++ app/user_profile/models.py | 8 +++---- app/user_profile/serializers.py | 15 +++++++----- app/user_profile/views.py | 7 +++--- dscountr/settings.py | 2 ++ 9 files changed, 84 insertions(+), 32 deletions(-) create mode 100644 app/user_profile/migrations/0002_auto_20190716_1039.py create mode 100644 app/user_profile/migrations/0003_auto_20190716_1304.py create mode 100644 app/user_profile/migrations/0004_auto_20190716_1405.py diff --git a/app/authentication/models.py b/app/authentication/models.py index 1e5f611..1614a87 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -87,7 +87,7 @@ def token(self): def _generate_firebase_token(self): """ - Generates a firebase token + Generates a jwt token """ user_details = {'email': self.email} token = jwt.encode( diff --git a/app/authentication/views.py b/app/authentication/views.py index 716d7cd..8a6b8b5 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -12,7 +12,7 @@ class RegistrationViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = RegistrationSerializer queryset = models.User.objects.all() - http_method_names = ['post'] + http_method_names = ['post', 'get'] class LoginViewSet(ModelViewSet): @@ -23,13 +23,10 @@ class LoginViewSet(ModelViewSet): http_method_names = ['get', ] DEFAULT_LOGIN_DATA = \ - dict([(field, "") for field in LoginSerializer.Meta.fields]) + dict([(field, "") for field in LoginSerializer.Meta.fields]) def list(self, request, *args, **kwargs): - print(dir(request)) - print(args, kwargs, request.content_type, request.data, request.query_params) phone_number = request.query_params.get("phone_number", "") - print(phone_number) if not phone_number: data = self.DEFAULT_LOGIN_DATA else: @@ -39,18 +36,6 @@ def list(self, request, *args, **kwargs): return Response(data) - # def get_object(self): - # print(self.kwargs) - # user = self.request.user - # pn = models.User.objects.filter(email=user) - # print(pn) - # queryset = models.User.objects.filter( - # id=2999, phone_number__startswith='+') - # print('<><><><>', queryset) - # obj = get_object_or_404(queryset, id=self.kwargs["pk"]) - # return obj - - class UserViewSet(ModelViewSet): permission_classes = (IsAdminUser, IsAuthenticated) serializer_class = RegistrationSerializer diff --git a/app/user_profile/migrations/0002_auto_20190716_1039.py b/app/user_profile/migrations/0002_auto_20190716_1039.py new file mode 100644 index 0000000..357ab71 --- /dev/null +++ b/app/user_profile/migrations/0002_auto_20190716_1039.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.3 on 2019-07-16 10:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='first_name', + field=models.CharField(max_length=50), + ), + migrations.AlterField( + model_name='profile', + name='last_name', + field=models.CharField(max_length=50), + ), + ] diff --git a/app/user_profile/migrations/0003_auto_20190716_1304.py b/app/user_profile/migrations/0003_auto_20190716_1304.py new file mode 100644 index 0000000..3145763 --- /dev/null +++ b/app/user_profile/migrations/0003_auto_20190716_1304.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.3 on 2019-07-16 13:04 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0002_auto_20190716_1039'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/app/user_profile/migrations/0004_auto_20190716_1405.py b/app/user_profile/migrations/0004_auto_20190716_1405.py new file mode 100644 index 0000000..1b031a9 --- /dev/null +++ b/app/user_profile/migrations/0004_auto_20190716_1405.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.3 on 2019-07-16 14:05 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0003_auto_20190716_1304'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/app/user_profile/models.py b/app/user_profile/models.py index 98d6f81..4c5ba63 100644 --- a/app/user_profile/models.py +++ b/app/user_profile/models.py @@ -9,15 +9,15 @@ class Profile(TimeStampedModel): user = models.OneToOneField( - "authentication.User", related_name="profile", on_delete=models.CASCADE) - first_name = models.CharField(max_length=30, blank=True) - last_name = models.CharField(max_length=30, blank=True) + User, related_name="profile", on_delete=models.CASCADE) + first_name = models.CharField(max_length=50, blank=False) + last_name = models.CharField(max_length=50, blank=False) class Meta: ordering = ['-created', ] def __str__(self): - return self.user.username + return self.user.email @receiver(post_save, sender=User) diff --git a/app/user_profile/serializers.py b/app/user_profile/serializers.py index 3b7e31a..b5fe5a5 100644 --- a/app/user_profile/serializers.py +++ b/app/user_profile/serializers.py @@ -1,18 +1,21 @@ from rest_framework import serializers + from .models import Profile +from ..authentication.models import User class UserProfileSerializer(serializers.ModelSerializer): """ Serializer class for getting user profile """ - username = serializers.ReadOnlyField(source='fetch_username') - first_name = serializers.CharField( - allow_blank=True, required=False, min_length=1, max_length=50) - last_name = serializers.CharField( - allow_blank=True, required=False, min_length=1, max_length=50) + email = serializers.ReadOnlyField(source='user.email') + full_name = serializers.SerializerMethodField() class Meta: model = Profile - fields = ['username', 'id', 'first_name', 'last_name'] + fields = ['id', 'first_name', + 'last_name', 'full_name', 'email'] + + def get_full_name(self, obj): + return f'{obj.first_name} {obj.last_name}' diff --git a/app/user_profile/views.py b/app/user_profile/views.py index b35531e..36d557c 100644 --- a/app/user_profile/views.py +++ b/app/user_profile/views.py @@ -1,13 +1,12 @@ -from rest_framework.permissions import IsAdminUser, IsAuthenticated, AllowAny +from rest_framework.permissions import IsAdminUser, IsAuthenticated, AllowAny, IsAuthenticatedOrReadOnly from rest_framework.viewsets import ModelViewSet from .serializers import (UserProfileSerializer,) -from . import models +from .models import Profile from ..firebase_auth import FirebaseTokenAuthentication class UserProfileViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = UserProfileSerializer - authentication_classes = (FirebaseTokenAuthentication,) - queryset = models.Profile.objects.all() + queryset = Profile.objects.all() http_method_names = ['get', 'patch'] diff --git a/dscountr/settings.py b/dscountr/settings.py index 5bc40e9..8b0f248 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -117,8 +117,10 @@ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( # 'app.firebase_auth.FirebaseTokenAuthentication', + "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", + ), "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), } From 5af1ffd138286b6ae92647447b4ca67d0acb7162 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Wed, 17 Jul 2019 11:35:05 +0300 Subject: [PATCH 18/24] user update generates token --- app/authentication/backends.py | 90 +++++++++++++++++++ app/authentication/models.py | 39 ++++---- app/authentication/serializers.py | 39 +++++++- app/authentication/urls.py | 5 +- app/authentication/views.py | 17 ++-- .../migrations/0005_auto_20190716_1436.py | 21 +++++ app/user_profile/models.py | 2 - app/user_profile/serializers.py | 7 +- dscountr/settings.py | 6 +- 9 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 app/authentication/backends.py create mode 100644 app/user_profile/migrations/0005_auto_20190716_1436.py diff --git a/app/authentication/backends.py b/app/authentication/backends.py new file mode 100644 index 0000000..eb16306 --- /dev/null +++ b/app/authentication/backends.py @@ -0,0 +1,90 @@ +import jwt + +from django.conf import settings +from datetime import datetime + +from decouple import config + +from rest_framework import authentication, exceptions + +from .models import User + + +class JWTAuthentication(authentication.BaseAuthentication): + authentication_header_prefix = 'Token' + + def authenticate(self, request): + """ + The `authenticate` method is called on every request regardless of + whether the endpoint requires authentication. + + `authenticate` has two possible return values: + + 1) `None` - We return `None` if we do not wish to authenticate. Usually + this means we know authentication will fail. An example of + this is when the request does not include a token in the + headers. + + 2) `(user, token)` - We return a user/token combination when + authentication is successful. + + If neither case is met, that means there's an error + and we do not return anything. + We simple raise the `AuthenticationFailed` + exception and let Django REST Framework + handle the rest. + """ + request.user = None + + auth_header = authentication.get_authorization_header(request).split() + auth_header_prefix = self.authentication_header_prefix.lower() + + if not auth_header: + return None + + if len(auth_header) == 1: + return None + + elif len(auth_header) > 2: + return None + + prefix = auth_header[0].decode('utf-8') + token = auth_header[1].decode('utf-8') + + if prefix.lower() != auth_header_prefix: + return None + + return self._authenticate_credentials(request, token) + + def _authenticate_credentials(self, request, token): + """ + Try to authenticate the given credentials. If authentication is + successful, return the user and token. If not, throw an error. + """ + try: + payload = jwt.decode(token, config('SECRET_KEY')) + except: + msg = 'Invalid authentication. Could not decode token.' + raise exceptions.AuthenticationFailed(msg) + + try: + user = User.objects.get(pk=payload['id']) + except User.DoesNotExist: + msg = 'No user matching this token was found.' + raise exceptions.AuthenticationFailed(msg) + + if not user.is_active: + msg = 'This user has been deactivated.' + raise exceptions.AuthenticationFailed(msg) + + return (user, token) + + def generate_token(self, user_id): + """ + gerates jwt token by encoding registered user id + """ + payload = { + 'id': user_id, + 'iat': datetime.utcnow() + } + return jwt.encode(payload, config('SECRET_KEY')).decode('UTF-8') diff --git a/app/authentication/models.py b/app/authentication/models.py index 1614a87..2d84eda 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -70,6 +70,7 @@ class User(AbstractBaseUser, PermissionsMixin): class Meta: verbose_name_plural = "All Users" + ordering = ["-id"] def __str__(self): """ @@ -78,22 +79,22 @@ def __str__(self): """ return self.email - @property - def token(self): - """ - method allows us to get a user's token - """ - return self._generate_firebase_token() - - def _generate_firebase_token(self): - """ - Generates a jwt token - """ - user_details = {'email': self.email} - token = jwt.encode( - { - 'user_data': user_details, - 'exp': datetime.now() + timedelta(hours=24) - }, settings.SECRET_KEY, algorithm='HS256' - ) - return token.decode('utf-8') + # @property + # def token(self): + # """ + # method allows us to get a user's token + # """ + # return self._generate_firebase_token() + + # def _generate_firebase_token(self): + # """ + # Generates a jwt token + # """ + # dt = datetime.now() + timedelta(days=60) + + # token = jwt.encode({ + # 'id': self.pk, + # 'exp': int(dt.strftime('%s')) + # }, settings.SECRET_KEY, algorithm='HS256') + + # return token.decode('utf-8') diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index eef0dd5..4308f9b 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -8,6 +8,7 @@ from ..user_profile.models import Profile from ..auth_backend import PasswordlessAuthBackend from decouple import config +from .backends import JWTAuthentication class RegistrationSerializer(serializers.ModelSerializer): @@ -16,12 +17,16 @@ class RegistrationSerializer(serializers.ModelSerializer): UniqueValidator(queryset=User.objects.all(), message='User with this Phone Number already exists.', )],) + full_name = serializers.SerializerMethodField() class Meta: model = User - fields = ['id', 'first_name', 'last_name', 'email', + fields = ['id', 'first_name', 'last_name', 'full_name', 'email', 'phone_number', 'date_of_birth', 'gender'] + def get_full_name(self, obj): + return f'{obj.first_name} {obj.last_name}' + def create(self, validated_data): return User.objects.createuser(**validated_data) @@ -29,10 +34,40 @@ def create(self, validated_data): class LoginSerializer(serializers.Serializer): phone_number = PhoneNumberField() email = serializers.CharField(max_length=255, read_only=True) - token = serializers.CharField(max_length=255, read_only=True) + token = serializers.SerializerMethodField() first_name = serializers.CharField(max_length=50, read_only=True) last_name = serializers.CharField(max_length=50, read_only=True) + def get_token(self, obj): + token = JWTAuthentication.generate_token(self, obj.pk) + return token + class Meta: model = User fields = ['id', 'first_name', 'last_name', 'phone_number', 'token'] + + +class UserSerializer(serializers.ModelSerializer): + """Handles serialization and deserialization of User objects.""" + + class Meta: + model = User + fields = ['id', 'email'] + + read_only_fields = ('token',) + + def update(self, instance, validated_data): + """Performs an update on a User.""" + + password = validated_data.pop('password') + + for (key, value) in validated_data.items(): + + setattr(instance, key, value) + + if password is not None: + instance.set_password(password) + + instance.save() + + return instance diff --git a/app/authentication/urls.py b/app/authentication/urls.py index e490e0d..2211327 100644 --- a/app/authentication/urls.py +++ b/app/authentication/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import include from django.urls import path from rest_framework.routers import DefaultRouter, SimpleRouter -from .views import RegistrationViewSet, LoginViewSet +from .views import RegistrationViewSet, LoginViewSet, UpdateUserViewSet from ..user_profile.views import UserProfileViewSet app_name = 'authentication' @@ -16,9 +16,10 @@ def __init_(self, trailing_slash='/?'): router = OptionalTrailingSlashRouter() # users -router.register('users', RegistrationViewSet, 'user') +router.register('users', RegistrationViewSet, 'users') router.register('profiles', UserProfileViewSet, 'profile') router.register('login', LoginViewSet, 'login') +router.register('user', UpdateUserViewSet, 'user') urlpatterns = [ diff --git a/app/authentication/views.py b/app/authentication/views.py index 8a6b8b5..a48f786 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -1,18 +1,19 @@ from rest_framework import status -from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated +from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.response import Response from rest_framework.generics import get_object_or_404 -from .serializers import (RegistrationSerializer, LoginSerializer) +from .serializers import (RegistrationSerializer, + LoginSerializer, UserSerializer) from . import models from ..filters import UserFilter class RegistrationViewSet(ModelViewSet): - permission_classes = (AllowAny,) + permission_classes = (IsAuthenticatedOrReadOnly,) serializer_class = RegistrationSerializer queryset = models.User.objects.all() - http_method_names = ['post', 'get'] + http_method_names = ['post', 'get', 'patch'] class LoginViewSet(ModelViewSet): @@ -36,8 +37,8 @@ def list(self, request, *args, **kwargs): return Response(data) -class UserViewSet(ModelViewSet): - permission_classes = (IsAdminUser, IsAuthenticated) - serializer_class = RegistrationSerializer +class UpdateUserViewSet(ModelViewSet): + permission_classes = (IsAuthenticated,) + serializer_class = UserSerializer queryset = models.User.objects.all() - http_method_names = ['post', 'get', 'patch'] + http_method_names = ['patch', 'get'] diff --git a/app/user_profile/migrations/0005_auto_20190716_1436.py b/app/user_profile/migrations/0005_auto_20190716_1436.py new file mode 100644 index 0000000..b93628b --- /dev/null +++ b/app/user_profile/migrations/0005_auto_20190716_1436.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2.3 on 2019-07-16 14:36 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0004_auto_20190716_1405'), + ] + + operations = [ + migrations.RemoveField( + model_name='profile', + name='first_name', + ), + migrations.RemoveField( + model_name='profile', + name='last_name', + ), + ] diff --git a/app/user_profile/models.py b/app/user_profile/models.py index 4c5ba63..98dab1d 100644 --- a/app/user_profile/models.py +++ b/app/user_profile/models.py @@ -10,8 +10,6 @@ class Profile(TimeStampedModel): user = models.OneToOneField( User, related_name="profile", on_delete=models.CASCADE) - first_name = models.CharField(max_length=50, blank=False) - last_name = models.CharField(max_length=50, blank=False) class Meta: ordering = ['-created', ] diff --git a/app/user_profile/serializers.py b/app/user_profile/serializers.py index b5fe5a5..cc2739c 100644 --- a/app/user_profile/serializers.py +++ b/app/user_profile/serializers.py @@ -10,12 +10,7 @@ class UserProfileSerializer(serializers.ModelSerializer): Serializer class for getting user profile """ email = serializers.ReadOnlyField(source='user.email') - full_name = serializers.SerializerMethodField() class Meta: model = Profile - fields = ['id', 'first_name', - 'last_name', 'full_name', 'email'] - - def get_full_name(self, obj): - return f'{obj.first_name} {obj.last_name}' + fields = ['id', 'email'] diff --git a/dscountr/settings.py b/dscountr/settings.py index 8b0f248..df4db47 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -91,8 +91,6 @@ } AUTHENTICATION_BACKENDS = ( - # ... your other backends - 'app.auth_backend.PasswordlessAuthBackend', 'django.contrib.auth.backends.ModelBackend', ) @@ -117,9 +115,7 @@ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( # 'app.firebase_auth.FirebaseTokenAuthentication', - "rest_framework.authentication.TokenAuthentication", - "rest_framework.authentication.BasicAuthentication", - "rest_framework.authentication.SessionAuthentication", + 'app.authentication.backends.JWTAuthentication', ), "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), From d9a386c8668d27c430abbc6dda467d5fe6527474 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Wed, 17 Jul 2019 15:10:55 +0300 Subject: [PATCH 19/24] updates users details --- app/authentication/backends.py | 16 ---------------- app/authentication/serializers.py | 9 ++++----- app/authentication/views.py | 2 +- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/app/authentication/backends.py b/app/authentication/backends.py index eb16306..5ba230a 100644 --- a/app/authentication/backends.py +++ b/app/authentication/backends.py @@ -17,22 +17,6 @@ def authenticate(self, request): """ The `authenticate` method is called on every request regardless of whether the endpoint requires authentication. - - `authenticate` has two possible return values: - - 1) `None` - We return `None` if we do not wish to authenticate. Usually - this means we know authentication will fail. An example of - this is when the request does not include a token in the - headers. - - 2) `(user, token)` - We return a user/token combination when - authentication is successful. - - If neither case is met, that means there's an error - and we do not return anything. - We simple raise the `AuthenticationFailed` - exception and let Django REST Framework - handle the rest. """ request.user = None diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 4308f9b..63348b6 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -52,22 +52,21 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'email'] + fields = ['id', 'first_name', 'last_name', + 'phone_number', 'email', 'date_of_birth', 'gender'] read_only_fields = ('token',) def update(self, instance, validated_data): """Performs an update on a User.""" - password = validated_data.pop('password') + email = validated_data.pop('email') + phone_number = validated_data.pop('phone_number') for (key, value) in validated_data.items(): setattr(instance, key, value) - if password is not None: - instance.set_password(password) - instance.save() return instance diff --git a/app/authentication/views.py b/app/authentication/views.py index a48f786..94be78d 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -13,7 +13,7 @@ class RegistrationViewSet(ModelViewSet): permission_classes = (IsAuthenticatedOrReadOnly,) serializer_class = RegistrationSerializer queryset = models.User.objects.all() - http_method_names = ['post', 'get', 'patch'] + http_method_names = ['post', 'get'] class LoginViewSet(ModelViewSet): From 682868c7f47ddffd107ab1fc5c0ff375c1b3bee9 Mon Sep 17 00:00:00 2001 From: meshnesh Date: Wed, 17 Jul 2019 21:03:00 +0300 Subject: [PATCH 20/24] added sessionAuth token --- .../migrations/0008_auto_20190717_1802.py | 22 +++++++++++++++++++ dscountr/settings.py | 1 + 2 files changed, 23 insertions(+) create mode 100644 app/authentication/migrations/0008_auto_20190717_1802.py diff --git a/app/authentication/migrations/0008_auto_20190717_1802.py b/app/authentication/migrations/0008_auto_20190717_1802.py new file mode 100644 index 0000000..d37c202 --- /dev/null +++ b/app/authentication/migrations/0008_auto_20190717_1802.py @@ -0,0 +1,22 @@ +# Generated by Django 2.2.3 on 2019-07-17 18:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0007_auto_20190716_0917'), + ] + + operations = [ + migrations.AlterModelOptions( + name='user', + options={'ordering': ['-id'], 'verbose_name_plural': 'All Users'}, + ), + migrations.AlterField( + model_name='user', + name='password', + field=models.CharField(default='YouAndM3', max_length=255), + ), + ] diff --git a/dscountr/settings.py b/dscountr/settings.py index df4db47..127d620 100644 --- a/dscountr/settings.py +++ b/dscountr/settings.py @@ -116,6 +116,7 @@ "DEFAULT_AUTHENTICATION_CLASSES": ( # 'app.firebase_auth.FirebaseTokenAuthentication', 'app.authentication.backends.JWTAuthentication', + 'rest_framework.authentication.SessionAuthentication', ), "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), From 37937d5237a328550ab7760001c1df2dc2811463 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Wed, 17 Jul 2019 21:18:13 +0300 Subject: [PATCH 21/24] change permissions --- app/authentication/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/authentication/views.py b/app/authentication/views.py index 94be78d..65f09fb 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -10,7 +10,7 @@ class RegistrationViewSet(ModelViewSet): - permission_classes = (IsAuthenticatedOrReadOnly,) + permission_classes = (AllowAny,) serializer_class = RegistrationSerializer queryset = models.User.objects.all() http_method_names = ['post', 'get'] From a7f7bc0d7b2d60f561ef30d81824dd1596de01d7 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Mon, 22 Jul 2019 16:02:31 +0300 Subject: [PATCH 22/24] format files --- Pipfile | 2 + Pipfile.lock | 51 ++++++++++++++--- app/apps.py | 2 +- app/auth_backend.py | 4 +- app/authentication/choices.py | 6 +- .../migrations/0009_auto_20190722_1140.py | 18 ++++++ app/authentication/models.py | 23 ++++---- app/authentication/serializers.py | 56 +++++++++++++------ app/authentication/urls.py | 15 ++--- app/authentication/views.py | 26 +++++---- app/filters.py | 5 +- app/firebase_auth.py | 6 +- app/user_profile/models.py | 7 +-- app/user_profile/serializers.py | 8 +-- app/user_profile/views.py | 14 +++-- 15 files changed, 163 insertions(+), 80 deletions(-) create mode 100644 app/authentication/migrations/0009_auto_20190722_1140.py diff --git a/Pipfile b/Pipfile index 49cde31..33fd872 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,8 @@ verify_ssl = true [dev-packages] autopep8 = "*" pylint = "*" +black = "19.3b0" +isort = "4.3.21" [packages] django = "==2.2.3" diff --git a/Pipfile.lock b/Pipfile.lock index 7d146d8..8efe4e5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8598a500a7165a35194927dac2119289b3187a403bd9cba5e9bdaf140678cec8" + "sha256": "549e431b79c0985a2228e128bfa630c1265a600ef3f6a6f6170476cc1f595f60" }, "pipfile-spec": 6, "requires": { @@ -126,11 +126,11 @@ "grpc" ], "hashes": [ - "sha256:72a1c8966bdbd70a72de32760368aec399fe6a5c2a6675d9476cb9ae27046de7", - "sha256:f45d74aef41e1de49ceadebf382e1291ddcbe431a8b533aff8a1140a35531465" + "sha256:ae9e76295a268e27a829a752cc2d0e58a529daeecf9be8ff7a981f0325452671", + "sha256:b4e488df53535a1d6f5876c0201f00a954659f5ed396d63fc15b3204d63a3604" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.13.0" + "version": "==1.14.0" }, "google-api-python-client": { "hashes": [ @@ -417,13 +417,20 @@ }, "whitenoise": { "hashes": [ - "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", - "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" + "sha256:59d880d25d0e90bcc6554fe0504a11195bd2e59b3d690b6fb42a8040d4e67ef5", + "sha256:c9b7c47fdc1dba4d37bf2787a01a844dc7a521e174fcd22a2d429e0be65e1782" ], - "version": "==4.1.2" + "version": "==4.1.3" } }, "develop": { + "appdirs": { + "hashes": [ + "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", + "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" + ], + "version": "==1.4.3" + }, "astroid": { "hashes": [ "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", @@ -431,6 +438,13 @@ ], "version": "==2.2.5" }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -438,11 +452,27 @@ "index": "pypi", "version": "==1.4.4" }, + "black": { + "hashes": [ + "sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf", + "sha256:68950ffd4d9169716bcb8719a56c07a2f4485354fec061cdd5910aa07369731c" + ], + "index": "pypi", + "version": "==19.3b0" + }, + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "version": "==7.0" + }, "isort": { "hashes": [ "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" ], + "index": "pypi", "version": "==4.3.21" }, "lazy-object-proxy": { @@ -497,6 +527,13 @@ ], "version": "==1.12.0" }, + "toml": { + "hashes": [ + "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", + "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" + ], + "version": "==0.10.0" + }, "typed-ast": { "hashes": [ "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", diff --git a/app/apps.py b/app/apps.py index 6b5d94f..1e4d098 100644 --- a/app/apps.py +++ b/app/apps.py @@ -2,4 +2,4 @@ class MyappConfig(AppConfig): - name = 'app' + name = "app" diff --git a/app/auth_backend.py b/app/auth_backend.py index 11996d6..a731dae 100644 --- a/app/auth_backend.py +++ b/app/auth_backend.py @@ -1,6 +1,6 @@ -from django.contrib.auth.backends import ModelBackend -from django.contrib.auth import get_user_model from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend User = get_user_model() diff --git a/app/authentication/choices.py b/app/authentication/choices.py index e06de7b..933a2b7 100644 --- a/app/authentication/choices.py +++ b/app/authentication/choices.py @@ -1,5 +1 @@ -GENDER_CHOICES = ( - ('M', 'Male'), - ('F', 'Female'), - ('A', 'Alien'), -) +GENDER_CHOICES = (("M", "Male"), ("F", "Female"), ("A", "Alien")) diff --git a/app/authentication/migrations/0009_auto_20190722_1140.py b/app/authentication/migrations/0009_auto_20190722_1140.py new file mode 100644 index 0000000..0cfc8f6 --- /dev/null +++ b/app/authentication/migrations/0009_auto_20190722_1140.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-22 11:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0008_auto_20190717_1802'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='password', + field=models.CharField(default='!1xKZFUMiyDaS7Exy0CurdiaQ1Pp88xxHpN0kw3pb', max_length=255), + ), + ] diff --git a/app/authentication/models.py b/app/authentication/models.py index 2d84eda..b7d05e9 100644 --- a/app/authentication/models.py +++ b/app/authentication/models.py @@ -1,14 +1,15 @@ -import jwt from datetime import datetime, timedelta + +import jwt +from decouple import config from django.conf import settings -from django.contrib.auth.models import ( - AbstractBaseUser, BaseUserManager, PermissionsMixin -) -from django.db import models +from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager, + PermissionsMixin) from django.core.exceptions import ValidationError -from decouple import config -from phonenumber_field.modelfields import PhoneNumberField +from django.db import models from firebase_admin import auth +from phonenumber_field.modelfields import PhoneNumberField + from .choices import GENDER_CHOICES @@ -16,7 +17,7 @@ class UserManager(BaseUserManager): use_in_migrations = True def createuser(self, **fields): - email = fields.pop('email') + email = fields.pop("email") if not email: raise ValueError("Email address is required") @@ -55,15 +56,15 @@ class User(AbstractBaseUser, PermissionsMixin): phone_number = PhoneNumberField(db_index=True, unique=True) date_of_birth = models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) - password = models.CharField(max_length=255, default=config('P_WORD')) + password = models.CharField(max_length=255, default=config("P_WORD")) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # The `USERNAME_FIELD` property specifies the log in field. - USERNAME_FIELD = 'phone_number' - REQUIRED_FIELDS = ['email', 'date_of_birth', ] + USERNAME_FIELD = "phone_number" + REQUIRED_FIELDS = ["email", "date_of_birth"] # the UserManager class should manage objects of this type. objects = UserManager() diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 63348b6..72fffe6 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -1,31 +1,44 @@ import json -from rest_framework import serializers + +from decouple import config from django.contrib.auth import authenticate -from rest_framework.validators import UniqueValidator -from .models import User from firebase_admin import auth from phonenumber_field.serializerfields import PhoneNumberField -from ..user_profile.models import Profile +from rest_framework import serializers +from rest_framework.validators import UniqueValidator + from ..auth_backend import PasswordlessAuthBackend -from decouple import config +from ..user_profile.models import Profile from .backends import JWTAuthentication +from .models import User class RegistrationSerializer(serializers.ModelSerializer): phone_number = PhoneNumberField( validators=[ - UniqueValidator(queryset=User.objects.all(), - message='User with this Phone Number already exists.', - )],) + UniqueValidator( + queryset=User.objects.all(), + message="User with this Phone Number already exists.", + ) + ] + ) full_name = serializers.SerializerMethodField() class Meta: model = User - fields = ['id', 'first_name', 'last_name', 'full_name', 'email', - 'phone_number', 'date_of_birth', 'gender'] + fields = [ + "id", + "first_name", + "last_name", + "full_name", + "email", + "phone_number", + "date_of_birth", + "gender", + ] def get_full_name(self, obj): - return f'{obj.first_name} {obj.last_name}' + return f"{obj.first_name} {obj.last_name}" def create(self, validated_data): return User.objects.createuser(**validated_data) @@ -44,7 +57,7 @@ def get_token(self, obj): class Meta: model = User - fields = ['id', 'first_name', 'last_name', 'phone_number', 'token'] + fields = ["id", "first_name", "last_name", "phone_number", "token"] class UserSerializer(serializers.ModelSerializer): @@ -52,16 +65,23 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'first_name', 'last_name', - 'phone_number', 'email', 'date_of_birth', 'gender'] - - read_only_fields = ('token',) + fields = [ + "id", + "first_name", + "last_name", + "phone_number", + "email", + "date_of_birth", + "gender", + ] + + read_only_fields = ("token",) def update(self, instance, validated_data): """Performs an update on a User.""" - email = validated_data.pop('email') - phone_number = validated_data.pop('phone_number') + email = validated_data.pop("email") + phone_number = validated_data.pop("phone_number") for (key, value) in validated_data.items(): diff --git a/app/authentication/urls.py b/app/authentication/urls.py index 2211327..438cfdd 100644 --- a/app/authentication/urls.py +++ b/app/authentication/urls.py @@ -1,14 +1,15 @@ from django.conf.urls import include from django.urls import path from rest_framework.routers import DefaultRouter, SimpleRouter -from .views import RegistrationViewSet, LoginViewSet, UpdateUserViewSet + from ..user_profile.views import UserProfileViewSet +from .views import LoginViewSet, RegistrationViewSet, UpdateUserViewSet -app_name = 'authentication' +app_name = "authentication" class OptionalTrailingSlashRouter(SimpleRouter): - def __init_(self, trailing_slash='/?'): + def __init_(self, trailing_slash="/?"): self.trailing_slash = trailing_slash super().__init__() @@ -16,10 +17,10 @@ def __init_(self, trailing_slash='/?'): router = OptionalTrailingSlashRouter() # users -router.register('users', RegistrationViewSet, 'users') -router.register('profiles', UserProfileViewSet, 'profile') -router.register('login', LoginViewSet, 'login') -router.register('user', UpdateUserViewSet, 'user') +router.register("users", RegistrationViewSet, "users") +router.register("profiles", UserProfileViewSet, "profile") +router.register("login", LoginViewSet, "login") +router.register("user", UpdateUserViewSet, "user") urlpatterns = [ diff --git a/app/authentication/views.py b/app/authentication/views.py index 65f09fb..3917cd6 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -1,19 +1,24 @@ from rest_framework import status -from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly -from rest_framework.viewsets import ModelViewSet, GenericViewSet -from rest_framework.response import Response from rest_framework.generics import get_object_or_404 -from .serializers import (RegistrationSerializer, - LoginSerializer, UserSerializer) -from . import models +from rest_framework.permissions import ( + AllowAny, + IsAdminUser, + IsAuthenticated, + IsAuthenticatedOrReadOnly, +) +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet, ModelViewSet + from ..filters import UserFilter +from . import models +from .serializers import LoginSerializer, RegistrationSerializer, UserSerializer class RegistrationViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = RegistrationSerializer queryset = models.User.objects.all() - http_method_names = ['post', 'get'] + http_method_names = ["post", "get"] class LoginViewSet(ModelViewSet): @@ -21,10 +26,9 @@ class LoginViewSet(ModelViewSet): serializer_class = LoginSerializer queryset = models.User.objects.all() filterset_class = UserFilter - http_method_names = ['get', ] + http_method_names = ["get"] - DEFAULT_LOGIN_DATA = \ - dict([(field, "") for field in LoginSerializer.Meta.fields]) + DEFAULT_LOGIN_DATA = dict([(field, "") for field in LoginSerializer.Meta.fields]) def list(self, request, *args, **kwargs): phone_number = request.query_params.get("phone_number", "") @@ -41,4 +45,4 @@ class UpdateUserViewSet(ModelViewSet): permission_classes = (IsAuthenticated,) serializer_class = UserSerializer queryset = models.User.objects.all() - http_method_names = ['patch', 'get'] + http_method_names = ["patch", "get"] diff --git a/app/filters.py b/app/filters.py index f0e567a..ff08155 100644 --- a/app/filters.py +++ b/app/filters.py @@ -25,8 +25,7 @@ def filter_contains_with_multiple_query_values(self, queryset, name, value): if options: lookup = functools.reduce( operator.or_, - {Q(**{"__".join([name, "icontains"]): item}) - for item in options}, + {Q(**{"__".join([name, "icontains"]): item}) for item in options}, ) else: lookup = Q(**{}) @@ -52,4 +51,4 @@ class UserFilter(BaseFilter): class Meta: model = User - fields = ["phone_number", ] + fields = ["phone_number"] diff --git a/app/firebase_auth.py b/app/firebase_auth.py index 7ac20d7..bccfb95 100644 --- a/app/firebase_auth.py +++ b/app/firebase_auth.py @@ -1,10 +1,10 @@ import logging + +from decouple import config from django.contrib.auth import get_user_model +from firebase_admin import auth, credentials, initialize_app from rest_framework import exceptions from rest_framework.authentication import TokenAuthentication -from decouple import config -from firebase_admin import auth, credentials, initialize_app - private_key = config("PRIVATE_KEY").replace("\\n", "\n") payload = { diff --git a/app/user_profile/models.py b/app/user_profile/models.py index 98dab1d..67aa2c6 100644 --- a/app/user_profile/models.py +++ b/app/user_profile/models.py @@ -1,5 +1,5 @@ -from django.db import models from django.contrib.auth import get_user_model +from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver from django_extensions.db.models import TimeStampedModel @@ -8,11 +8,10 @@ class Profile(TimeStampedModel): - user = models.OneToOneField( - User, related_name="profile", on_delete=models.CASCADE) + user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE) class Meta: - ordering = ['-created', ] + ordering = ["-created"] def __str__(self): return self.user.email diff --git a/app/user_profile/serializers.py b/app/user_profile/serializers.py index cc2739c..5ddeebb 100644 --- a/app/user_profile/serializers.py +++ b/app/user_profile/serializers.py @@ -1,16 +1,16 @@ from rest_framework import serializers - -from .models import Profile from ..authentication.models import User +from .models import Profile class UserProfileSerializer(serializers.ModelSerializer): """ Serializer class for getting user profile """ - email = serializers.ReadOnlyField(source='user.email') + + email = serializers.ReadOnlyField(source="user.email") class Meta: model = Profile - fields = ['id', 'email'] + fields = ["id", "email"] diff --git a/app/user_profile/views.py b/app/user_profile/views.py index 36d557c..6333d67 100644 --- a/app/user_profile/views.py +++ b/app/user_profile/views.py @@ -1,12 +1,18 @@ -from rest_framework.permissions import IsAdminUser, IsAuthenticated, AllowAny, IsAuthenticatedOrReadOnly +from rest_framework.permissions import ( + AllowAny, + IsAdminUser, + IsAuthenticated, + IsAuthenticatedOrReadOnly, +) from rest_framework.viewsets import ModelViewSet -from .serializers import (UserProfileSerializer,) -from .models import Profile + from ..firebase_auth import FirebaseTokenAuthentication +from .models import Profile +from .serializers import UserProfileSerializer class UserProfileViewSet(ModelViewSet): permission_classes = (AllowAny,) serializer_class = UserProfileSerializer queryset = Profile.objects.all() - http_method_names = ['get', 'patch'] + http_method_names = ["get", "patch"] From 94c1c3a632b6b40cdfbe2e9c530d1128b0f2c29d Mon Sep 17 00:00:00 2001 From: graycadeau Date: Fri, 26 Jul 2019 20:59:21 +0300 Subject: [PATCH 23/24] user fields --- app/authentication/serializers.py | 5 ++++- app/authentication/views.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/authentication/serializers.py b/app/authentication/serializers.py index 72fffe6..1abfed0 100644 --- a/app/authentication/serializers.py +++ b/app/authentication/serializers.py @@ -50,6 +50,8 @@ class LoginSerializer(serializers.Serializer): token = serializers.SerializerMethodField() first_name = serializers.CharField(max_length=50, read_only=True) last_name = serializers.CharField(max_length=50, read_only=True) + gender = serializers.CharField(max_length=50, read_only=True) + date_of_birth = serializers.CharField(max_length=50, read_only=True) def get_token(self, obj): token = JWTAuthentication.generate_token(self, obj.pk) @@ -57,7 +59,8 @@ def get_token(self, obj): class Meta: model = User - fields = ["id", "first_name", "last_name", "phone_number", "token"] + fields = ["id", "first_name", "last_name", + "phone_number", "token", "gender", "date_of_birth"] class UserSerializer(serializers.ModelSerializer): diff --git a/app/authentication/views.py b/app/authentication/views.py index 3917cd6..cd1b5c0 100644 --- a/app/authentication/views.py +++ b/app/authentication/views.py @@ -28,7 +28,8 @@ class LoginViewSet(ModelViewSet): filterset_class = UserFilter http_method_names = ["get"] - DEFAULT_LOGIN_DATA = dict([(field, "") for field in LoginSerializer.Meta.fields]) + DEFAULT_LOGIN_DATA = dict([(field, "") + for field in LoginSerializer.Meta.fields]) def list(self, request, *args, **kwargs): phone_number = request.query_params.get("phone_number", "") From 1f0da73ac9a81d4e07729b1afb8e973f16f57402 Mon Sep 17 00:00:00 2001 From: graycadeau Date: Fri, 26 Jul 2019 22:47:02 +0300 Subject: [PATCH 24/24] pipfile --- Pipfile | 4 ++-- Pipfile.lock | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Pipfile b/Pipfile index 33fd872..69a211c 100644 --- a/Pipfile +++ b/Pipfile @@ -6,8 +6,8 @@ verify_ssl = true [dev-packages] autopep8 = "*" pylint = "*" -black = "19.3b0" -isort = "4.3.21" +black = "==19.3b0" +isort = "==4.3.21" [packages] django = "==2.2.3" diff --git a/Pipfile.lock b/Pipfile.lock index 8efe4e5..d564f3b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "549e431b79c0985a2228e128bfa630c1265a600ef3f6a6f6170476cc1f595f60" + "sha256": "1869e5eaf276d31490b8bf3f66b33a371c27a0e7f7642c22a7253d5749d919c0" }, "pipfile-spec": 6, "requires": { @@ -134,10 +134,10 @@ }, "google-api-python-client": { "hashes": [ - "sha256:048da0d68564380ee23b449e5a67d4666af1b3b536d2fb0a02cee1ad540fa5ec", - "sha256:5def5a485b1cbc998b8f869456c7bde0c0e6d3d0a5ea1f300b5ef57cb4b1ce8f" + "sha256:2e55a5c7b56233c68945b6804c73e253445933f4d485d4e69e321b38772b9dd6", + "sha256:60f2ac2f27997d9af10ae126d9937b7d8c1fd061d12668ccaf94b4347ee85021" ], - "version": "==1.7.9" + "version": "==1.7.10" }, "google-auth": { "hashes": [ @@ -170,10 +170,10 @@ }, "google-cloud-storage": { "hashes": [ - "sha256:10b8a708d71b45589e06d0dc2bcc614e1d1c921902df8d22e374af1fb346ab68", - "sha256:4a2a0e2486b1977a4f3e382ed0be118933ecb6a92dc6b2c3d0b56ef8d76ac7a9" + "sha256:4e24989b69e37086bd8c219d5502b13540ee9650ab9ea52cd909ad819ea51542", + "sha256:6ed0d1c29124554691d6ff58f406062540fc9d8ef50acd59061ec3d5f820b398" ], - "version": "==1.16.1" + "version": "==1.17.0" }, "google-resumable-media": { "hashes": [