Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/django.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ jobs:
- name: Run Tests
run: |
echo "Running tests in example! For now!"
cd example
pytest
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ build-backend = 'setuptools.build_meta'

[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "tests.settings"
python_files = ["tests.py", "test_*.py", "*_tests.py"]
python_files = ["tests.py", "test_*.py", "*_tests.py"]
django_find_project = false
pythonpath = "."
testpaths = "tests"
norecursedirs = ["example", "build", "dist", "*.egg"]
38 changes: 38 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import uuid

from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models


class EmailUserManager(BaseUserManager):
"""
Custom user manager for email-based authentication
"""

def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user


class EmailUser(AbstractUser):
"""
Custom user model that uses email as the username field
"""

username = None # Remove username field
email = models.EmailField(unique=True)
secret = models.CharField(max_length=256, default=uuid.uuid4)

USERNAME_FIELD = "email"
REQUIRED_FIELDS = [] # Remove email from required fields since it's the username

objects = EmailUserManager()

class Meta:
app_label = "tests"
8 changes: 4 additions & 4 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"django.contrib.sessions",
"django.contrib.messages",
"rest_framework",
"tests",
"django_drf_jwt", # Your package
"myuser",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -52,10 +52,10 @@

REST_FRAMEWORK = {"DEFAULT_AUTHENTICATION_CLASSES": ("django_drf_jwt.authentication.JWTAuthentication",)}

AUTH_USER_MODEL = "myuser.MyUser"

# JWT DATA
JWT_DRF = {
# JWT_USER_SECRET_FIELD - MUST BE DEFINED - This must be filed in User object
"JWT_USER_SECRET_FIELD": "secret",
"JWT_USER_SECRET_FIELD": "secret", # for testing purposes we can use last_name as secret field
}

AUTH_USER_MODEL = "tests.EmailUser"
19 changes: 12 additions & 7 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse

from rest_framework.test import APIClient

from myuser.models import MyUser

User = get_user_model()


@pytest.fixture
def create_user():
email = "testuser@test.com"
password = "somepassword123"
user = MyUser.objects.create_user(email=email)
user = User.objects.create_user(email=email)
user.USERNAME_FIELD = "email"
user.set_password(password)
user.save()
return email, password
user.secret = "somesecret"
return email, password, user


GET_TOKEN_URL = reverse("get_token")
Expand All @@ -40,7 +44,7 @@ def test_get_token_bad_credentials(request_data, expected_errors):

@pytest.mark.django_db
def test_get_token(create_user):
email, password = create_user
email, password, *_ = create_user
client = APIClient()
response = client.post(GET_TOKEN_URL, {"email": email, "password": password})
assert response.status_code == 201
Expand All @@ -50,12 +54,13 @@ def test_get_token(create_user):

@pytest.mark.django_db
def test_revoke_token(create_user):
email, password = create_user
email, password, user = create_user
old_secret = user.secret
client = APIClient()
response = client.post(GET_TOKEN_URL, {"email": email, "password": password})
token = response.json().get("token")
client.credentials(HTTP_AUTHORIZATION="JWT " + token)
response = client.post(reverse("revoke_token"), {})
assert response.status_code == 201
user = MyUser.objects.get(email=email)
assert user.secret != token, "Expect secret to be changed after revoking token"
user = User.objects.get(email=email)
assert user.secret != old_secret, "Expect secret to be changed after revoking token"