Something went wrong on our end
test_registration.py 14.73 KiB
import urllib.parse
from unittest.mock import call, patch
from django.contrib import auth
from django.contrib.auth.tokens import default_token_generator
from django.core import mail
from django.test import override_settings
from django.urls import reverse
from rest_framework import status
from arkindex.documents.models import Corpus
from arkindex.project.default_corpus import DEFAULT_CORPUS_TYPES
from arkindex.project.tests import FixtureAPITestCase
from arkindex.users.models import Group, Right, Role, Scope, User
class TestRegistration(FixtureAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create_user("email@address.com", "P4$5w0Rd")
def test_retrieve_requires_login(self):
response = self.client.get(reverse("api:user-retrieve"))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
# Feature flags should be included
self.assertIsInstance(response.json().get("features"), dict)
def test_update_requires_login(self):
response = self.client.put(
reverse("api:user-retrieve"),
data={"password": "N€wP4$5w0Rd"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_logout_requires_login(self):
response = self.client.delete(reverse("api:user-retrieve"))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_retrieve(self):
self.client.force_login(self.user)
response = self.client.get(reverse("api:user-retrieve"))
self.assertEqual(response.status_code, status.HTTP_200_OK)
data = response.json()
self.assertEqual(data["email"], "email@address.com")
self.assertEqual(data["is_admin"], False)
self.assertNotIn("password", data)
def test_update_password(self):
self.client.force_login(self.user)
response = self.client.patch(
reverse("api:user-retrieve"),
data={"password": "N€wP4$5w0Rd"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.user.refresh_from_db()
self.assertTrue(self.user.check_password("N€wP4$5w0Rd"))
def test_update_display_name(self):
self.client.force_login(self.user)
response = self.client.patch(
reverse("api:user-retrieve"),
data={"display_name": "There was a typo in my name"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.user.refresh_from_db()
self.assertEqual(self.user.display_name, "There was a typo in my name")
def test_logout(self):
self.client.force_login(self.user)
response = self.client.delete(reverse("api:user-retrieve"))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(auth.get_user(self.client).is_authenticated)
def test_login_wrong_email(self):
response = self.client.post(
reverse("api:user-login"),
data={"email": "lol@lol.lol", "password": "password"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertDictEqual(response.json(), {"detail": "Incorrect authentication credentials."})
self.assertFalse(auth.get_user(self.client).is_authenticated)
def test_login_wrong_password(self):
response = self.client.post(
reverse("api:user-login"),
data={"email": "email@address.com", "password": "wrongpassword"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertDictEqual(response.json(), {"detail": "Incorrect authentication credentials."})
self.assertFalse(auth.get_user(self.client).is_authenticated)
def test_login_email_uppercase_letters(self):
"""
Asserts the endpoint is case insensitive for the email
"""
response = self.client.post(
reverse("api:user-login"),
data={"email": "eMaIL@adDreSs.cOm", "password": "P4$5w0Rd"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(auth.get_user(self.client).is_authenticated)
self.assertEqual(auth.get_user(self.client).email, "email@address.com")
def test_login(self):
response = self.client.post(
reverse("api:user-login"),
data={"email": "email@address.com", "password": "P4$5w0Rd"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(auth.get_user(self.client).is_authenticated)
self.assertEqual(auth.get_user(self.client).email, "email@address.com")
@patch("arkindex.users.managers.BaseACLManager.filter_rights", return_value=Corpus.objects.none())
def test_email_verification(self, filter_rights_mock):
newuser = User.objects.create_user("newuser@example.com", password="hunter2")
self.assertFalse(newuser.verified_email)
self.assertTrue(newuser.has_usable_password())
corpora = list(Corpus.objects.all().values_list("id", flat=True))
response = self.client.get("{}?{}".format(
reverse("api:user-token"),
urllib.parse.urlencode({
"email": "newuser@example.com",
"token": default_token_generator.make_token(newuser),
})),
)
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
newuser.refresh_from_db()
self.assertTrue(newuser.verified_email)
self.assertEqual(filter_rights_mock.call_count, 1)
self.assertEqual(filter_rights_mock.call_args, call(newuser, Corpus, Role.Admin.value))
# Assert a trial corpus is created for the new user
new_corpus = Corpus.objects.exclude(id__in=corpora).get()
self.assertEqual(new_corpus.name, "My Project")
self.assertEqual(new_corpus.description, "Project for newuser@example.com")
membership = new_corpus.memberships.get()
self.assertEqual(membership.user, newuser)
self.assertEqual(membership.level, Role.Admin.value)
# Assert defaults types are set on the new corpus
self.assertCountEqual(
list(new_corpus.types.values(
"slug",
"display_name",
"folder",
"color",
)),
[{
"folder": False,
**values
} for values in DEFAULT_CORPUS_TYPES]
)
self.assertCountEqual(
list(newuser.user_scopes.values_list("scope", flat=True)),
[Scope.CreateIIIFImage, Scope.UploadS3Image],
)
def test_email_verification_default_group(self):
"""
If settings.SIGNUP_DEFAULT_GROUP is defined, then upon email verification the user
is added to this group
"""
test_group = Group.objects.first()
newuser = User.objects.create_user("newuser@example.com", password="hunter2")
self.assertFalse(newuser.verified_email)
with (self.settings(SIGNUP_DEFAULT_GROUP=str(test_group.id)), self.assertNumQueries(15)):
response = self.client.get("{}?{}".format(
reverse("api:user-token"),
urllib.parse.urlencode({
"email": "newuser@example.com",
"token": default_token_generator.make_token(newuser),
})),
)
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
newuser.refresh_from_db()
self.assertTrue(newuser.verified_email)
self.assertTrue(Right.objects.filter(user=newuser, content_id=test_group.id, level=Role.Guest.value).exists())
def test_email_verification_default_group_doesnt_exist(self):
newuser = User.objects.create_user("newuser@example.com", password="hunter2")
self.assertFalse(newuser.verified_email)
with (
self.settings(SIGNUP_DEFAULT_GROUP="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
self.assertNumQueries(10),
self.assertRaises(Group.DoesNotExist)
):
self.client.get("{}?{}".format(
reverse("api:user-token"),
urllib.parse.urlencode({
"email": "newuser@example.com",
"token": default_token_generator.make_token(newuser),
})),
)
def test_email_verification_no_password(self):
# A user with a verified email but no usable password may not be granted a trial corpus
newuser = User.objects.create_user("newuser@example.com")
self.assertFalse(newuser.verified_email)
self.assertFalse(newuser.has_usable_password())
corpora = Corpus.objects.all().values_list("id", flat=True)
response = self.client.get("{}?{}".format(
reverse("api:user-token"),
urllib.parse.urlencode({
"email": "newuser@example.com",
"token": default_token_generator.make_token(newuser),
})),
)
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
newuser.refresh_from_db()
self.assertTrue(newuser.verified_email)
self.assertFalse(Corpus.objects.exclude(id__in=corpora).exists())
def test_email_verification_already_admin(self):
user = User.objects.get(email="user@user.fr")
self.assertTrue(user.verified_email)
self.assertEqual(user.rights.filter(level__gte=Role.Admin.value).exists(), True)
corpora = list(Corpus.objects.all().values_list("id", flat=True))
response = self.client.get("{}?{}".format(
reverse("api:user-token"),
urllib.parse.urlencode({
"email": "user@user.fr",
"token": default_token_generator.make_token(user),
})),
)
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
# Assert no trial corpus is created
new_corpus = Corpus.objects.exclude(id__in=corpora)
self.assertFalse(new_corpus.exists())
def test_email_verification_no_args(self):
response = self.client.get(reverse("api:user-token"))
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_create_no_password(self):
response = self.client.post(
reverse("api:user-new"),
data={"display_name": "New user", "email": "newuser@example.com"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(auth.get_user(self.client).is_authenticated)
self.assertEqual(auth.get_user(self.client).email, "newuser@example.com")
user = User.objects.get_by_natural_key("newuser@example.com")
self.assertFalse(user.verified_email)
self.assertFalse(user.user_scopes.exists())
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["newuser@example.com"])
def test_create(self):
response = self.client.post(
reverse("api:user-new"),
data={"display_name": "New user", "email": "newuser@example.com", "password": "myVerySecretPassword"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(auth.get_user(self.client).is_authenticated)
self.assertEqual(auth.get_user(self.client).email, "newuser@example.com")
user = User.objects.get_by_natural_key("newuser@example.com")
self.assertFalse(user.verified_email)
self.assertFalse(user.user_scopes.exists())
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["newuser@example.com"])
self.assertTrue(user.check_password("myVerySecretPassword"))
def test_register_wrong_password(self):
wrong = {
"P@SsWrD": ["This password is too short. It must contain at least 8 characters."],
"42133742": ["This password is entirely numeric."],
"example.com": ["The password is too similar to the email address."],
"pikachu1": ["This password is too common."]
}
for pwd, messages in wrong.items():
response = self.client.post(
reverse("api:user-new"),
data={"display_name": "New user", "email": "newuser@example.com", "password": pwd},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json(), {"password": messages})
def test_register_wrong_fields(self):
response = self.client.post(
reverse("api:user-new"),
data={
"display_name": "A" * 1024,
"email": "",
"password": ""
},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {
"display_name": ["Ensure this field has no more than 120 characters."],
"email": ["This field may not be blank."],
"password": ["This field may not be blank."]
})
@override_settings(ARKINDEX_FEATURES={"signup": False})
def test_create_no_signup(self):
response = self.client.post(
reverse("api:user-new"),
data={"email": "newuser@example.com", "password": "myVerySecretPassword"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertListEqual(response.json(), ["Registration has been disabled on this instance."])
def test_register_existing_user(self):
email = "email@address.com"
self.assertTrue(User.objects.filter(email=email).exists())
response = self.client.post(
reverse("api:user-new"),
data={"display_name": "New user", "email": email, "password": "myVerySecretPassword"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {"email": ["An user with this email address already exists."]})
# Asserts that the check is insensitive on the email field
email = "eMaIL@adDreSs.cOm"
self.assertTrue(User.objects.filter(email=email).exists())
response = self.client.post(
reverse("api:user-new"),
data={"display_name": "New user", "email": email, "password": "myVerySecretPassword"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {"email": ["An user with this email address already exists."]})