Skip to content

Commit

Permalink
fix error when creating user with no password
Browse files Browse the repository at this point in the history
fix AttributeError: 'NoneType' object has no attribute 'lower' when creating a user with password field missing from the payload
  • Loading branch information
kelvin-muchiri committed Jul 20, 2023
1 parent 5f1b9b5 commit 7168ef3
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 36 deletions.
138 changes: 104 additions & 34 deletions onadata/apps/api/tests/viewsets/test_user_profile_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,40 +291,6 @@ def test_profile_create(self, mock_send_verification_email):
self.assertTrue(user.is_active)
self.assertTrue(user.check_password(password), password)

@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
@override_settings(ENABLE_EMAIL_VERIFICATION=True)
@patch(
(
"onadata.libs.serializers.user_profile_serializer."
"send_verification_email.delay"
)
)
def test_accept_invitaton(self, mock_send_email):
"""An invitation is accepted successfuly"""
self._project_create()
invitation = ProjectInvitation.objects.create(
email="[email protected]",
project=self.project,
role="editor",
)
# user registers using same email as invitation email
data = _profile_data()
del data["name"]
data["email"] = invitation.email
request = self.factory.post(
"/api/v1/profiles",
data=json.dumps(data),
content_type="application/json",
**self.extra,
)
response = self.view(request)
self.assertEqual(response.status_code, 201)
user = User.objects.get(username="deno")
mock_send_email.assert_called_once()
invitation.refresh_from_db()
self.assertEqual(invitation.status, ProjectInvitation.Status.ACCEPTED)
self.assertTrue(EditorRole.user_has_role(user, self.project))

def _create_user_using_profiles_endpoint(self, data):
request = self.factory.post(
"/api/v1/profiles",
Expand Down Expand Up @@ -1488,3 +1454,107 @@ def test_account_activation_emails(self, mock_send_mail):
),
]
)

@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
@override_settings(ENABLE_EMAIL_VERIFICATION=True)
@patch(
(
"onadata.libs.serializers.user_profile_serializer."
"send_verification_email.delay"
)
)
def test_accept_invitaton(self, mock_send_email):
"""An invitation is accepted successfuly"""
self._project_create()
invitation = ProjectInvitation.objects.create(
email="[email protected]",
project=self.project,
role="editor",
)
# user registers using same email as invitation email
data = _profile_data()
del data["name"]
data["email"] = invitation.email
request = self.factory.post(
"/api/v1/profiles",
data=json.dumps(data),
content_type="application/json",
**self.extra,
)
response = self.view(request)
self.assertEqual(response.status_code, 201)
user = User.objects.get(username="deno")
mock_send_email.assert_called_once()
invitation.refresh_from_db()
self.assertEqual(invitation.status, ProjectInvitation.Status.ACCEPTED)
self.assertTrue(EditorRole.user_has_role(user, self.project))

@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
@override_settings(ENABLE_EMAIL_VERIFICATION=True)
@override_settings(
AUTH_PASSWORD_VALIDATORS=[
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa
},
]
)
@patch(
(
"onadata.libs.serializers.user_profile_serializer."
"send_verification_email.delay"
)
)
def test_password_optional(self, mock_send_verification_email):
"""Field `password` is optional"""
# password not provided
data = _profile_data()
del data["name"]
del data["password"]
request = self.factory.post(
"/api/v1/profiles",
data=json.dumps(data),
content_type="application/json",
**self.extra,
)
response = self.view(request)
self.assertEqual(response.status_code, 201)
profile = UserProfile.objects.get(user__username=data["username"])
data["id"] = profile.user.pk
data["gravatar"] = profile.gravatar
data["url"] = "http://testserver/api/v1/profiles/deno"
data["user"] = "http://testserver/api/v1/users/deno"
data["metadata"] = {}
data["metadata"]["last_password_edit"] = profile.metadata["last_password_edit"]
data["joined_on"] = profile.user.date_joined
data["name"] = "%s %s" % ("Dennis", "erama")
self.assertEqual(response.data, data)
self.assertTrue(mock_send_verification_email.called)
user = User.objects.get(username="deno")
self.assertTrue(user.is_active)
# password blank
data = _profile_data()
user.delete()
del data["name"]
data["password"] = ""
request = self.factory.post(
"/api/v1/profiles",
data=json.dumps(data),
content_type="application/json",
**self.extra,
)
response = self.view(request)
self.assertEqual(response.status_code, 201)
profile = UserProfile.objects.get(user__username=data["username"])
data["id"] = profile.user.pk
data["gravatar"] = profile.gravatar
data["url"] = "http://testserver/api/v1/profiles/deno"
data["user"] = "http://testserver/api/v1/users/deno"
data["metadata"] = {}
data["metadata"]["last_password_edit"] = profile.metadata["last_password_edit"]
data["joined_on"] = profile.user.date_joined
data["name"] = "%s %s" % ("Dennis", "erama")
del data["password"]
self.assertEqual(response.data, data)
self.assertTrue(mock_send_verification_email.called)
user = User.objects.get(username="deno")
self.assertTrue(user.is_active)
9 changes: 7 additions & 2 deletions onadata/libs/serializers/user_profile_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,26 @@ def create(self, validated_data):
request = self.context.get("request")
metadata = {}
username = params.get("username")
password = params.get("password1")
site = Site.objects.get(pk=settings.SITE_ID)
new_user = None

try:
new_user = RegistrationProfile.objects.create_inactive_user(
username=username,
password=params.get("password1"),
password=password,
email=params.get("email"),
site=site,
send_email=settings.SEND_EMAIL_ACTIVATION_API,
)
validate_password(params.get("password1"), user=new_user)
except IntegrityError as e:
raise serializers.ValidationError(
_(f"User account {username} already exists")
) from e

try:
validate_password("" if password is None else password, user=new_user)

except ValidationError as e:
# Delete created user object if created
# to allow re-registration
Expand Down

0 comments on commit 7168ef3

Please sign in to comment.