Repository: Health-Informatics-UoN/carrot-mapper
Pull request #964: Feat/946/default admin
Author: login: g-pechorin
Labels: name: Area: Backend
Created: 2025-03-05T09:57:37Z | Merged: 2025-03-19T18:41:45Z

<!--
INSTRUCTIONS:

1. Please complete all sections detailing an ACTION
2. All tasks must be checked off before merging
-->

<!--
  PR Guidance:
  - 👷‍♀️ Create small PRs. In most cases this will be possible.
  - ✅ Provide tests for your changes.
  - 📝 Use descriptive commit messages.
  - 📗 Update any related documentation and include any relevant screenshots.
-->

<!-- 
  For Work In Progress Pull Requests, please use the Draft PR feature,
  see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
-->


## Pull Request Contents

<!--
ACTION: Delete any content types that don't apply to your pull request
-->

| |
|-|
♻️ Refactor

## Description

Adds a management command, is invoked on setup, which creates a default admin user for the carrot system iff there are 0 users in the database at present.

## Related Issues or other material

- Closes #

closes #946 


## Screenshots, example outputs/behaviour etc.

<!--
ACTION: Add material or delete this section if it's not applicable
-->

## ✅ Added/updated tests?

- [x] This PR contains relevant tests
  - Or doesn't need to per the below explanation

<!--
ACTION: If tests have not been added or updated, explain why here
-->

This functionality relies on reading the django database, performing a single comparison - a test seems redundant.

- [x] I've completed all **actions** and **tasks** detailed in the PR Template


Linked issue #946: Create super user on app install
### Is this the right issue type?

- [x] Yes, I'm planning work for this project team.

### Summary

Adding a default super user for Carrot when it is first installed would be very helpful.

Currently the install documentation asks that this is done locally: https://carrot.ac.uk/mapper/deployment/azure/steps#backend-app

```
A Django superuser also need creating by connecting to the Backend app and run the command:

python manage.py createsuperuser
```

We would like to do this through a management command, that will check if any users exist - and if they do not create one. This prevents super users being created by mistake.

The default credentials should be:

username: `admin`
password: `Password123!` (this should be capable of being overridden by environment variables)

### Acceptance Criteria

- [ ] When Carrot starts with a blank user database, a super user is created.
- [ ] If users exist in the database, no super user is created.
- [ ] The super user password is configurable through environment variables


### Tasks

- [ ] A new management command
- [ ] Checks if users exists
- [ ] If not - create a new user
- [ ] Have password be configurable through environment variable, and a set a default

### Confirm creation

- [x] This issue is ready
Linked issue comments: user: login: AndyRae
created_at: 2025-02-17T15:17:56Z
body: 
Say this is the default passwrod for a super user if they are seeded 

`settings.py`
```
DEFAULT_PASSWORD = os.getenv("SUPERUSER_DEFAULT_PASSWORD", "Password123")
```
author_association: MEMBER
user: login: g-pechorin
created_at: 2025-02-26T16:10:30Z
body: i need to pass tests (oops) and add my own (d'oh)
author_association: CONTRIBUTOR

Diff:
diff --git a/app/api/config/settings.py b/app/api/config/settings.py
index b56fb695d..22a45c881 100644
--- a/app/api/config/settings.py
+++ b/app/api/config/settings.py
@@ -237,3 +237,10 @@
     "USE_JWT": True,
     "JWT_AUTH_HTTPONLY": False,
 }
+
+
+##
+# https://github.com/Health-Informatics-UoN/carrot-mapper/issues/946
+SUPERUSER_DEFAULT_PASSWORD = os.getenv("SUPERUSER_DEFAULT_PASSWORD", None)
+SUPERUSER_DEFAULT_EMAIL = os.getenv("SUPERUSER_DEFAULT_EMAIL", "user@carrot")
+SUPERUSER_DEFAULT_USERNAME = os.getenv("SUPERUSER_DEFAULT_USERNAME", None)
diff --git a/app/api/entrypoint.sh b/app/api/entrypoint.sh
index 7b923d9c3..53fc56d86 100644
--- a/app/api/entrypoint.sh
+++ b/app/api/entrypoint.sh
@@ -10,6 +10,7 @@ mkdir staticfiles
 python manage.py collectstatic
 python manage.py migrate
 python manage.py automatic_seeding_data
