Snapshot: alpha-2026-9

This commit is contained in:
j3d1 2026-09-02 21:40:28 +02:00
parent 9acf5a97e2
commit d00b5c7961
241 changed files with 85546 additions and 2409 deletions

View file

@ -8,67 +8,80 @@ import dotenv
from django.db import transaction, IntegrityError
class CmdCtx:
def yesno(prompt, default=False):
if not sys.stdin.isatty():
return default
yes = {'yes', 'y', 'ye'}
no = {'no', 'n'}
def __init__(self, args):
self.args = args
if default:
yes.add('')
else:
no.add('')
def yesno(self, prompt, default=False):
if not sys.stdin.isatty() or self.args.noninteractive:
return default
elif self.args.yes:
hint = ' [Y/n] ' if default else ' [y/N] '
while True:
choice = input(prompt + hint).lower()
if choice in yes:
return True
elif self.args.no:
elif choice in no:
return False
yes = {'yes', 'y', 'ye'}
no = {'no', 'n'}
if default:
yes.add('')
else:
no.add('')
hint = ' [Y/n] ' if default else ' [y/N] '
while True:
choice = input(prompt + hint).lower()
if choice in yes:
return True
elif choice in no:
return False
else:
print('Please respond with "yes" or "no"')
print('Please respond with "yes" or "no"')
def configure(ctx):
def configure():
# Keys this function may generate/update; tracked so an unwritable .env (e.g. a prod
# container configured via --env-file) can still print them for the operator to apply manually.
tracked_keys = ['SECRET_KEY', 'ALLOWED_HOSTS']
unwritable = False
if not os.path.exists('.env'):
if not ctx.yesno("the .env file does not exist, do you want to create it?", default=True):
print('Aborting')
exit(0)
if not os.path.exists('.env.dist'):
print('No .env.dist file found')
exit(1)
else:
from shutil import copyfile
copyfile('.env.dist', '.env')
if yesno("the .env file does not exist, do you want to create it?", default=True):
if not os.path.exists('.env.dist'):
print('No .env.dist file found')
else:
for key in dotenv.dotenv_values('.env.dist'):
if key not in tracked_keys:
tracked_keys.append(key)
from shutil import copyfile
try:
copyfile('.env.dist', '.env')
except PermissionError:
unwritable = True
env = dotenv.load_dotenv('.env')
if not env or not os.getenv('SECRET_KEY'):
dotenv.load_dotenv('.env')
if not os.getenv('SECRET_KEY'):
from django.core.management.utils import get_random_secret_key
print('No SECRET_KEY found in .env file, generating one...')
with open('.env', 'a') as f:
f.write('\nSECRET_KEY=')
f.write(get_random_secret_key())
f.write('\n')
secret_key = get_random_secret_key()
os.environ['SECRET_KEY'] = secret_key
try:
with open('.env', 'a') as f:
f.write('\nSECRET_KEY=')
f.write(secret_key)
f.write('\n')
except PermissionError:
unwritable = True
# TODO rename ALLOWED_HOSTS to something more self-explanatory
current_hosts = os.getenv('ALLOWED_HOSTS')
print('Current ALLOWED_HOSTS: {}'.format(current_hosts))
if ctx.yesno("Do you want to add ALLOWED_HOSTS?"):
if yesno("Do you want to add ALLOWED_HOSTS?"):
hosts = input("Enter a comma-separated list of allowed hosts: ")
joined_hosts = current_hosts + ',' + hosts if current_hosts else hosts
dotenv.set_key('.env', 'ALLOWED_HOSTS', joined_hosts)
os.environ['ALLOWED_HOSTS'] = joined_hosts
try:
dotenv.set_key('.env', 'ALLOWED_HOSTS', joined_hosts)
except PermissionError:
unwritable = True
if unwritable:
print('Could not write .env (read-only working directory) - resulting configuration:')
for key in tracked_keys:
print('{}={}'.format(key, os.getenv(key, '')))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
import django
@ -76,21 +89,20 @@ def configure(ctx):
django.setup()
if not os.path.exists('db.sqlite3'):
if not ctx.yesno("No database found, do you want to create one?", default=True):
if not yesno("No database found, do you want to create one?", default=True):
print('Aborting')
exit(0)
from django.core.management import call_command
call_command('migrate')
if ctx.yesno("Do you want to create a superuser?"):
if yesno("Do you want to create a superuser?"):
from django.core.management import call_command
call_command('createsuperuser')
call_command('collectstatic', '--no-input')
if ctx.yesno("Do you want to import all categories, properties and tags contained in this repository?",
default=True):
if yesno("Do you want to import all categories, properties and tags contained in this repository?", default=True):
from hostadmin.serializers import CategorySerializer, PropertySerializer, TagSerializer
from hostadmin.models import ImportedIdentifierSets
from hashlib import sha256
@ -193,7 +205,11 @@ def testdata():
import django
django.setup()
if os.path.exists('testdata.py'):
testdata_path = os.environ.get('TOOLSHED_SETUP_PATH', 'testdata.py')
if os.path.exists(testdata_path):
if testdata_path != 'testdata.py':
import sys
sys.path.append(os.path.dirname(testdata_path))
from testdata import create_test_data
create_test_data()
else:
@ -206,7 +222,6 @@ def main():
parser = ArgumentParser(description='Toolshed Server Configuration')
parser.add_argument('--yes', '-y', help='Answer yes to all questions', action='store_true')
parser.add_argument('--no', '-n', help='Answer no to all questions', action='store_true')
parser.add_argument('--noninteractive', '-x', help="Run in noninteractive mode", action='store_true')
parser.add_argument('cmd', help='Command', default='configure', nargs='?')
args = parser.parse_args()
@ -214,10 +229,8 @@ def main():
print('Error: --yes and --no are mutually exclusive')
exit(1)
ctx = CmdCtx(args)
if args.cmd == 'configure':
configure(ctx)
configure()
elif args.cmd == 'reset':
reset()
elif args.cmd == 'testdata':