Skip to content

Commit

Permalink
Support bootstrapping a Django/Wagtail admin user as part of `make pr…
Browse files Browse the repository at this point in the history
…eflight` (#14813)

If using sqlite locally, when `make preflight` runs, it will replace your local DB.

This changeset at least bootstraps a new admin user for you, even if any local CMS pages will have been lost
  • Loading branch information
stevejalim authored Jul 10, 2024
1 parent ff5c501 commit caf5db8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 1 deletion.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ preflight:
${MAKE} install-local-python-deps
$ npm install
$ bin/sync-all.sh
$ python manage.py bootstrap_local_admin

run-local-task-queue:
# We temporarily source the .env for the command's duration only
Expand Down
46 changes: 46 additions & 0 deletions bedrock/cms/management/commands/bootstrap_local_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.


import sys

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.db.transaction import atomic

from bedrock.base.config_manager import config


class Command(BaseCommand):
help = """Creates a Django/Wagtail Admin User based on the Mozilla
email address set as the WAGTAIL_ADMIN_EMAIL environment variable.
Optionally also sets a non-SSO password for that new user based on
WAGTAIL_ADMIN_PASSWORD"""

@atomic
def handle(self, *args, **kwargs):
WAGTAIL_ADMIN_EMAIL = config("WAGTAIL_ADMIN_EMAIL", default="")
WAGTAIL_ADMIN_PASSWORD = config("WAGTAIL_ADMIN_PASSWORD", default="")

if not WAGTAIL_ADMIN_EMAIL:
sys.stdout.write("Not bootstrapping an Admin user: WAGTAIL_ADMIN_EMAIL not defined in environment.")
return
if not WAGTAIL_ADMIN_EMAIL.endswith("@mozilla.com"):
sys.stdout.write("Not bootstrapping an Admin user: WAGTAIL_ADMIN_EMAIL is not a @mozilla.com email address.")
return

user, created = User.objects.get_or_create(email=WAGTAIL_ADMIN_EMAIL)
if not created:
sys.stdout.write(f"Admin user {WAGTAIL_ADMIN_EMAIL} already exists")
else:
user.username = WAGTAIL_ADMIN_EMAIL
user.is_staff = True
user.is_superuser = True
if not WAGTAIL_ADMIN_PASSWORD:
user.set_unusable_password() # They won't need one to use SSO
sys.stdout.write(f"Created Admin user {WAGTAIL_ADMIN_EMAIL} for local SSO use")
else:
user.set_password(WAGTAIL_ADMIN_PASSWORD)
sys.stdout.write(f"Created Admin user {WAGTAIL_ADMIN_EMAIL} with password '{WAGTAIL_ADMIN_PASSWORD}'")
user.save()
80 changes: 79 additions & 1 deletion bedrock/cms/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from io import StringIO
from unittest.mock import patch
from unittest.mock import call, patch

from django.conf import settings
from django.contrib.auth.models import User
Expand Down Expand Up @@ -87,3 +87,81 @@ def test_scrub(self):
self.assertEqual(Revision.objects.count(), 0)
self.assertEqual(TranslationSource.objects.count(), 0)
self.assertEqual(SimpleRichTextPage.objects.count(), 3) # pages are unaffected


@patch("bedrock.cms.management.commands.bootstrap_local_admin.sys.stdout.write")
class BootstrapLocalAdminTests(TransactionTestCase):
def _run_test(self, mock_write, expected_output):
out = StringIO()
call_command("bootstrap_local_admin", stdout=out)
output = mock_write.call_args_list
self.assertEqual(output, expected_output)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "", "WAGTAIL_ADMIN_PASSWORD": ""})
def test_no_env_vars_available(self, mock_write):
self._run_test(
mock_write=mock_write,
expected_output=[
call("Not bootstrapping an Admin user: WAGTAIL_ADMIN_EMAIL not defined in environment."),
],
)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "[email protected]", "WAGTAIL_ADMIN_PASSWORD": ""})
def test_email_available(self, mock_write):
self._run_test(
mock_write=mock_write,
expected_output=[
call("Created Admin user [email protected] for local SSO use"),
],
)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "[email protected]", "WAGTAIL_ADMIN_PASSWORD": ""})
def test_email_available_but_not_moco(self, mock_write):
self._run_test(
mock_write=mock_write,
expected_output=[
call("Not bootstrapping an Admin user: WAGTAIL_ADMIN_EMAIL is not a @mozilla.com email address."),
],
)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "[email protected]", "WAGTAIL_ADMIN_PASSWORD": "secret"})
def test_email_and_password_available(self, mock_write):
self._run_test(
mock_write=mock_write,
expected_output=[
call("Created Admin user [email protected] with password 'secret'"),
],
)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "", "WAGTAIL_ADMIN_PASSWORD": ""})
def test_only_password_available(self, mock_write):
self._run_test(
mock_write=mock_write,
expected_output=[
call("Not bootstrapping an Admin user: WAGTAIL_ADMIN_EMAIL not defined in environment."),
],
)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "[email protected]", "WAGTAIL_ADMIN_PASSWORD": ""})
def test_existing_user_exists_email_only(self, mock_write):
out = StringIO()
call_command("bootstrap_local_admin", stdout=out)
call_command("bootstrap_local_admin", stdout=out)
output = mock_write.call_args_list
expected_output = [
call("Created Admin user [email protected] for local SSO use"),
call("Admin user [email protected] already exists"),
]
self.assertEqual(output, expected_output)

@patch.dict("os.environ", {"WAGTAIL_ADMIN_EMAIL": "[email protected]", "WAGTAIL_ADMIN_PASSWORD": "secret"})
def test_existing_user_exists_email_and_password(self, mock_write):
out = StringIO()
call_command("bootstrap_local_admin", stdout=out)
call_command("bootstrap_local_admin", stdout=out)
output = mock_write.call_args_list
expected_output = [
call("Created Admin user [email protected] with password 'secret'"),
call("Admin user [email protected] already exists"),
]
self.assertEqual(output, expected_output)

0 comments on commit caf5db8

Please sign in to comment.