From f71b28856bd28954ee0cad296201becc0ff12320 Mon Sep 17 00:00:00 2001 From: Andrzej Pragacz Date: Mon, 24 Jul 2023 01:15:50 +0200 Subject: [PATCH] Add skipped test_ok_with_user_with_relations test (#259) --- tests/helpers/api_views.py | 8 +-- .../custom_users/migrations/0001_initial.py | 52 +++++++++++++++---- tests/testapps/custom_users/models.py | 13 +++++ tests/testapps/custom_users/serializers.py | 21 ++++++++ .../api/views/register/test_register.py | 27 ++++++++++ tests/unit_tests/conftest.py | 6 +++ 6 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 tests/testapps/custom_users/serializers.py diff --git a/tests/helpers/api_views.py b/tests/helpers/api_views.py index c2929487..b6c5207f 100644 --- a/tests/helpers/api_views.py +++ b/tests/helpers/api_views.py @@ -21,11 +21,11 @@ def __init__(self, view_provider: ViewProvider): def view_url(self): return self._view_provider.view_url - def create_post_request(self, data=None): - return self._factory.post(self.view_url, data) + def create_post_request(self, data=None, format=None): # noqa: E501 pylint: disable=redefined-builtin + return self._factory.post(self.view_url, data=data, format=format) - def create_patch_request(self, data=None): - return self._factory.patch(self.view_url, data) + def create_patch_request(self, data=None, format=None): # noqa: E501 pylint: disable=redefined-builtin + return self._factory.patch(self.view_url, data=data, format=format) def create_get_request(self): return self._factory.get(self.view_url) diff --git a/tests/testapps/custom_users/migrations/0001_initial.py b/tests/testapps/custom_users/migrations/0001_initial.py index dd054ff4..4f6e140d 100644 --- a/tests/testapps/custom_users/migrations/0001_initial.py +++ b/tests/testapps/custom_users/migrations/0001_initial.py @@ -1,5 +1,4 @@ -# pylint: disable=invalid-name -# Generated by Django 3.0.3 on 2020-04-01 17:27 +# Generated by Django 4.2.3 on 2023-07-23 06:33 import django.contrib.auth.models import django.contrib.auth.validators @@ -13,10 +12,18 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0001_initial'), + ('auth', '0012_alter_user_first_name_max_length'), ] operations = [ + migrations.CreateModel( + name='Channel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200, unique=True)), + ('description', models.TextField(blank=True)), + ], + ), migrations.CreateModel( name='SimpleEmailBasedUser', fields=[ @@ -44,15 +51,15 @@ class Migration(migrations.Migration): ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('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='_userwithusertype_groups_+', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='_userwithusertype_user_permissions_+', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), - ('user_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='custom_users.UserType')), + ('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='+', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='+', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ('user_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='custom_users.usertype')), ], options={ 'abstract': False, @@ -69,14 +76,39 @@ class Migration(migrations.Migration): ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('email', models.EmailField(blank=True, max_length=254, unique=True, verbose_name='email address')), - ('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='_userwithuniqueemail_groups_+', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='_userwithuniqueemail_user_permissions_+', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ('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='+', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='+', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='UserWithChannel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('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='+', related_query_name='user', to='auth.group', verbose_name='groups')), + ('primary_channel', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='owner', to='custom_users.channel')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='+', related_query_name='user', to='auth.permission', verbose_name='user permissions')), ], options={ 'abstract': False, diff --git a/tests/testapps/custom_users/models.py b/tests/testapps/custom_users/models.py index b3d93a96..0e7eb58b 100644 --- a/tests/testapps/custom_users/models.py +++ b/tests/testapps/custom_users/models.py @@ -54,3 +54,16 @@ class SimpleEmailBasedUser(AbstractBaseUser): unique=True, blank=True, ) + + +class Channel(models.Model): + name = models.CharField(max_length=200, unique=True) + description = models.TextField(blank=True) + + +class UserWithChannel(AbstractUser): + primary_channel = models.OneToOneField( + Channel, + on_delete=models.PROTECT, + related_name="owner", + ) diff --git a/tests/testapps/custom_users/serializers.py b/tests/testapps/custom_users/serializers.py new file mode 100644 index 00000000..4b04ae96 --- /dev/null +++ b/tests/testapps/custom_users/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from rest_registration.api.serializers import DefaultRegisterUserSerializer +from tests.testapps.custom_users.models import Channel + + +class ChannelSerializer(serializers.ModelSerializer): + class Meta: + model = Channel + fields = ["name", "description"] + + +class RegisterUserSerializer(DefaultRegisterUserSerializer): + primary_channel = ChannelSerializer() + + def create(self, validated_data): + channel_data = validated_data.pop("primary_channel") + channel = Channel.objects.create(**channel_data) + validated_data["primary_channel"] = channel + user = super().create(validated_data) + return user diff --git a/tests/unit_tests/api/views/register/test_register.py b/tests/unit_tests/api/views/register/test_register.py index f6500c9f..61d436ff 100644 --- a/tests/unit_tests/api/views/register/test_register.py +++ b/tests/unit_tests/api/views/register/test_register.py @@ -91,6 +91,33 @@ def test_ok( assert_valid_register_verification_email(sent_email, user, timer) +@pytest.mark.skip("TODO: Issue #259") +@pytest.mark.django_db +@override_rest_registration_settings({ + 'REGISTER_SERIALIZER_CLASS': 'tests.testapps.custom_users.serializers.RegisterUserSerializer', # noqa: E501 +}) +def test_ok_with_user_with_relations( + settings_with_user_with_channel, + api_view_provider, api_factory, +): + data = _get_register_user_data(password='testpassword') + data["primary_channel"] = { + "name": "fake-channel", + "description": "blah", + } + request = api_factory.create_post_request(data, format="json") + with capture_sent_emails() as sent_emails, capture_time() as timer: + response = api_view_provider.view_func(request) + assert_response_status_is_created(response) + # Check database state. + user = _get_register_response_user(response) + assert_user_state_matches_data(user, data) + # Check verification e-mail. + assert_one_email_sent(sent_emails) + sent_email = sent_emails[0] + assert_valid_register_verification_email(sent_email, user, timer) + + @pytest.mark.django_db @override_rest_registration_settings({ 'USER_VERIFICATION_ID_FIELD': 'username', diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index b13ed17a..a11e270b 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -100,6 +100,12 @@ def settings_with_user_with_unique_email(): yield settings +@pytest.fixture() +def settings_with_user_with_channel(): + with override_auth_model_settings('custom_users.UserWithChannel'): + yield settings + + @pytest.fixture() def settings_with_coreapi_autoschema(): with override_settings(