+python manage.py default_super_user
 
 # Set tmp dir to be in-memory for speed. Pass logs to stdout/err as Docker will expect them there
 gunicorn --config gunicorn.conf.py --worker-tmp-dir /dev/shm --timeout 600 --log-file=- --bind :8000 --workers 3 config.wsgi:application --reload
diff --git a/app/api/test/test_setup.py b/app/api/test/test_setup.py
new file mode 100644
index 000000000..ee40a03e2
--- /dev/null
+++ b/app/api/test/test_setup.py
@@ -0,0 +1,222 @@
+from django.test import TestCase
+import shared.mapping.management.commands.default_super_user as dsu
+
+
+def mocks(command):
+    """rewires the mock command to point at mock objects, and, returns the lists used for mock messages and mock accounts"""
+
+    class m_objects:
+        users = []
+
+        def count(self):
+            return len(self.users)
+
+        def create_superuser(self, name, email, password):
+            self.users.append(
+                {
+                    "super": True,
+                    "name": name,
+                    "email": email,
+                    "password": password,
+                }
+            )
+
+    class m_users:
+        objects = m_objects()
+
+    class m_stdout:
+        messages = []
+
+        def write(self, message):
+            self.messages.append(message)
+
+    class m_style:
+        def WARNING(self, message):
+            return "> " + message
+
+        def SUCCESS(self, message):
+            return "; " + message
+
+        def ERROR(self, message):
+            return "! " + message
+
+    class m_settings:
+        SUPERUSER_DEFAULT_USERNAME = "#name"
+        SUPERUSER_DEFAULT_EMAIL = "#email"
+        SUPERUSER_DEFAULT_PASSWORD = "#password"
+
+    command.users = m_users()
+    command.style = m_style()
+    command.stdout = m_stdout()
+    command.settings = m_settings()
+
+    return [command.users.objects.users, command.stdout.messages]
+
+
+class TestSetup(TestCase):
+    """test details of setup"""
+
+    def test_no_accounts(self):
+        """tests if a (mock) account is added when the (mock) database has one"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        command.handle()
+
+        self.assertEqual(
+            [
+                {
+                    "super": True,
+                    "name": "#name",
+                    "email": "#email",
+                    "password": "#password",
+                }
+            ],
+            users,
+        )
+        self.assertEqual(
+            ["; Superuser created with Username='#name', Password='#*******d'"],
+            messages,
+        )
+
+    def test_no_create_when_single_user_present(self):
+        """creates a mock setup with a single user to be sure accounts won't be added in this case"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        geo = {
+            "super": False,
+            "name": "fred",
+            "email": "jake@foo",
+            "password": "ieatbugs",
+        }
+        users.append(geo)
+
+        command.handle()
+
+        self.assertEqual([geo], users)
+        self.assertEqual(
+            ["; There is already a user - a default superuser will not be added"],
+            messages,
+        )
+
+    def test_entrypoint(self):
+        """tests to see if there's a line in the entrypoint.sh to trigger the command"""
+        import os
+
+        found = False
+
+        entry = __file__
+        entry = os.path.dirname(entry)
+        entry = os.path.dirname(entry)
+        entry = os.path.join(entry, "entrypoint.sh")
+
+        with open(entry, "r") as file:
+            for line in file.read().splitlines():
+                line = line.strip()
+                print(line)
+                if "python manage.py default_super_user" == line:
+                    self.assertFalse(found)
+                    found = True
+        self.assertTrue(found)
+
+    def test_multiple_accounts_already(self):
+        """creates a mock setup with three users to be sure accounts won't be added in this case"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        account = {
+            "super": False,
+            "name": "fred",
+            "email": "jake@foo",
+            "password": "ieatbugs",
+        }
+        users.append(account)
+        account = {
+            "super": True,
+            "name": "kim",
+            "email": "kim@foo",
+            "password": "dayweekyear",
+        }
+        users.append(account)
+        account = {
+            "super": False,
+            "name": "sam",
+            "email": "sammy@foo",
+            "password": "drivecar",
+        }
+        users.append(account)
+
+        command.handle()
+
+        self.assertEqual(3, len(users))
+        self.assertEqual(
+            ["; There are 3 users - a default superuser will not be added"], messages
+        )
+
+    def test_no_env_username(self):
+        """test that a user won't be created when username isn't set in env"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        command.settings.SUPERUSER_DEFAULT_USERNAME = None
+
+        command.handle()
+
+        self.assertEqual([], users)
+        self.assertEqual(
+            [
+                "! no SUPERUSER_DEFAULT_USERNAME value was defined in the environment variables",
+                "! no user account exists in the system",
+            ],
+            messages,
+        )
+
+    def test_no_env_password(self):
+        """test that a user won't be created when password isn't set in env"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        command.settings.SUPERUSER_DEFAULT_PASSWORD = None
+
+        command.handle()
+
+        self.assertEqual([], users)
+        self.assertEqual(
+            [
+                "! no SUPERUSER_DEFAULT_PASSWORD value was defined in the environment variables",
+                "! no user account exists in the system",
+            ],
+            messages,
+        )
+
+    def test_no_env_username_or_password(self):
+        """test that a user won't be created when neither password or username are set in env"""
+
+        command = dsu.Command()
+
+        [users, messages] = mocks(command)
+
+        command.settings.SUPERUSER_DEFAULT_USERNAME = None
+        command.settings.SUPERUSER_DEFAULT_PASSWORD = None
+
+        command.handle()
+
+        self.assertEqual([], users)
+        self.assertEqual(
+            [
+                "! neither SUPERUSER_DEFAULT_USERNAME or SUPERUSER_DEFAULT_PASSWORD values were defined in the environment variables",
+                "! no user account exists in the system",
+            ],
+            messages,
+        )
diff --git a/app/shared/shared/mapping/management/commands/default_super_user.py b/app/shared/shared/mapping/management/commands/default_super_user.py
new file mode 100644
index 000000000..e9080c606
--- /dev/null
+++ b/app/shared/shared/mapping/management/commands/default_super_user.py
@@ -0,0 +1,69 @@
+"""Command to create a default superuser if no users exist"""
+
+from django.contrib.auth import get_user_model
+from django.core.management.base import BaseCommand
+import django
+import django.conf as dc
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if user_count > 0:
+            message = (
+                "There is already a user - a default superuser will not be added"
+                if user_count == 1
+                else f"There are {user_count} users - a default superuser will not be added"
+            )
+            self.stdout.write(self.style.SUCCESS(message))
+            return
+
+        # https://github.com/Health-Informatics-UoN/carrot-mapper/issues/946
+        su_username = self.settings.SUPERUSER_DEFAULT_USERNAME
+        su_password = self.settings.SUPERUSER_DEFAULT_PASSWORD
+        su_email_address = self.settings.SUPERUSER_DEFAULT_EMAIL
+
+        # check to see if the username and password are available
+        if None == su_username or None == su_password:
+            if None != su_password:
+                message = "no SUPERUSER_DEFAULT_USERNAME value was defined in the environment variables"
+            elif None != su_username:
+                message = "no SUPERUSER_DEFAULT_PASSWORD value was defined in the environment variables"
+            else:
+                message = "neither SUPERUSER_DEFAULT_USERNAME or SUPERUSER_DEFAULT_PASSWORD values were defined in the environment variables"
+
+            self.stdout.write(self.style.ERROR(message))
+            self.stdout.write(self.style.ERROR("no user account exists in the system"))
+            return
+
+        # execute the creation command
+        self.users.objects.create_superuser(
+            su_username,
+            su_email_address,
+            su_password,
+        )
+        # log the user's details
+        logged_password = su_password
+        logged_password = (
+            logged_password[0]
+            + ("*" * len(logged_password[1:-1]))
+            + logged_password[-1]
+        )
+        self.stdout.write(
+            self.style.SUCCESS(
+                f"Superuser created with Username='{su_username}', Password='{logged_password}'"
+            )
+        )


