forked from bsoc-bitbyte/GetIt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'Priyansh61-ticket' into develop
- Loading branch information
Showing
37 changed files
with
710 additions
and
32 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from django.contrib import admin | ||
from django import forms | ||
from django.contrib.auth.admin import UserAdmin | ||
from .models import Account | ||
|
||
|
||
class AccountAddForm(forms.ModelForm): | ||
class Meta: | ||
model = Account | ||
fields = ('email', | ||
'first_name', | ||
'last_name', | ||
'password', | ||
'is_active', | ||
'is_staff') | ||
|
||
|
||
class AccountAdmin(UserAdmin): | ||
add_form = AccountAddForm | ||
list_display = ('email', | ||
'first_name', | ||
'last_name', | ||
'last_login', | ||
'date_joined', | ||
'is_active', | ||
'is_staff') | ||
add_fieldsets = ( | ||
(None, { | ||
'classes': ('wide',), | ||
'fields': ('email', | ||
'first_name', | ||
'last_name', | ||
'password', | ||
'is_active', | ||
'is_staff') | ||
}), | ||
) | ||
|
||
list_display_links = ('email', 'first_name', 'last_name') | ||
readonly_fields = ('last_login', 'date_joined') | ||
ordering = ('-date_joined',) | ||
|
||
filter_horizontal = () | ||
list_filter = () | ||
fieldsets = () | ||
|
||
|
||
admin.site.register(Account, AccountAdmin) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class AccountsConfig(AppConfig): | ||
default_auto_field = 'django.db.models.BigAutoField' | ||
name = 'accounts' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from django.db import models | ||
from django.core.validators import RegexValidator | ||
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager | ||
|
||
|
||
class MyAccountManager(BaseUserManager): | ||
def create_user(self, first_name, last_name, email, password=None): | ||
if not email: | ||
raise ValueError("Users must have an email address") | ||
|
||
user = self.model( | ||
email=self.normalize_email(email), | ||
first_name=first_name, | ||
last_name=last_name | ||
) | ||
|
||
user.set_password(password) | ||
user.save(using=self._db) | ||
|
||
return user | ||
|
||
def create_superuser(self, first_name, last_name, email, password): | ||
user = self.create_user( | ||
email=self.normalize_email(email), | ||
first_name=first_name, | ||
last_name=last_name, | ||
password=password | ||
) | ||
|
||
user.is_admin = True | ||
user.is_active = True | ||
user.is_staff = True | ||
user.is_superadmin = True | ||
|
||
user.save(using=self._db) | ||
|
||
return user | ||
|
||
|
||
class Account(AbstractBaseUser): | ||
phone_regex = RegexValidator(regex=r'^(\+91)?\d{10}$', message="Invalid phone number") | ||
|
||
first_name = models.CharField(max_length=50) | ||
last_name = models.CharField(max_length=50) | ||
email = models.EmailField(unique=True) | ||
phone_number = models.CharField(max_length=13, validators=[phone_regex], blank=True) | ||
address = models.CharField(max_length=128, blank=True) | ||
|
||
# required | ||
date_joined = models.DateTimeField(auto_now_add=True) | ||
last_login = models.DateTimeField(auto_now=True) | ||
is_admin = models.BooleanField(default=False) | ||
is_staff = models.BooleanField(default=False) | ||
is_superadmin = models.BooleanField(default=False) | ||
is_active = models.BooleanField(default=True) | ||
|
||
USERNAME_FIELD = 'email' | ||
REQUIRED_FIELDS = ['first_name', 'last_name'] | ||
|
||
objects = MyAccountManager() | ||
|
||
def __str__(self): | ||
return str(self.email) | ||
|
||
def has_perm(self, perm, obj=None): | ||
return self.is_admin | ||
|
||
def has_module_perms(self, add_label): | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from rest_framework import serializers | ||
from .models import Account | ||
|
||
|
||
class AccountSerializer(serializers.ModelSerializer): | ||
class Meta: | ||
model = Account | ||
fields = ['id', | ||
'first_name', | ||
'last_name', | ||
'email', | ||
'password', | ||
'address', | ||
'phone_number', | ||
'date_joined', | ||
'last_login'] | ||
extra_kwargs = { | ||
'password': {'write_only': True}, | ||
'date_joined': {'read_only': True}, | ||
'last_login': {'read_only': True}, | ||
} | ||
|
||
def create(self, validated_data): | ||
password = validated_data.pop('password', None) | ||
|
||
if not password: | ||
raise serializers.ValidationError('Password is required') | ||
|
||
account = self.Meta.model(**validated_data) | ||
account.set_password(password) | ||
account.save() | ||
|
||
return account |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import pytest | ||
from rest_framework.test import APIClient | ||
from rest_framework import status | ||
from .models import Account | ||
|
||
account_data = { | ||
"email": "test@email.com", | ||
"password": "testpassword", | ||
"first_name": "test", | ||
"last_name": "account", | ||
"phone_number": "1234567890", | ||
"address": "test address", | ||
} | ||
|
||
|
||
@pytest.fixture | ||
def api_client(): | ||
account = Account.objects.create(**account_data) | ||
client = APIClient() | ||
client.force_authenticate(user=account) | ||
return client | ||
|
||
|
||
@pytest.mark.django_db | ||
def testCreateAccountView_validAccountDetails_accountCreationSuccesful(): | ||
# Arrange | ||
client = APIClient() | ||
|
||
# Act | ||
response = client.post('/api/accounts/', account_data, format='json') | ||
|
||
print(response.data) | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_201_CREATED | ||
assert Account.objects.count() == 1 | ||
assert response.data['email'] == account_data['email'] | ||
|
||
# check that password is not returned and the stored password is hashed | ||
assert 'password' not in response.data | ||
assert Account.objects.get().password != account_data['password'] | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize('field', ['email', 'password', 'first_name', 'last_name']) | ||
def testCreateAccountView_missingRequiredDetails_returnsBadRequest(field): | ||
# Arrange | ||
client = APIClient() | ||
data = account_data.copy() | ||
data.pop(field) | ||
|
||
# Act | ||
response = client.post('/api/accounts/', data, format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize('new_email', ['test@email.com', 'testemail']) | ||
def testCreateAccountView_invalidOrDuplicateEmail_returnsBadRequest(new_email): | ||
# Arrange | ||
client = APIClient() | ||
client.post('/api/accounts/', account_data, format='json') | ||
data = account_data.copy() | ||
data['email'] = new_email | ||
|
||
# Act | ||
response = client.post('/api/accounts/', data, format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
|
||
|
||
@pytest.mark.django_db | ||
def testRetrieveLoggedInAccountView_userLoggedIn_returnsAccountDetails(api_client): | ||
# Act | ||
response = api_client.get('/api/accounts/me/', format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_200_OK | ||
assert response.data['email'] == account_data['email'] | ||
|
||
|
||
@pytest.mark.django_db | ||
def testRetrieveLoggedInAccountView_userNotLoggedIn_returnsForbidden(): | ||
# Arrange | ||
client = APIClient() | ||
|
||
# Act | ||
response = client.get('/api/accounts/me/', format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_403_FORBIDDEN | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize('field', ['email', 'first_name', 'last_name', 'address']) | ||
def testUpdateLogInAccountView_userLoggedIn_updateSuccesful(api_client, field): | ||
# Arrange | ||
data = { | ||
field: f'new{account_data[field]}' | ||
} | ||
|
||
# Act | ||
response = api_client.put('/api/accounts/me/', data, format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_200_OK | ||
assert response.data[field] == data[field] | ||
|
||
|
||
@pytest.mark.django_db | ||
def testUpdateLogInAccountView_userNotLoggedIn_returnsForbidden(): | ||
# Arrange | ||
client = APIClient() | ||
|
||
# Act | ||
response = client.put('/api/accounts/me/', {}, format='json') | ||
|
||
# Assert | ||
assert response.status_code == status.HTTP_403_FORBIDDEN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from django.urls import path | ||
from .views import CreateAccountView, RetrieveUpdateLoggedInAccountView | ||
|
||
urlpatterns = [ | ||
path('', CreateAccountView.as_view()), | ||
path('me/', RetrieveUpdateLoggedInAccountView.as_view()), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from rest_framework.generics import CreateAPIView | ||
from rest_framework.views import APIView | ||
from rest_framework.response import Response | ||
from rest_framework.permissions import IsAuthenticated | ||
from .serializers import AccountSerializer | ||
from .models import Account | ||
|
||
|
||
class CreateAccountView(CreateAPIView): | ||
""" View to create accounts """ | ||
queryset = Account.objects.all() | ||
serializer_class = AccountSerializer | ||
|
||
|
||
class RetrieveUpdateLoggedInAccountView(APIView): | ||
""" View to retrieve and change logged in account """ | ||
permission_classes = (IsAuthenticated,) | ||
|
||
def get(self, request): | ||
serializer = AccountSerializer(request.user) | ||
return Response(serializer.data) | ||
|
||
def put(self, request): | ||
# let update be partial | ||
serializer = AccountSerializer(request.user, data=request.data, partial=True) | ||
if serializer.is_valid(): | ||
serializer.save() | ||
return Response(serializer.data) | ||
return Response(serializer.errors) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from django.urls import path | ||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView | ||
|
||
|
||
urlpatterns = [ | ||
path('', TokenObtainPairView.as_view(), name='token_obtain_pair'), | ||
path('refresh/', TokenRefreshView.as_view(), name='token_refresh'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.