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
79 changes: 38 additions & 41 deletions promo_code/user/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by Django 5.2b1 on 2025-02-28 17:01
# Generated by Django 5.2 on 2025-05-01 19:23

import uuid
from django.db import migrations, models


Expand All @@ -8,70 +9,66 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
("auth", "0012_alter_user_first_name_max_length"),
]

operations = [
migrations.CreateModel(
name='User',
name="User",
fields=[
("password", models.CharField(max_length=128, verbose_name="password")),
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'password',
models.CharField(max_length=128, verbose_name='password'),
),
(
'is_superuser',
"is_superuser",
models.BooleanField(
default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
verbose_name='superuser status',
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
('email', models.EmailField(max_length=120, unique=True)),
('name', models.CharField(max_length=100)),
('surname', models.CharField(max_length=120)),
(
'avatar_url',
models.URLField(blank=True, max_length=350, null=True),
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
verbose_name="UUID",
),
),
('other', models.JSONField(default=dict)),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=False)),
('last_login', models.DateTimeField(blank=True, null=True)),
("email", models.EmailField(max_length=120, unique=True)),
("name", models.CharField(max_length=100)),
("surname", models.CharField(max_length=120)),
("avatar_url", models.URLField(blank=True, max_length=350, null=True)),
("other", models.JSONField(default=dict)),
("token_version", models.IntegerField(default=0)),
("is_active", models.BooleanField(default=True)),
("is_staff", models.BooleanField(default=False)),
("last_login", models.DateTimeField(blank=True, null=True)),
(
'groups',
"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',
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',
"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',
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
'abstract': False,
"abstract": False,
},
),
]
18 changes: 0 additions & 18 deletions promo_code/user/migrations/0002_user_token_version.py

This file was deleted.

8 changes: 8 additions & 0 deletions promo_code/user/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import uuid

import django.contrib.auth.models
import django.db.models
import django.utils.timezone
Expand Down Expand Up @@ -38,6 +40,12 @@ class User(
django.contrib.auth.models.AbstractBaseUser,
django.contrib.auth.models.PermissionsMixin,
):
id = django.db.models.UUIDField(
'UUID',
primary_key=True,
default=uuid.uuid4,
editable=False,
)
email = django.db.models.EmailField(
unique=True,
max_length=user.constants.EMAIL_MAX_LENGTH,
Expand Down
1 change: 1 addition & 0 deletions promo_code/user/tests/auth/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def setUpTestData(cls):
cls.refresh_url = django.urls.reverse('api-user:user-token-refresh')
cls.signup_url = django.urls.reverse('api-user:sign-up')
cls.signin_url = django.urls.reverse('api-user:sign-in')
cls.user_profile_url = django.urls.reverse('api-user:user-profile')

def tearDown(self):
user.models.User.objects.all().delete()
Expand Down
Empty file.
Empty file.
126 changes: 126 additions & 0 deletions promo_code/user/tests/user/operations/test_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import rest_framework.status

import user.tests.auth.base


class TestUserProfile(user.tests.auth.base.BaseUserAuthTestCase):
def setUp(self):
super().setUp()
signup_data = {
'name': 'Steve',
'surname': 'Wozniak',
'email': 'creator@apple.com',
'password': 'WhoLivesInCalifornia2000!',
'other': {'age': 23, 'country': 'us'},
}
response = self.client.post(
self.signup_url, signup_data, format='json',
)
token = response.data.get('access')
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + token)
self.initial_token = token

def test_get_profile_initial(self):
response = self.client.get(self.user_profile_url, format='json')
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
expected = {
'name': 'Steve',
'surname': 'Wozniak',
'email': 'creator@apple.com',
'other': {'age': 23, 'country': 'us'},
}
self.assertEqual(response.json(), expected)

