diff --git a/src/documents/management/commands/manage_superuser.py b/src/documents/management/commands/manage_superuser.py index e892f7d22..2f506b54a 100644 --- a/src/documents/management/commands/manage_superuser.py +++ b/src/documents/management/commands/manage_superuser.py @@ -11,7 +11,14 @@ logger = logging.getLogger("paperless.management.superuser") class Command(BaseCommand): help = """ - Creates a Django superuser based on env variables. + Creates a Django superuser: + User named: admin + Email: root@localhost + with password based on env variable. + No superuser will be created, when: + - The username is taken already exists + - A superuser already exists + - PAPERLESS_ADMIN_PASSWORD is not set """.replace( " ", "", @@ -19,26 +26,41 @@ class Command(BaseCommand): def handle(self, *args, **options): - username = os.getenv("PAPERLESS_ADMIN_USER") - if not username: - return - + username = os.getenv("PAPERLESS_ADMIN_USER", "admin") mail = os.getenv("PAPERLESS_ADMIN_MAIL", "root@localhost") password = os.getenv("PAPERLESS_ADMIN_PASSWORD") - # Check if user exists already, leave as is if it does + # Check if there's already a user called admin if User.objects.filter(username=username).exists(): - user: User = User.objects.get_by_natural_key(username) - user.set_password(password) - user.save() - self.stdout.write(f"Changed password of user {username}.") - elif password: - # Create superuser based on env variables - User.objects.create_superuser(username, mail, password) - self.stdout.write(f'Created superuser "{username}" with provided password.') - else: - self.stdout.write(f'Did not create superuser "{username}".') self.stdout.write( - 'Make sure you specified "PAPERLESS_ADMIN_PASSWORD" in your ' - '"docker-compose.env" file.', + self.style.NOTICE( + f"Did not create superuser, a user {username} already exists", + ), + ) + return + + # Check if any superuseruser + # exists already, leave as is if it does + if User.objects.filter(is_superuser=True).count() > 0: + self.stdout.write( + self.style.NOTICE( + "Did not create superuser, the DB already contains superusers", + ), + ) + return + + if password is None: + self.stdout.write( + self.style.ERROR( + "Please check if PAPERLESS_ADMIN_PASSWORD has been" + " set in the environment", + ), + ) + else: + # Create superuser with password based on env variable + User.objects.create_superuser(username, mail, password) + self.stdout.write( + self.style.SUCCESS( + f'Created superuser "{username}" with provided password.', + ), ) diff --git a/src/documents/tests/test_management_superuser.py b/src/documents/tests/test_management_superuser.py index b4e91fd66..4a8bb7bb3 100644 --- a/src/documents/tests/test_management_superuser.py +++ b/src/documents/tests/test_management_superuser.py @@ -1,5 +1,6 @@ import os import shutil +from io import StringIO from unittest import mock from django.contrib.auth.models import User @@ -15,53 +16,180 @@ from documents.tests.utils import DirectoriesMixin class TestManageSuperUser(DirectoriesMixin, TestCase): def reset_environment(self): - if "PAPERLESS_ADMIN_USER" in os.environ: - del os.environ["PAPERLESS_ADMIN_USER"] if "PAPERLESS_ADMIN_PASSWORD" in os.environ: del os.environ["PAPERLESS_ADMIN_PASSWORD"] + if "PAPERLESS_ADMIN_USER" in os.environ: + del os.environ["PAPERLESS_ADMIN_USER"] + if "PAPERLESS_ADMIN_MAIL" in os.environ: + del os.environ["PAPERLESS_ADMIN_MAIL"] - def setUp(self) -> None: - super().setUp() - self.reset_environment() - - def tearDown(self) -> None: - super().tearDown() - self.reset_environment() + def call_command(self, environ, *args, **kwargs): + out = StringIO() + with mock.patch.dict(os.environ, environ): + call_command( + "manage_superuser", + "--no-color", + stdout=out, + stderr=StringIO(), + **kwargs, + ) + return out.getvalue() def test_no_user(self): - call_command("manage_superuser") + """ + GIVEN: + - Environment does not contain admin user info + THEN: + - No admin user is created + """ - # just the consumer user. + out = self.call_command(environ={}) + + # just the consumer user which is created + # during migration self.assertEqual(User.objects.count(), 1) self.assertTrue(User.objects.filter(username="consumer").exists()) + self.assertEqual(User.objects.filter(is_superuser=True).count(), 0) + self.assertEqual( + out, + "Please check if PAPERLESS_ADMIN_PASSWORD has been set in the environment\n", + ) def test_create(self): - os.environ["PAPERLESS_ADMIN_USER"] = "new_user" - os.environ["PAPERLESS_ADMIN_PASSWORD"] = "123456" + """ + GIVEN: + - Environment does contain admin user password + THEN: + - admin user is created + """ - call_command("manage_superuser") + out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - user: User = User.objects.get_by_natural_key("new_user") - self.assertTrue(user.check_password("123456")) + # count is 2 as there's the consumer + # user already created during migration + user: User = User.objects.get_by_natural_key("admin") + self.assertEqual(User.objects.count(), 2) + self.assertTrue(user.is_superuser) + self.assertEqual(user.email, "root@localhost") + self.assertEqual(out, 'Created superuser "admin" with provided password.\n') - def test_update(self): - os.environ["PAPERLESS_ADMIN_USER"] = "new_user" - os.environ["PAPERLESS_ADMIN_PASSWORD"] = "123456" + def test_some_superuser_exists(self): + """ + GIVEN: + - A super user already exists + - Environment does contain admin user password + THEN: + - admin user is NOT created + """ + User.objects.create_superuser("someuser", "root@localhost", "password") - call_command("manage_superuser") + out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - os.environ["PAPERLESS_ADMIN_USER"] = "new_user" - os.environ["PAPERLESS_ADMIN_PASSWORD"] = "more_secure_pwd_7645" + self.assertEqual(User.objects.count(), 2) + with self.assertRaises(User.DoesNotExist): + User.objects.get_by_natural_key("admin") + self.assertEqual( + out, + "Did not create superuser, the DB already contains superusers\n", + ) - call_command("manage_superuser") + def test_admin_superuser_exists(self): + """ + GIVEN: + - A super user already exists + - The existing superuser's username is admin + - Environment does contain admin user password + THEN: + - Password remains unchanged + """ + User.objects.create_superuser("admin", "root@localhost", "password") - user: User = User.objects.get_by_natural_key("new_user") - self.assertTrue(user.check_password("more_secure_pwd_7645")) + out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) + + self.assertEqual(User.objects.count(), 2) + user: User = User.objects.get_by_natural_key("admin") + self.assertTrue(user.check_password("password")) + self.assertEqual(out, "Did not create superuser, a user admin already exists\n") + + def test_admin_user_exists(self): + """ + GIVEN: + - A user already exists with the username admin + - Environment does contain admin user password + THEN: + - Password remains unchanged + - User is not upgraded to superuser + """ + + User.objects.create_user("admin", "root@localhost", "password") + + out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) + + self.assertEqual(User.objects.count(), 2) + user: User = User.objects.get_by_natural_key("admin") + self.assertTrue(user.check_password("password")) + self.assertFalse(user.is_superuser) + self.assertEqual(out, "Did not create superuser, a user admin already exists\n") def test_no_password(self): - os.environ["PAPERLESS_ADMIN_USER"] = "new_user" - - call_command("manage_superuser") + """ + GIVEN: + - No environment data is set + THEN: + - No user is created + """ + out = self.call_command(environ={}) with self.assertRaises(User.DoesNotExist): - User.objects.get_by_natural_key("new_user") + User.objects.get_by_natural_key("admin") + self.assertEqual( + out, + "Please check if PAPERLESS_ADMIN_PASSWORD has been set in the environment\n", + ) + + def test_user_email(self): + """ + GIVEN: + - Environment does contain admin user password + - Environment contains user email + THEN: + - admin user is created + """ + + out = self.call_command( + environ={ + "PAPERLESS_ADMIN_PASSWORD": "123456", + "PAPERLESS_ADMIN_MAIL": "hello@world.com", + }, + ) + + user: User = User.objects.get_by_natural_key("admin") + self.assertEqual(User.objects.count(), 2) + self.assertTrue(user.is_superuser) + self.assertEqual(user.email, "hello@world.com") + self.assertEqual(user.username, "admin") + self.assertEqual(out, 'Created superuser "admin" with provided password.\n') + + def test_user_username(self): + """ + GIVEN: + - Environment does contain admin user password + - Environment contains user username + THEN: + - admin user is created + """ + + out = self.call_command( + environ={ + "PAPERLESS_ADMIN_PASSWORD": "123456", + "PAPERLESS_ADMIN_MAIL": "hello@world.com", + "PAPERLESS_ADMIN_USER": "super", + }, + ) + + user: User = User.objects.get_by_natural_key("super") + self.assertEqual(User.objects.count(), 2) + self.assertTrue(user.is_superuser) + self.assertEqual(user.email, "hello@world.com") + self.assertEqual(user.username, "super") + self.assertEqual(out, 'Created superuser "super" with provided password.\n')