Reviews:
user: login: CodeByKarthik
body: Hi Peter, 

The code looks great! I just have a small suggestion and let me know your thoughts.

Looking forward from you. 

Thanks and regards, 
Karthik
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:11:25Z
user: login: AndrewThien
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T17:45:42Z
user: login: anwarfg
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-11T16:28:40Z
user: login: g-pechorin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T18:17:18Z
user: login: AndrewThien
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T15:24:36Z
user: login: g-pechorin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T15:46:42Z
user: login: AndrewThien
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T08:48:13Z
user: login: brian-kim31
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T09:15:11Z
user: login: ShasonGurung
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T10:05:12Z
user: login: g-pechorin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T10:32:59Z
user: login: ShasonGurung
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T10:34:28Z
user: login: CodeByKarthik
body: Thanks for your contribution Peter. Good Job✌🏻
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T11:31:14Z
user: login: ShasonGurung
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T08:58:28Z
user: login: AndrewThien
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:18:35Z
user: login: AndyRae
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-19T15:08:11Z
user: login: CodeByKarthik
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:33:14Z

Review comments:
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """create a default superuser iff no users exist"""
+
+    help = "create a default superuser iff no users exist"
+
+    from django.contrib.auth import get_user_model
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if 0 != user_count:
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: CodeByKarthik
body: Hi Peter,

