Skip to content

Commit

Permalink
feat(api): add User.outreach_preference
Browse files Browse the repository at this point in the history
  • Loading branch information
peterthomassen committed Jan 19, 2022
1 parent 9f07e2f commit db4934c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 9 deletions.
18 changes: 18 additions & 0 deletions api/desecapi/migrations/0022_user_outreach_preference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-11 19:28

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('desecapi', '0021_authenticatednoopuseraction'),
]

operations = [
migrations.AddField(
model_name='user',
name='outreach_preference',
field=models.BooleanField(default=True),
),
]
1 change: 1 addition & 0 deletions api/desecapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def _limit_domains_default():
created = models.DateTimeField(auto_now_add=True)
limit_domains = models.PositiveIntegerField(default=_limit_domains_default.__func__, null=True, blank=True)
needs_captcha = models.BooleanField(default=True)
outreach_preference = models.BooleanField(default=True)

objects = MyUserManager()

Expand Down
4 changes: 2 additions & 2 deletions api/desecapi/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ class UserSerializer(serializers.ModelSerializer):

class Meta:
model = models.User
fields = ('created', 'email', 'id', 'limit_domains',)
fields = ('created', 'email', 'id', 'limit_domains', 'outreach_preference',)
read_only_fields = ('created', 'email', 'id', 'limit_domains',)

def validate_password(self, value):
Expand All @@ -657,7 +657,7 @@ class RegisterAccountSerializer(UserSerializer):

class Meta:
model = UserSerializer.Meta.model
fields = ('email', 'password', 'domain', 'captcha',)
fields = ('email', 'password', 'domain', 'captcha', 'outreach_preference',)
extra_kwargs = {
'password': {
'write_only': True, # Do not expose password field
Expand Down
39 changes: 33 additions & 6 deletions api/desecapi/tests/test_user_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ def _test_registration(self, email=None, password=None, late_captcha=True, **kwa
self.assertFalse(User.objects.get(email=email).is_active)
self.assertIsNone(User.objects.get(email=email).is_active)
self.assertEqual(User.objects.get(email=email).needs_captcha, late_captcha)
self.assertEqual(User.objects.get(email=email).outreach_preference, kwargs.get('outreach_preference', True))
self.assertPassword(email, password)
confirmation_link = self.assertRegistrationEmail(email)
self.assertConfirmationLinkRedirect(confirmation_link)
Expand Down Expand Up @@ -539,7 +540,9 @@ def test_authenticated_action_redirect_with_invalid_code(self):
self.assertConfirmationLinkRedirect(confirmation_link)

def test_registration(self):
self._test_registration(password=self.random_password())
for outreach_preference in [None, True, False]:
kwargs = dict(outreach_preference=outreach_preference) if outreach_preference is not None else {}
self._test_registration(password=self.random_password(), **kwargs)

def test_registration_trim_email(self):
user_email = ' {} '.format(self.random_username())
Expand Down Expand Up @@ -685,22 +688,46 @@ def _finish_delete_account(self, confirmation_link):
def test_view_account(self):
response = self.client.view_account(self.token)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data.keys(), {'created', 'email', 'id', 'limit_domains'})
self.assertEqual(response.data.keys(), {'created', 'email', 'id', 'limit_domains', 'outreach_preference'})
self.assertEqual(response.data['email'], self.email)
self.assertEqual(response.data['id'], str(User.objects.get(email=self.email).pk))
self.assertEqual(response.data['limit_domains'], settings.LIMIT_USER_DOMAIN_COUNT_DEFAULT)
self.assertTrue(response.data['outreach_preference'])

def test_view_account_read_only(self):
# Should this test ever be removed (to allow writeable fields), make sure to
# add new tests for each read-only field individually (such as limit_domains)!
for method in [self.client.patch, self.client.put, self.client.post, self.client.delete]:
def test_view_account_forbidden_methods(self):
for method in [self.client.post, self.client.delete]:
response = method(
reverse('v1:account'),
{'limit_domains': 99},
HTTP_AUTHORIZATION='Token {}'.format(self.token)
)
self.assertResponse(response, status.HTTP_405_METHOD_NOT_ALLOWED)

def test_view_account_update(self):
user = User.objects.get(email=self.email)
immutable_fields = ('created', 'email', 'id', 'limit_domains', 'password',)
immutable_values = [getattr(user, key) for key in immutable_fields]
outreach_preference = user.outreach_preference

for method in [self.client.patch, self.client.put]:
outreach_preference = not outreach_preference
response = method(
reverse('v1:account'),
{
'created': '2019-10-16T18:09:17.715702Z',
'email': '[email protected]',
'id': '9ab16e5c-805d-4ab1-9030-af3f5a541d47',
'limit_domains': 42,
'password': self.random_password(),
'outreach_preference': outreach_preference,
},
HTTP_AUTHORIZATION='Token {}'.format(self.token)
)
self.assertResponse(response, status.HTTP_200_OK)
user = User.objects.get(email=self.email)
self.assertEqual(outreach_preference, user.outreach_preference) # `outreach_preference` updated
self.assertEqual(immutable_values, [getattr(user, k) for k in immutable_fields]) # read-only fields ignored

def test_reset_password(self):
self._test_reset_password(self.email)

Expand Down
2 changes: 1 addition & 1 deletion api/desecapi/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ def create(self, request, *args, **kwargs):
return Response(data={'detail': message}, status=status.HTTP_202_ACCEPTED)


class AccountView(generics.RetrieveAPIView):
class AccountView(generics.RetrieveUpdateAPIView):
permission_classes = (IsAuthenticated, permissions.TokenNoDomainPolicy,)
serializer_class = serializers.UserSerializer
throttle_scope = 'account_management_passive'
Expand Down

0 comments on commit db4934c

Please sign in to comment.