Add JWT auth with per-user data isolation and account settings.
Users can register, log in, and manage profile/password in a personal account page; server data is scoped by owner across contacts, maps, tags, and import. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import pytest
|
||||
from django.test import override_settings
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
|
||||
JWT_REST_FRAMEWORK = {
|
||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||
'PAGE_SIZE': 100,
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def jwt_api_client():
|
||||
with override_settings(USE_JWT_AUTH=True, REST_FRAMEWORK=JWT_REST_FRAMEWORK):
|
||||
api_settings.reload()
|
||||
client = APIClient()
|
||||
yield client
|
||||
api_settings.reload()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_register_and_isolated_contacts(jwt_api_client):
|
||||
reg = jwt_api_client.post(
|
||||
'/api/v1/auth/register/',
|
||||
{'username': 'alice', 'password': 'strong-pass-1'},
|
||||
format='json',
|
||||
)
|
||||
assert reg.status_code == 201
|
||||
assert reg.data['user']['username'] == 'alice'
|
||||
token = reg.data['access']
|
||||
|
||||
create = jwt_api_client.post(
|
||||
'/api/v1/contacts/',
|
||||
{'name': 'Контакт Alice'},
|
||||
format='json',
|
||||
HTTP_AUTHORIZATION=f'Bearer {token}',
|
||||
)
|
||||
assert create.status_code == 201
|
||||
|
||||
reg_b = jwt_api_client.post(
|
||||
'/api/v1/auth/register/',
|
||||
{'username': 'bob', 'password': 'strong-pass-2'},
|
||||
format='json',
|
||||
)
|
||||
token_b = reg_b.data['access']
|
||||
|
||||
alice_list = jwt_api_client.get(
|
||||
'/api/v1/contacts/',
|
||||
HTTP_AUTHORIZATION=f'Bearer {token}',
|
||||
)
|
||||
bob_list = jwt_api_client.get(
|
||||
'/api/v1/contacts/',
|
||||
HTTP_AUTHORIZATION=f'Bearer {token_b}',
|
||||
)
|
||||
assert alice_list.data['count'] == 1
|
||||
assert bob_list.data['count'] == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_unauthenticated_api_denied(jwt_api_client, sample_contact):
|
||||
response = jwt_api_client.get('/api/v1/contacts/')
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_update_profile_and_password(jwt_api_client):
|
||||
reg = jwt_api_client.post(
|
||||
'/api/v1/auth/register/',
|
||||
{'username': 'carol', 'email': 'carol@test.com', 'password': 'strong-pass-1'},
|
||||
format='json',
|
||||
)
|
||||
token = reg.data['access']
|
||||
auth = {'HTTP_AUTHORIZATION': f'Bearer {token}'}
|
||||
|
||||
profile = jwt_api_client.patch(
|
||||
'/api/v1/auth/me/',
|
||||
{
|
||||
'username': 'carol_new',
|
||||
'email': 'new@test.com',
|
||||
'current_password': 'strong-pass-1',
|
||||
},
|
||||
format='json',
|
||||
**auth,
|
||||
)
|
||||
assert profile.status_code == 200
|
||||
assert profile.data['username'] == 'carol_new'
|
||||
assert profile.data['email'] == 'new@test.com'
|
||||
|
||||
password = jwt_api_client.post(
|
||||
'/api/v1/auth/me/password/',
|
||||
{
|
||||
'current_password': 'strong-pass-1',
|
||||
'new_password': 'strong-pass-9',
|
||||
},
|
||||
format='json',
|
||||
**auth,
|
||||
)
|
||||
assert password.status_code == 200
|
||||
|
||||
login = jwt_api_client.post(
|
||||
'/api/v1/auth/token/',
|
||||
{'username': 'carol_new', 'password': 'strong-pass-9'},
|
||||
format='json',
|
||||
)
|
||||
assert login.status_code == 200
|
||||
Reference in New Issue
Block a user