Add personal API tokens; wire measuring tools into remaining surfaces
API tokens: any user mints named, optionally-expiring tokens (shopdb_pat_..., sha256-stored, secret shown once) at Settings > API Tokens; a before-request shim swaps a valid PAT for a request-scoped JWT of its owner, so the entire existing auth/authz/import-mode stack works unchanged and revoked/expired tokens 401 cleanly. Built for long-running scripts - the legacy import no longer dies when a login JWT expires. Migration 7d21_apitokens; create/revoke audit-logged. Audited integration gaps fixed: Asset.to_dict serializes measuring tools (typedata + pluginid - relationship links to tools resolve); map subtype filter/colors and MapEditor include them; dashboard totals count them; warranty links use a new by-asset route; the measuringtools ADR-010 hooks are real (corrected presentation token, implemented map-overlay endpoint); the login avatar resolves through the employee-photo helper. 737 tests pass; naming green; frontend builds; both features verified live end-to-end. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -913,6 +913,14 @@ def get_assets_map():
|
||||
)
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
try:
|
||||
from plugins.measuringtools.models import MeasuringTool
|
||||
eager_options.append(
|
||||
subqueryload(Asset.measuringtool)
|
||||
.joinedload(MeasuringTool.measuringtooltype)
|
||||
)
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
|
||||
query = Asset.query.options(*eager_options).filter(
|
||||
Asset.isactive == True,
|
||||
@@ -941,7 +949,10 @@ def get_assets_map():
|
||||
# Filter by subtype (depends on asset type) - case-insensitive matching
|
||||
if subtype_id := request.args.get('subtype'):
|
||||
subtype_id = int(subtype_id)
|
||||
asset_type_lower = selected_assettype.lower() if selected_assettype else ''
|
||||
# Normalize the underscore DB form (measuring_tool, network_device) to
|
||||
# the space form the branches below compare against.
|
||||
asset_type_lower = (
|
||||
selected_assettype.lower().replace('_', ' ') if selected_assettype else '')
|
||||
if asset_type_lower == 'machine':
|
||||
try:
|
||||
from plugins.machines.models import Machine
|
||||
@@ -974,6 +985,15 @@ def get_assets_map():
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
elif asset_type_lower == 'measuring tool':
|
||||
try:
|
||||
from plugins.measuringtools.models import MeasuringTool
|
||||
query = query.join(
|
||||
MeasuringTool, MeasuringTool.assetid == Asset.assetid).filter(
|
||||
MeasuringTool.measuringtooltypeid == subtype_id
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Filter by business unit
|
||||
if bu_id := request.args.get('businessunitid'):
|
||||
@@ -1100,6 +1120,14 @@ def get_assets_map():
|
||||
except ImportError:
|
||||
subtypes['Printer'] = []
|
||||
|
||||
try:
|
||||
from plugins.measuringtools.models import MeasuringToolType
|
||||
measuringtool_types = MeasuringToolType.query.filter(
|
||||
MeasuringToolType.isactive == True).order_by(MeasuringToolType.name).all()
|
||||
subtypes['Measuring Tool'] = [{'id': mt.measuringtooltypeid, 'name': mt.name, 'color': mt.color} for mt in measuringtool_types]
|
||||
except ImportError:
|
||||
subtypes['Measuring Tool'] = []
|
||||
|
||||
return success_response({
|
||||
'assets': data,
|
||||
'total': len(data),
|
||||
|
||||
Reference in New Issue
Block a user