123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- from django.contrib.auth import get_user_model
- from django.core import mail
- from django.urls import reverse
- from ...conf.test import override_dynamic_settings
- from ...legal.models import Agreement
- from ..models import Ban, Online
- from ..test import UserTestCase
- User = get_user_model()
- class UserCreateTests(UserTestCase):
- """tests for new user registration (POST to /api/users/)"""
- def setUp(self):
- super().setUp()
- Agreement.objects.invalidate_cache()
- self.api_link = "/api/users/"
- def tearDown(self):
- Agreement.objects.invalidate_cache()
- def test_empty_request(self):
- """empty request errors with code 400"""
- response = self.client.post(self.api_link)
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(),
- {
- "username": ["This field is required."],
- "email": ["This field is required."],
- "password": ["This field is required."],
- },
- )
- def test_invalid_data(self):
- """invalid request data errors with code 400"""
- response = self.client.post(
- self.api_link, "false", content_type="application/json"
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(),
- {
- "username": ["This field is required."],
- "email": ["This field is required."],
- "password": ["This field is required."],
- },
- )
- def test_authenticated_request(self):
- """authentiated user request errors with code 403"""
- self.login_user(self.get_authenticated_user())
- response = self.client.post(self.api_link)
- self.assertEqual(response.status_code, 403)
- self.assertEqual(
- response.json(),
- {"detail": "This action is not available to signed in users."},
- )
- @override_dynamic_settings(account_activation="closed")
- def test_registration_off_request(self):
- """registrations off request errors with code 403"""
- response = self.client.post(self.api_link)
- self.assertEqual(response.status_code, 403)
- self.assertEqual(
- response.json(), {"detail": "New users registrations are currently closed."}
- )
- def test_registration_validates_ip_ban(self):
- """api validates ip ban"""
- Ban.objects.create(
- check_type=Ban.IP,
- banned_value="127.*",
- user_message="You can't register account like this.",
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 403)
- def test_registration_validates_ip_registration_ban(self):
- """api validates ip registration-only ban"""
- Ban.objects.create(
- check_type=Ban.IP,
- banned_value="127.*",
- user_message="You can't register account like this.",
- registration_only=True,
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"__all__": ["You can't register account like this."]}
- )
- def test_registration_validates_username(self):
- """api validates usernames"""
- user = self.get_authenticated_user()
- response = self.client.post(
- self.api_link,
- data={
- "username": user.username,
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"username": ["This username is not available."]}
- )
- def test_registration_validates_username_ban(self):
- """api validates username ban"""
- Ban.objects.create(
- banned_value="totally*",
- user_message="You can't register account like this.",
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"username": ["You can't register account like this."]}
- )
- def test_registration_validates_username_registration_ban(self):
- """api validates username registration-only ban"""
- Ban.objects.create(
- banned_value="totally*",
- user_message="You can't register account like this.",
- registration_only=True,
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"username": ["You can't register account like this."]}
- )
- def test_registration_validates_email(self):
- """api validates usernames"""
- user = self.get_authenticated_user()
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": user.email,
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"email": ["This e-mail address is not available."]}
- )
- def test_registration_validates_email_ban(self):
- """api validates email ban"""
- Ban.objects.create(
- check_type=Ban.EMAIL,
- banned_value="lorem*",
- user_message="You can't register account like this.",
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"email": ["You can't register account like this."]}
- )
- def test_registration_validates_email_registration_ban(self):
- """api validates email registration-only ban"""
- Ban.objects.create(
- check_type=Ban.EMAIL,
- banned_value="lorem*",
- user_message="You can't register account like this.",
- registration_only=True,
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"email": ["You can't register account like this."]}
- )
- def test_registration_requires_password(self):
- """api uses django's validate_password to validate registrations"""
- response = self.client.post(
- self.api_link,
- data={"username": "User", "email": "loremipsum@dolor.met", "password": ""},
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(response.json(), {"password": ["This field is required."]})
- def test_registration_validates_password(self):
- """api uses django's validate_password to validate registrations"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "l.o.r.e.m.i.p.s.u.m@gmail.com",
- "password": "123",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(),
- {
- "email": ["This email is not allowed."],
- "password": [
- (
- "This password is too short. "
- "It must contain at least 7 characters."
- ),
- "This password is entirely numeric.",
- ],
- },
- )
- def test_registration_validates_password_similiarity(self):
- """api uses validate_password to validate registrations"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "BobBoberson",
- "email": "l.o.r.e.m.i.p.s.u.m@gmail.com",
- "password": "BobBoberson",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(),
- {
- "email": ["This email is not allowed."],
- "password": ["The password is too similar to the username."],
- },
- )
- @override_dynamic_settings(
- captcha_type="qa", qa_question="Test", qa_answers="Lorem\nIpsum"
- )
- def test_registration_validates_captcha(self):
- """api validates captcha"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "captcha": "dolor",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(response.json(), {"captcha": ["Entered answer is incorrect."]})
- # valid captcha
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "captcha": "ipSUM",
- },
- )
- self.assertEqual(response.status_code, 200)
- @override_dynamic_settings(
- captcha_type="qa", qa_question="", qa_answers="Lorem\n\nIpsum"
- )
- def test_qacaptcha_handles_empty_answers(self):
- """api validates captcha"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "captcha": "",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(response.json(), {"captcha": ["Entered answer is incorrect."]})
- def test_registration_check_agreement(self):
- """api checks agreement"""
- agreement = Agreement.objects.create(
- type=Agreement.TYPE_TOS, text="Lorem ipsum", is_active=True
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"terms_of_service": ["This agreement is required."]}
- )
- # invalid agreement id
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "terms_of_service": agreement.id + 1,
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(), {"terms_of_service": ["This agreement is required."]}
- )
- # valid agreement id
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "terms_of_service": agreement.id,
- },
- )
- self.assertEqual(response.status_code, 200)
- user = User.objects.get(email="loremipsum@dolor.met")
- self.assertEqual(user.agreements, [agreement.id])
- self.assertEqual(user.useragreement_set.count(), 1)
- def test_registration_ignore_inactive_agreement(self):
- """api ignores inactive agreement"""
- Agreement.objects.create(
- type=Agreement.TYPE_TOS, text="Lorem ipsum", is_active=False
- )
- response = self.client.post(
- self.api_link,
- data={
- "username": "totallyNew",
- "email": "loremipsum@dolor.met",
- "password": "LoremP4ssword",
- "terms_of_service": "",
- },
- )
- self.assertEqual(response.status_code, 200)
- user = User.objects.get(email="loremipsum@dolor.met")
- self.assertEqual(user.agreements, [])
- self.assertEqual(user.useragreement_set.count(), 0)
- def test_registration_calls_validate_new_registration(self):
- """api uses validate_new_registration to validate registrations"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "l.o.r.e.m.i.p.s.u.m@gmail.com",
- "password": "pas123",
- },
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.json(),
- {
- "email": ["This email is not allowed."],
- "password": [
- "This password is too short. It must contain at least 7 characters."
- ],
- },
- )
- @override_dynamic_settings(account_activation="none")
- def test_registration_creates_active_user(self):
- """api creates active and signed in user on POST"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "user@example.com",
- "password": self.USER_PASSWORD,
- },
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(
- response.json(),
- {"activation": "active", "username": "User", "email": "user@example.com"},
- )
- User.objects.get_by_username("User")
- test_user = User.objects.get_by_email("user@example.com")
- self.assertEqual(Online.objects.filter(user=test_user).count(), 1)
- self.assertTrue(test_user.check_password(self.USER_PASSWORD))
- auth_json = self.client.get(reverse("misago:api:auth")).json()
- self.assertTrue(auth_json["is_authenticated"])
- self.assertEqual(auth_json["username"], "User")
- self.assertIn("Welcome", mail.outbox[0].subject)
- self.assertEqual(test_user.audittrail_set.count(), 1)
- @override_dynamic_settings(account_activation="user")
- def test_registration_creates_inactive_user(self):
- """api creates inactive user on POST"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "user@example.com",
- "password": self.USER_PASSWORD,
- },
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(
- response.json(),
- {"activation": "user", "username": "User", "email": "user@example.com"},
- )
- auth_json = self.client.get(reverse("misago:api:auth")).json()
- self.assertFalse(auth_json["is_authenticated"])
- User.objects.get_by_username("User")
- User.objects.get_by_email("user@example.com")
- self.assertIn("Welcome", mail.outbox[0].subject)
- @override_dynamic_settings(account_activation="admin")
- def test_registration_creates_admin_activated_user(self):
- """api creates admin activated user on POST"""
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "user@example.com",
- "password": self.USER_PASSWORD,
- },
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(
- response.json(),
- {"activation": "admin", "username": "User", "email": "user@example.com"},
- )
- auth_json = self.client.get(reverse("misago:api:auth")).json()
- self.assertFalse(auth_json["is_authenticated"])
- User.objects.get_by_username("User")
- User.objects.get_by_email("user@example.com")
- self.assertIn("Welcome", mail.outbox[0].subject)
- @override_dynamic_settings(account_activation="none")
- def test_registration_creates_user_with_whitespace_password(self):
- """api creates user with spaces around password"""
- password = " %s " % self.USER_PASSWORD
- response = self.client.post(
- self.api_link,
- data={
- "username": "User",
- "email": "user@example.com",
- "password": password,
- },
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(
- response.json(),
- {"activation": "active", "username": "User", "email": "user@example.com"},
- )
- User.objects.get_by_username("User")
- test_user = User.objects.get_by_email("user@example.com")
- self.assertEqual(Online.objects.filter(user=test_user).count(), 1)
- self.assertTrue(test_user.check_password(password))
- self.assertIn("Welcome", mail.outbox[0].subject)
- @override_dynamic_settings(account_activation="none")
- def test_new_registrations_validators_hook_is_used_by_registration_api(
- db, client, mocker
- ):
- def validator(request, cleaned_data, add_error):
- add_error("username", "ERROR FROM PLUGIN")
- mocker.patch(
- "misago.users.validators.hooks.new_registrations_validators", [validator]
- )
- response = client.post(
- "/api/users/",
- {"username": "User", "email": "user@example.com", "password": "PASSW0RD123"},
- )
- assert response.status_code == 400
- assert response.json() == {"username": ["ERROR FROM PLUGIN"]}
|