def test_patch_profile_update_name_and_surname(self):
payload = {'name': 'John', 'surname': 'Tsal'}
response = self.client.patch(
self.user_profile_url, payload, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
self.assertEqual(response.data.get('name'), 'John')
self.assertEqual(response.data.get('surname'), 'Tsal')

def test_patch_profile_update_avatar_url(self):
payload = {'avatar_url': 'http://nodomain.com/kitten.jpeg'}
response = self.client.patch(
self.user_profile_url, payload, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
self.assertEqual(
response.data.get('avatar_url'), 'http://nodomain.com/kitten.jpeg',
)

def test_patch_password_and_check_persistence(self):
new_password = 'MegaGiant88888@dooRuveS'
self.client.patch(
self.user_profile_url,
{'name': 'John', 'surname': 'Tsal'},
format='json',
)
self.client.patch(
self.user_profile_url,
{'avatar_url': 'http://nodomain.com/kitten.jpeg'},
format='json',
)
response = self.client.patch(
self.user_profile_url, {'password': new_password}, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
data = response.data
self.assertEqual(data.get('name'), 'John')
self.assertEqual(data.get('surname'), 'Tsal')
self.assertEqual(data.get('email'), 'creator@apple.com')
self.assertEqual(data.get('other'), {'age': 23, 'country': 'us'})
self.assertEqual(
data.get('avatar_url'), 'http://nodomain.com/kitten.jpeg',
)

# test old token still valid
response = self.client.get(self.user_profile_url, format='json')
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)

def test_auth_sign_in_old_password_fails(self):
new_password = 'MegaGiant88888@dooRuveS'
response = self.client.patch(
self.user_profile_url, {'password': new_password}, format='json',
)
self.client.credentials()
response = self.client.post(
self.signin_url,
{
'email': 'creator@apple.com',
'password': 'WhoLivesInCalifornia2000!',
},
format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_401_UNAUTHORIZED,
)

def test_auth_sign_in_new_password_succeeds(self):
new_password = 'MegaGiant88888@dooRuveS'
response = self.client.patch(
self.user_profile_url, {'password': new_password}, format='json',
)
self.client.credentials()
response = self.client.post(
self.signin_url,
{
'email': 'creator@apple.com',
'password': 'MegaGiant88888@dooRuveS',
},
format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
Empty file.
81 changes: 81 additions & 0 deletions promo_code/user/tests/user/validations/test_profile_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import parameterized
import rest_framework.status

import user.tests.auth.base


class ProfileAPITestCase(user.tests.auth.base.BaseUserAuthTestCase):
def setUp(self):
super().setUp()
signup_data = {
'name': 'Jack',
'surname': 'Sparrow',
'email': 'sparrow@movie.com',
'password': 'WhoLivesInTheOcean100500!',
'other': {'age': 48, 'country': 'gb'},
}
response = self.client.post(
self.signup_url, signup_data, format='json',
)
token = response.data.get('access')
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + token)

def test_update_profile_empty_name_and_surname(self):
payload = {'name': '', 'surname': ''}
response = self.client.patch(
self.user_profile_url, payload, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_400_BAD_REQUEST,
)

@parameterized.parameterized.expand(
[
('no_scheme', 'notURLcom'),
('only_scheme', 'https://'),
('no_domain', 'https://.com'),
],
)
def test_update_profile_invalid_avatar_url(self, name, url):
payload = {'avatar_url': url}
response = self.client.patch(
self.user_profile_url, payload, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_400_BAD_REQUEST,
)

@parameterized.parameterized.expand(
[
('simple_alpha_num', 'pro100'),
('only_symbols', '!!!!!'),
('only_nums', '1234567890'),
('only_lowercase_chars', 'abcdefghijklmno'),
('only_uppercase-chars', 'ABCDEFGHIJKLMNO'),
('only_symbols_and_nums', '1234567890!@#$%^&*()_+{}|:"<>?'),
('repetitive_chars', 'onlyYOUOOOO!'),
('mixed_short', 'yOu!@1'),
('repeating_pattern', '11111@@@@@aaaaa'),
],
)
def test_update_profile_weak_password(self, name, pwd):
payload = {'password': pwd}
response = self.client.patch(
self.user_profile_url, payload, format='json',
)
self.assertEqual(
response.status_code, rest_framework.status.HTTP_400_BAD_REQUEST,
)

def test_get_profile(self):
response = self.client.get(self.user_profile_url, format='json')
self.assertEqual(
response.status_code, rest_framework.status.HTTP_200_OK,
)
expected = {
'name': 'Jack',
'surname': 'Sparrow',
'email': 'sparrow@movie.com',
'other': {'age': 48, 'country': 'gb'},
}
self.assertEqual(response.json(), expected)