First-run setup wizard (/setup)
- setup_complete site setting; a fresh admin is steered to /setup until it is finished (skippable for the session). - SetupWizard.vue: Site (facility/base-url/access-domain), Features (plugin enable/disable), Floor Map dimensions, Starter Data (seed common vendors), Finish. Reuses the settings + plugins APIs. - setup blueprint: POST /setup/seed-starter (idempotent common vendors) and POST /setup/complete. setupState composable drives the router redirect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
shopdb/core/api/setup.py
Normal file
62
shopdb/core/api/setup.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""First-run setup wizard support endpoints.
|
||||
|
||||
The wizard itself is frontend; these endpoints cover the pieces that need
|
||||
server work: seeding common starter data and marking setup finished. Site,
|
||||
plugin, and map configuration reuse the existing settings / plugins APIs.
|
||||
"""
|
||||
|
||||
from flask import Blueprint
|
||||
from flask_jwt_extended import jwt_required
|
||||
|
||||
from shopdb.extensions import db
|
||||
from shopdb.core.models import Vendor, Setting
|
||||
from shopdb.utils.responses import success_response
|
||||
from shopdb.utils.authz import require_role
|
||||
|
||||
setup_bp = Blueprint('setup', __name__)
|
||||
|
||||
# Common hardware vendors most sites will want on hand.
|
||||
STARTER_VENDORS = [
|
||||
('Dell Inc.', 'https://www.dell.com'),
|
||||
('HP Inc.', 'https://www.hp.com'),
|
||||
('Lenovo', 'https://www.lenovo.com'),
|
||||
('Xerox', 'https://www.xerox.com'),
|
||||
('Zebra Technologies', 'https://www.zebra.com'),
|
||||
('Cisco', 'https://www.cisco.com'),
|
||||
('Brother', 'https://www.brother.com'),
|
||||
('Microsoft', 'https://www.microsoft.com'),
|
||||
]
|
||||
|
||||
|
||||
@setup_bp.route('/seed-starter', methods=['POST'])
|
||||
@jwt_required()
|
||||
@require_role('admin')
|
||||
def seed_starter():
|
||||
"""Add common vendors that are not already present. Idempotent."""
|
||||
existing = {v.vendor.strip().lower() for v in Vendor.query.all()}
|
||||
added = []
|
||||
for name, website in STARTER_VENDORS:
|
||||
if name.strip().lower() in existing:
|
||||
continue
|
||||
db.session.add(Vendor(vendor=name, website=website))
|
||||
added.append(name)
|
||||
db.session.commit()
|
||||
return success_response(
|
||||
{'added': added, 'addedcount': len(added)},
|
||||
message=f'Seeded {len(added)} vendor(s).'
|
||||
)
|
||||
|
||||
|
||||
@setup_bp.route('/complete', methods=['POST'])
|
||||
@jwt_required()
|
||||
@require_role('admin')
|
||||
def mark_complete():
|
||||
"""Flag the first-run setup as finished."""
|
||||
row = Setting.query.filter_by(key='setup_complete').first()
|
||||
if row:
|
||||
row.value = 'true'
|
||||
else:
|
||||
db.session.add(Setting(key='setup_complete', value='true',
|
||||
valuetype='boolean', category='site'))
|
||||
db.session.commit()
|
||||
return success_response({'complete': True}, message='Setup marked complete.')
|
||||
Reference in New Issue
Block a user