diff --git a/InvenTree/InvenTree/apps.py b/InvenTree/InvenTree/apps.py index 76b918459c..80389bda95 100644 --- a/InvenTree/InvenTree/apps.py +++ b/InvenTree/InvenTree/apps.py @@ -4,8 +4,13 @@ import logging from django.apps import AppConfig from django.core.exceptions import AppRegistryNotReady +from django.conf import settings +from django.contrib.auth import get_user_model +from django.db import transaction +from django.db.utils import IntegrityError from InvenTree.ready import isInTestMode, canAppAccessDatabase +from .config import get_setting import InvenTree.tasks @@ -26,6 +31,9 @@ class InvenTreeConfig(AppConfig): if not isInTestMode(): self.update_exchange_rates() + if canAppAccessDatabase() or settings.TESTING_ENV: + self.add_user_on_startup() + def remove_obsolete_tasks(self): """ Delete any obsolete scheduled tasks in the database @@ -138,3 +146,54 @@ class InvenTreeConfig(AppConfig): update_exchange_rates() except Exception as e: logger.error(f"Error updating exchange rates: {e}") + + def add_user_on_startup(self): + """Add a user on startup""" + # stop if checks were already created + if hasattr(settings, 'USER_ADDED') and settings.USER_ADDED: + return + + # get values + add_user = get_setting( + 'INVENTREE_ADMIN_USER', + settings.CONFIG.get('admin_user', False) + ) + add_email = get_setting( + 'INVENTREE_ADMIN_EMAIL', + settings.CONFIG.get('admin_email', False) + ) + add_password = get_setting( + 'INVENTREE_ADMIN_PASSWORD', + settings.CONFIG.get('admin_password', False) + ) + + # check if all values are present + set_variables = 0 + for tested_var in [add_user, add_email, add_password]: + if tested_var: + set_variables += 1 + + # no variable set -> do not try anything + if set_variables == 0: + settings.USER_ADDED = True + return + + # not all needed variables set + if set_variables < 3: + logger.warn('Not all required settings for adding a user on startup are present:\nINVENTREE_SET_USER, INVENTREE_SET_EMAIL, INVENTREE_SET_PASSWORD') + settings.USER_ADDED = True + return + + # good to go -> create user + user = get_user_model() + try: + with transaction.atomic(): + new_user = user.objects.create_superuser(add_user, add_email, add_password) + logger.info(f'User {str(new_user)} was created!') + except IntegrityError as _e: + logger.warning(f'The user "{add_user}" could not be created due to the following error:\n{str(_e)}') + if settings.TESTING_ENV: + raise _e + + # do not try again + settings.USER_ADDED = True diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 121f1b6383..279225355d 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -37,6 +37,8 @@ def _is_true(x): # Determine if we are running in "test" mode e.g. "manage.py test" TESTING = 'test' in sys.argv +# Are enviroment variables manipulated by tests? Needs to be set by testing code +TESTING_ENV = False # New requirement for django 3.2+ DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 205231eb7b..f89a8b073d 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -1,9 +1,12 @@ import json +from test.support import EnvironmentVarGuard -from django.test import TestCase +from django.test import TestCase, override_settings import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError +from django.contrib.auth import get_user_model +from django.conf import settings from djmoney.money import Money from djmoney.contrib.exchange.models import Rate, convert_money @@ -407,3 +410,46 @@ class TestStatus(TestCase): def test_Importing(self): self.assertEqual(ready.isImportingData(), False) + + +class TestSettings(TestCase): + """ + Unit tests for settings + """ + + def setUp(self) -> None: + self.user_mdl = get_user_model() + self.env = EnvironmentVarGuard() + + def run_reload(self): + from plugin import registry + + with self.env: + settings.USER_ADDED = False + registry.reload_plugins() + + @override_settings(TESTING_ENV=True) + def test_set_user_to_few(self): + # add shortcut + user_count = self.user_mdl.objects.count + # enable testing mode + settings.TESTING_ENV = True + + # nothing set + self.run_reload() + self.assertEqual(user_count(), 0) + + # not enough set + self.env.set('INVENTREE_ADMIN_USER', 'admin') # set username + self.run_reload() + self.assertEqual(user_count(), 0) + + # enough set + self.env.set('INVENTREE_ADMIN_USER', 'admin') # set username + self.env.set('INVENTREE_ADMIN_EMAIL', 'info@example.com') # set email + self.env.set('INVENTREE_ADMIN_PASSWORD', 'password123') # set password + self.run_reload() + self.assertEqual(user_count(), 1) + + # make sure to clean up + settings.TESTING_ENV = False diff --git a/InvenTree/config_template.yaml b/InvenTree/config_template.yaml index b14c1224ce..65dd20d3e8 100644 --- a/InvenTree/config_template.yaml +++ b/InvenTree/config_template.yaml @@ -154,6 +154,11 @@ static_root: '/home/inventree/data/static' # Use environment variable INVENTREE_LOGIN_ATTEMPTS #login_attempts: 5 +# Add new user on first startup +#admin_user: admin +#admin_email: info@example.com +#admin_password: inventree + # Permit custom authentication backends #authentication_backends: # - 'django.contrib.auth.backends.ModelBackend'