mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Updates the superuser management command to better handle existing super users
This commit is contained in:
		| @@ -11,7 +11,14 @@ logger = logging.getLogger("paperless.management.superuser") | |||||||
| class Command(BaseCommand): | class Command(BaseCommand): | ||||||
|  |  | ||||||
|     help = """ |     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( |     """.replace( | ||||||
|         "    ", |         "    ", | ||||||
|         "", |         "", | ||||||
| @@ -19,26 +26,41 @@ class Command(BaseCommand): | |||||||
|  |  | ||||||
|     def handle(self, *args, **options): |     def handle(self, *args, **options): | ||||||
|  |  | ||||||
|         username = os.getenv("PAPERLESS_ADMIN_USER") |         username = os.getenv("PAPERLESS_ADMIN_USER", "admin") | ||||||
|         if not username: |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         mail = os.getenv("PAPERLESS_ADMIN_MAIL", "root@localhost") |         mail = os.getenv("PAPERLESS_ADMIN_MAIL", "root@localhost") | ||||||
|         password = os.getenv("PAPERLESS_ADMIN_PASSWORD") |         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(): |         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( |             self.stdout.write( | ||||||
|                 'Make sure you specified "PAPERLESS_ADMIN_PASSWORD" in your ' |                 self.style.NOTICE( | ||||||
|                 '"docker-compose.env" file.', |                     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.', | ||||||
|  |                 ), | ||||||
|             ) |             ) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import os | import os | ||||||
| import shutil | import shutil | ||||||
|  | from io import StringIO | ||||||
| from unittest import mock | from unittest import mock | ||||||
|  |  | ||||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||||
| @@ -15,53 +16,180 @@ from documents.tests.utils import DirectoriesMixin | |||||||
|  |  | ||||||
| class TestManageSuperUser(DirectoriesMixin, TestCase): | class TestManageSuperUser(DirectoriesMixin, TestCase): | ||||||
|     def reset_environment(self): |     def reset_environment(self): | ||||||
|         if "PAPERLESS_ADMIN_USER" in os.environ: |  | ||||||
|             del os.environ["PAPERLESS_ADMIN_USER"] |  | ||||||
|         if "PAPERLESS_ADMIN_PASSWORD" in os.environ: |         if "PAPERLESS_ADMIN_PASSWORD" in os.environ: | ||||||
|             del os.environ["PAPERLESS_ADMIN_PASSWORD"] |             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: |     def call_command(self, environ, *args, **kwargs): | ||||||
|         super().setUp() |         out = StringIO() | ||||||
|         self.reset_environment() |         with mock.patch.dict(os.environ, environ): | ||||||
|  |             call_command( | ||||||
|     def tearDown(self) -> None: |                 "manage_superuser", | ||||||
|         super().tearDown() |                 "--no-color", | ||||||
|         self.reset_environment() |                 stdout=out, | ||||||
|  |                 stderr=StringIO(), | ||||||
|  |                 **kwargs, | ||||||
|  |             ) | ||||||
|  |         return out.getvalue() | ||||||
|  |  | ||||||
|     def test_no_user(self): |     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.assertEqual(User.objects.count(), 1) | ||||||
|         self.assertTrue(User.objects.filter(username="consumer").exists()) |         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): |     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") |         # count is 2 as there's the consumer | ||||||
|         self.assertTrue(user.check_password("123456")) |         # 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): |     def test_some_superuser_exists(self): | ||||||
|         os.environ["PAPERLESS_ADMIN_USER"] = "new_user" |         """ | ||||||
|         os.environ["PAPERLESS_ADMIN_PASSWORD"] = "123456" |         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" |         self.assertEqual(User.objects.count(), 2) | ||||||
|         os.environ["PAPERLESS_ADMIN_PASSWORD"] = "more_secure_pwd_7645" |         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") |         out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) | ||||||
|         self.assertTrue(user.check_password("more_secure_pwd_7645")) |  | ||||||
|  |         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): |     def test_no_password(self): | ||||||
|         os.environ["PAPERLESS_ADMIN_USER"] = "new_user" |         """ | ||||||
|  |         GIVEN: | ||||||
|         call_command("manage_superuser") |             - No environment data is set | ||||||
|  |         THEN: | ||||||
|  |             - No user is created | ||||||
|  |         """ | ||||||
|  |         out = self.call_command(environ={}) | ||||||
|  |  | ||||||
|         with self.assertRaises(User.DoesNotExist): |         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') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Trenton Holmes
					Trenton Holmes