Skip to content

Commit

Permalink
Add option to create initial superuser
Browse files Browse the repository at this point in the history
  • Loading branch information
sissbruecker committed Aug 14, 2022
1 parent e4636c0 commit 6dbc99a
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
37 changes: 37 additions & 0 deletions bookmarks/management/commands/create_initial_superuser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import logging

from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model

logger = logging.getLogger(__name__)


class Command(BaseCommand):
help = "Creates an initial superuser for a deployment using env variables"

def handle(self, *args, **options):
User = get_user_model()
superuser_name = os.getenv('LD_SUPERUSER_NAME', None)
superuser_password = os.getenv('LD_SUPERUSER_PASSWORD', None)

# Skip if option is undefined
if not superuser_name:
logger.info('Skip creating initial superuser, LD_SUPERUSER_NAME option is not defined')
return

# Skip if user already exists
user_exists = User.objects.filter(username=superuser_name).exists()
if user_exists:
logger.info('Skip creating initial superuser, user already exists')
return

user = User(username=superuser_name, is_superuser=True, is_staff=True)

if superuser_password:
user.set_password(superuser_password)
else:
user.set_unusable_password()

user.save()
logger.info('Created initial superuser')
45 changes: 45 additions & 0 deletions bookmarks/tests/test_create_initial_superuser_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os
from unittest import mock

from django.test import TestCase

from bookmarks.models import User
from bookmarks.management.commands.create_initial_superuser import Command


class TestCreateInitialSuperuserCommand(TestCase):

@mock.patch.dict(os.environ, {'LD_SUPERUSER_NAME': 'john', 'LD_SUPERUSER_PASSWORD': 'password123'})
def test_create_with_password(self):
Command().handle()

self.assertEqual(1, User.objects.count())

user = User.objects.first()
self.assertEqual('john', user.username)
self.assertTrue(user.has_usable_password())
self.assertTrue(user.check_password('password123'))

@mock.patch.dict(os.environ, {'LD_SUPERUSER_NAME': 'john'})
def test_create_without_password(self):
Command().handle()

self.assertEqual(1, User.objects.count())

user = User.objects.first()
self.assertEqual('john', user.username)
self.assertFalse(user.has_usable_password())

def test_create_without_options(self):
Command().handle()

self.assertEqual(0, User.objects.count())

@mock.patch.dict(os.environ, {'LD_SUPERUSER_NAME': 'john', 'LD_SUPERUSER_PASSWORD': 'password123'})
def test_create_multiple_times(self):
Command().handle()
Command().handle()
Command().handle()

self.assertEqual(1, User.objects.count())

2 changes: 2 additions & 0 deletions bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mkdir -p data
python manage.py migrate
# Generate secret key file if it does not exist
python manage.py generate_secret_key
# Create initial superuser if defined in options / environment variables
python manage.py create_initial_superuser

# Ensure the DB folder is owned by the right user
chown -R www-data: /etc/linkding/data
Expand Down
16 changes: 16 additions & 0 deletions docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ All options need to be defined as environment variables in the environment that

## List of options

### `LD_SUPERUSER_NAME`

Values: `String` | Default = None

When set, creates an initial superuser with the specified username when starting the container.
Does nothing if the user already exists.

See [`LD_SUPERUSER_PASSWORD`](#ld_superuser_password) on how to configure the respective password.

### `LD_SUPERUSER_PASSWORD`

Values: `String` | Default = None

The password for the initial superuser.
When left undefined, the superuser will be created without a usable password, which means the user can not authenticate using credentials / through the login form, and can only be authenticated using proxy authentication (see [`LD_ENABLE_AUTH_PROXY`](#ld_enable_auth_proxy)).

### `LD_DISABLE_BACKGROUND_TASKS`

Values: `True`, `False` | Default = `False`
Expand Down

0 comments on commit 6dbc99a

Please sign in to comment.