I hope you are doing well. The code is working fine, but I think it could be slightly improved with the following approach:

```
if user_count > 0:
    message = (
        "There is already a user - default superuser will not be added"
        if user_count == 1
        else f"There are {user_count} users - default superuser will not be added"
    )
    self.stdout.write(self.style.SUCCESS(message))
    return
```

- This makes it easier to understand and make sure that the function returns immediately when the condition is met. 

- Additionally, it keeps `user_count` as an integer for logical operations rather than replacing it with a string. 

Let me know your thoughts🙂
created_at: 2025-03-07T16:00:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """create a default superuser iff no users exist"""
+
+    help = "create a default superuser iff no users exist"
+
+    from django.contrib.auth import get_user_model
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if 0 != user_count:
+            if 1 == user_count:
+                user_count = (
+                    "There is already a user - default superuser will not be added"
+                )
+            else:
+                user_count = f"There are {user_count} users  - default superuser will not be added"
+            self.stdout.write(self.style.SUCCESS(user_count))
+        else:
+            self.stdout.write(
+                self.style.SUCCESS(
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: CodeByKarthik
body: Could you please add a log statement that prints the username and password. 

**For example:** 
```
self.stdout.write(
    self.style.SUCCESS(
        f"Superuser successfully created with Username='{self.settings.SUPERUSER_DEFAULT_NAME}', Password='{self.settings.SUPERUSER_DEFAULT_PASSWORD}'"
    )
)
```

Adding a log statement that prints the username and password would provide an easy way to verify that the superuser is being set up correctly without having to manually check the database.
created_at: 2025-03-07T16:09:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: AndrewThien
body: ```suggestion
"""Command to create a default superuser if no users exist"""
```
created_at: 2025-03-08T17:43:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """create a default superuser iff no users exist"""
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: AndrewThien
body: ```suggestion
    """Create a default superuser if no users exist"""
```
created_at: 2025-03-08T17:44:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """create a default superuser iff no users exist"""
+
+    help = "create a default superuser iff no users exist"
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: AndrewThien
body: ```suggestion
    help = "Create a default superuser if no users exist"
```
created_at: 2025-03-08T17:44:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: anwarfg
body: Unless you mean 'if and only if', in which case I'd suggest you write it out since the shorthand is maybe not so well known - especially in a docstring (as opposed to a comment).
created_at: 2025-03-11T16:28:40Z
author_association: NONE
diff_hunk: @@ -0,0 +1,44 @@
+"""command to create a default superuser iff no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """create a default superuser iff no users exist"""
+
+    help = "create a default superuser iff no users exist"
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: g-pechorin
body: "if and only if" was exactly what i meant ... and you're exactly right that i should spell it out
created_at: 2025-03-12T18:17:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+"""Command to create a default superuser if no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    from django.contrib.auth import get_user_model
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if user_count > 0:
+            message = (
+                "There is already a user - default superuser will not be added"
+                if user_count == 1
+                else f"There are {user_count} users - default superuser will not be added"
+            )
+            self.stdout.write(self.style.SUCCESS(message))
+            return
+        else:
+            # execute the creation command
+            self.users.objects.create_superuser(
+                self.settings.SUPERUSER_DEFAULT_NAME,
+                self.settings.SUPERUSER_DEFAULT_EMAIL,
+                self.settings.SUPERUSER_DEFAULT_PASSWORD,
+            )
+            # log the user's details
+            self.stdout.write(
+                self.style.SUCCESS(
+                    f"Superuser successfully created with Username='{self.settings.SUPERUSER_DEFAULT_NAME}', Password='{self.settings.SUPERUSER_DEFAULT_PASSWORD}'"
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: AndrewThien
body: Security concerns were raised by @brian-kim31 when password and username are exposed on the console.
Maybe you can hide the password somehow, only showing a few last letters for the purpose of tracking, for example?
created_at: 2025-03-13T15:24:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+"""Command to create a default superuser if no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    from django.contrib.auth import get_user_model
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if user_count > 0:
+            message = (
+                "There is already a user - default superuser will not be added"
+                if user_count == 1
+                else f"There are {user_count} users - default superuser will not be added"
+            )
+            self.stdout.write(self.style.SUCCESS(message))
+            return
+        else:
+            # execute the creation command
+            self.users.objects.create_superuser(
+                self.settings.SUPERUSER_DEFAULT_NAME,
+                self.settings.SUPERUSER_DEFAULT_EMAIL,
+                self.settings.SUPERUSER_DEFAULT_PASSWORD,
+            )
+            # log the user's details
+            self.stdout.write(
+                self.style.SUCCESS(
+                    f"Superuser successfully created with Username='{self.settings.SUPERUSER_DEFAULT_NAME}', Password='{self.settings.SUPERUSER_DEFAULT_PASSWORD}'"
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: g-pechorin
body: how about first-letter *** last-letter? so with `Password123!` it'd show `P**********!`?
created_at: 2025-03-13T15:46:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+"""Command to create a default superuser if no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    from django.contrib.auth import get_user_model
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: ShasonGurung
body: any reason this import is inside the class instead of at the top?
created_at: 2025-03-14T09:53:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+"""Command to create a default superuser if no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    from django.contrib.auth import get_user_model
+
+    """wraps getUserModel so i can replace it for unit tests"""
+    users = get_user_model()
+
+    """wraps settings for unit tests"""
+    settings = dc.settings
+
+    def handle(self, *args, **options):
+        """primary functionality"""
+
+        user_count = self.users.objects.count()
+        if user_count > 0:
+            message = (
+                "There is already a user - default superuser will not be added"
+                if user_count == 1
+                else f"There are {user_count} users - default superuser will not be added"
+            )
+            self.stdout.write(self.style.SUCCESS(message))
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: ShasonGurung
body: ```suggestion
            self.stdout.write(self.style.WARNING(message))
```
created_at: 2025-03-14T10:04:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+"""Command to create a default superuser if no users exist"""
+
+import django.conf as dc
+from django.core.management.base import BaseCommand
+import django
+import os
+
+
+class Command(BaseCommand):
+    """Create a default superuser if and only if no users exist"""
+
+    help = "Create a default superuser if and only if no users exist"
+
+    from django.contrib.auth import get_user_model
path: app/shared/shared/mapping/management/commands/default_super_user.py
user: login: g-pechorin
body: i've changed it
created_at: 2025-03-14T10:32:59Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-05T09:58:22Z
body: <!-- Pytest Coverage Comment: test-workers -->
| Tests | Skipped | Failures | Errors | Time |
| ----- | ------- | -------- | -------- | ------------------ |
| 25 | 1 :zzz: | 6 :x: | 0 :fire: | 4.225s :stopwatch: |

author_association: NONE
user: login: CodeByKarthik
created_at: 2025-03-13T13:12:33Z
body: Thanks for your changes @g-pechorin. I can approve your PR once I get the request access. 
author_association: CONTRIBUTOR
user: login: g-pechorin
created_at: 2025-03-18T15:20:55Z
body: i'm going to re-run the whole setup on my workstation to check this. it'll take awhile.
author_association: CONTRIBUTOR