Skip to content

Commit

Permalink
Abstract User model
Browse files Browse the repository at this point in the history
  • Loading branch information
ajharry69 committed Jun 12, 2020
1 parent 1db3940 commit 9121e35
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 39 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ INSTALLED_APPS = [
```
- Add/modify your `AUTH_USER_MODEL` setting to
```python
AUTH_USER_MODEL = 'xauth.User' # Can also be a modified direct subclass of `xauth.models.User`
# Can also be a (modified) direct subclass of `xauth.models.AbstractUser`
AUTH_USER_MODEL = 'xauth.User'
```
- Add/modify your `REST_FRAMEWORK` setting to
```python
Expand Down
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ INSTALLED_APPS = [
```
- Add/modify your `AUTH_USER_MODEL` setting to
```python
AUTH_USER_MODEL = 'xauth.User' # Can also be a modified direct subclass of `xauth.models.User`
# Can also be a (modified) direct subclass of `xauth.models.AbstractUser`
AUTH_USER_MODEL = 'xauth.User'
```
- Add/modify your `REST_FRAMEWORK` setting to
```python
Expand Down
7 changes: 3 additions & 4 deletions xauth/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class UserAdmin(BaseUserAdmin):
form = UserUpdateForm
add_form = UserCreationForm

list_display = ('surname', 'first_name', 'last_name', 'date_of_birth', 'mobile_number', 'username', 'email',
'provider', 'created_at', 'is_verified', 'is_staff', 'is_newbie',)
list_display = ('username', 'email', 'surname', 'first_name', 'last_name', 'date_of_birth', 'mobile_number',
'provider', 'is_verified', 'is_staff', 'is_newbie', 'created_at',)
list_filter = ('provider', 'is_verified', 'is_staff',)
# readonly_fields = ('provider', 'is_verified', 'is_staff', 'created_at',)
search_fields = ('surname', 'first_name', 'last_name', 'email', 'mobile_number',)
Expand Down Expand Up @@ -109,6 +109,5 @@ class SecurityQuestionAdmin(admin.ModelAdmin):
list_display = ('question', 'usable', 'added_on')


admin.site.register(SecurityQuestion, SecurityQuestionAdmin)

admin.site.register(get_user_model(), UserAdmin)
admin.site.register(SecurityQuestion, SecurityQuestionAdmin)
4 changes: 3 additions & 1 deletion xauth/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.0.6 on 2020-05-29 22:20
# Generated by Django 3.0.7 on 2020-06-12 18:56

import django.utils.timezone
from django.conf import settings
Expand Down Expand Up @@ -49,6 +49,8 @@ class Migration(migrations.Migration):
],
options={
'ordering': ('created_at', 'updated_at', 'username'),
'abstract': False,
'swappable': 'AUTH_USER_MODEL',
},
),
migrations.CreateModel(
Expand Down
21 changes: 13 additions & 8 deletions xauth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from datetime import datetime, date

import timeago
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin, AbstractUser
from django.contrib.auth import models as dj_auth_models
from django.db import models
from django.utils import timezone
from django.utils.datetime_safe import date as dj_date, datetime as dj_datetime
Expand All @@ -20,7 +20,7 @@ def default_security_question():
return SecurityQuestion.objects.order_by('id').first()


class UserManager(BaseUserManager):
class UserManager(dj_auth_models.BaseUserManager):
def create_user(
self, email,
username=None,
Expand Down Expand Up @@ -66,7 +66,7 @@ def __user(self, email, username, password, surname=None, first_name=None, last_
)


class User(AbstractBaseUser, PermissionsMixin):
class AbstractUser(dj_auth_models.AbstractBaseUser, dj_auth_models.PermissionsMixin):
"""
Guidelines: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/
"""
Expand Down Expand Up @@ -112,6 +112,7 @@ class User(AbstractBaseUser, PermissionsMixin):

class Meta:
ordering = ('created_at', 'updated_at', 'username',)
abstract = True

def __str__(self):
return self.get_full_name()
Expand All @@ -132,7 +133,7 @@ def save(self, *args, **kwargs):
self.set_unusable_password()
self.is_verified = self.__get_ascertained_verification_status()
reset_empty_nullable_to_null(self, self.NULLABLE_FIELDS)
super(User, self).save(*args, **kwargs)
super(AbstractUser, self).save(*args, **kwargs)

def get_full_name(self):
"""
Expand Down Expand Up @@ -512,8 +513,7 @@ def update_signin_attempts(self, failed: bool):
attempt.refresh_from_db()
return self.__remaining_attempts(attempt) if failed else attempt.attempt_count - 1

@staticmethod
def get_random_code(alpha_numeric: bool = True, length=None):
def get_random_code(self, alpha_numeric: bool = True, length=None):
"""
Generates and returns random code of `length`
:param alpha_numeric: if `True`, include letters and numbers in the generated code
Expand All @@ -526,9 +526,9 @@ def get_random_code(alpha_numeric: bool = True, length=None):
length = random.randint(8, 10) if length is None or not isinstance(length, int) else length
rand = None
if alpha_numeric:
rand = User.objects.make_random_password(length=length)
rand = self.__class__.objects.make_random_password(length=length)
else:
rand = User.objects.make_random_password(length=length, allowed_chars='23456789')
rand = self.__class__.objects.make_random_password(length=length, allowed_chars='23456789')
return rand

def token_payload(self) -> dict:
Expand Down Expand Up @@ -583,6 +583,11 @@ def __remaining_attempts(attempt_log):
return -1 if attempt_log is None else attempt_log.remaining


class User(AbstractUser):
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'


class SecurityQuestion(models.Model):
question = models.CharField(max_length=255, blank=False, null=False, unique=True, )
added_on = models.DateTimeField(auto_now_add=True, )
Expand Down
20 changes: 1 addition & 19 deletions xauth/tests/test_authentication_backend.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework import status
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework.test import APITestCase

from xauth import authentication

Expand Down Expand Up @@ -34,22 +32,6 @@ def test_get_user_with_None_username_and_None_password(self):
user = self.backend.get_user_with_username_and_password(username=None, password=None)
self.assertIsNone(user)

def test_get_post_request_username_and_password(self):
_username = 'user'
_password = 'password'
factory = APIRequestFactory()
from xauth import views
view = views.SignInView.as_view()
request = factory.post(reverse('xauth:signin'), data={
'username': _username,
'password': _password,
})
response = view(request)
self.assertEqual(response.status_code, status.HTTP_200_OK)
# username, password = self.backend.get_post_request_username_and_password(request)
# self.assertEqual(username, _username)
# self.assertEqual(password, _password)

def test_get_basic_auth_username_and_password(self):
from requests.auth import _basic_auth_str
_username, _password = 'user', 'password'
Expand Down
7 changes: 3 additions & 4 deletions xauth/tests/test_signin_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ def assert_post_request_auth(self, _username, _password, expect_status_code, exp
})
response_data = response.data
self.assertEqual(response.status_code, expect_status_code)
if expect_null_payload:
self.assertIsNotNone(get_response_data_message(response))
else:
self.assertIsNotNone(get_response_data_payload(response))
self.assertIsNotNone(
get_response_data_message(response) if expect_null_payload else get_response_data_payload(response))
return response

def assert_basic_auth(self, _username, _password, expect_status_code, expect_null_payload: bool = True):
from requests.auth import _basic_auth_str
Expand Down
3 changes: 2 additions & 1 deletion xauth/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re

from django.contrib.auth import logout
from django.contrib.auth import logout, login
from django.contrib.auth.models import AnonymousUser
from django.db.models import Q
from rest_framework import permissions, generics, views, status, viewsets
Expand Down Expand Up @@ -67,6 +67,7 @@ class SignInView(views.APIView):
def post(self, request, format=None):
# authentication logic is by default handled by the auth-backend
user = request.user
login(request, user)
user.update_or_create_access_log(force_create=True)
serializer = self.serializer_class(user, context={'request': request}, )
return get_wrapped_response(Response(serializer.data, status=status.HTTP_200_OK))
Expand Down

0 comments on commit 9121e35

Please sign in to comment.