inventory/inventory/routes/helpers.py

162 lines
6 KiB
Python

import base64
import csv
import hashlib
import io
import os
from flask import url_for, jsonify, request
from flask import current_app as app
from ..models import User, Inventory, WorkLog
from ..models.image import ImageAttachable
ROUTE_BREADCRUMBS = {
'main.user': {
'trail': [('Users', 'main.list_users')],
'model': User,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.user', id=i.id)
},
'main.inventory_item': {
'trail': [('Inventory', 'main.list_inventory')],
'model': Inventory,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.inventory_item', id=i.id)
},
'main.worklog': {
'trail': [('Work Log', 'main.list_worklog')],
'model': WorkLog,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.worklog', id=i.id)
}
}
inventory_headers = {
"Date Entered": lambda i: {"field": "timestamp", "text": i.timestamp.strftime("%Y-%m-%d") if i.timestamp else None},
"Identifier": lambda i: {"field": "identifier", "text": i.identifier},
"Name": lambda i: {"field": "name", "text": i.name},
"Serial Number": lambda i: {"field": "serial", "text": i.serial},
"Bar Code": lambda i: {"field": "barcode", "text": i.barcode},
"Brand": lambda i: {"field": "brand.name", "text": i.brand.name} if i.brand else {"text": None},
"Model": lambda i: {"field": "model", "text": i.model},
"Item Type": lambda i: {"field": "device_type.description", "text": i.device_type.description} if i.device_type else {"text": None},
"Shared?": lambda i: {"field": "shared", "text": i.shared, "type": "bool", "html": checked_box if i.shared else unchecked_box},
"Owner": lambda i: {"field": "owner.identifier", "text": i.owner.identifier, "url": url_for("main.user_item", id=i.owner.id)} if i.owner else {"text": None},
"Location": lambda i: {"field": "location.identifier", "text": i.location.identifier} if i.location else {"Text": None},
"Condition": lambda i: {"field": "condition", "text": i.condition}
}
checked_box = '''
<i class="bi bi-check2"></i>
'''
unchecked_box = ''
ACTIVE_STATUSES = [
"Working",
"Deployed",
"Partially Inoperable",
"Unverified"
]
INACTIVE_STATUSES = [
"Inoperable",
"Removed",
"Disposed"
]
FILTER_MAP = {
'user': Inventory.owner_id,
'location': Inventory.location_id,
'type': Inventory.type_id,
}
user_headers = {
"Last Name": lambda i: {"field": "last_name","text": i.last_name},
"First Name": lambda i: {"field": "first_name","text": i.first_name},
"Title": lambda i: {"field": "title","text": i.title},
"Supervisor": lambda i: {"field": "supervisor,identifier","text": i.supervisor.identifier, "url": url_for("main.user_item", id=i.supervisor.id)} if i.supervisor else {"text": None},
"Location": lambda i: {"field": "location,identifier","text": i.location.identifier} if i.location else {"text": None},
"Staff?": lambda i: {"field": "staff","text": i.staff, "type": "bool", "html": checked_box if i.staff else unchecked_box},
"Active?": lambda i: {"field": "active","text": i.active, "type": "bool", "html": checked_box if i.active else unchecked_box}
}
worklog_headers = {
"Contact": lambda i: {"text": i.contact.identifier, "url": url_for("main.user_item", id=i.contact.id)} if i.contact else {"Text": None},
"Work Item": lambda i: {"text": i.work_item.identifier, "url": url_for('main.inventory_item',id=i.work_item.id)} if i.work_item else {"text": None},
"Start Time": lambda i: {"text": i.start_time.strftime("%Y-%m-%d")},
"End Time": lambda i: {"text": i.end_time.strftime("%Y-%m-%d")} if i.end_time else {"text": None},
"Complete?": lambda i: {"text": i.complete, "type": "bool", "html": checked_box if i.complete else unchecked_box},
"Follow Up?": lambda i: {"text": i.followup, "type": "bool", "html": checked_box if i.followup else unchecked_box, "highlight": i.followup},
"Quick Analysis?": lambda i: {"text": i.analysis, "type": "bool", "html": checked_box if i.analysis else unchecked_box},
}
def link(text, endpoint, **values):
return {"text": text, "url": url_for(endpoint, **values)}
def generate_hashed_filename(file) -> str:
content = file.read()
file.seek(0) # Reset after reading
hash = hashlib.sha256(content).hexdigest()
ext = os.path.splitext(file.filename)[1]
return f"{hash}_{file.filename}"
def get_image_attachable_class_by_name(name: str):
for cls in ImageAttachable.__subclasses__():
if getattr(cls, '__tablename__', None) == name:
return cls
return None
def make_csv(export_func, columns, rows):
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(columns)
for row in rows:
writer.writerow([export_func(row, col) for col in columns])
csv_string = output.getvalue()
output.close()
return jsonify({
"success": True,
"csv": base64.b64encode(csv_string.encode()).decode(),
"count": len(rows)
})
def generate_breadcrumbs():
crumbs = []
endpoint = request.endpoint
view_args = request.view_args or {}
if endpoint in ROUTE_BREADCRUMBS:
print(endpoint, view_args)
config = ROUTE_BREADCRUMBS[endpoint]
for label, ep in config.get('trail', []):
crumbs.append({'label': label, 'url': url_for(ep)})
obj_id = view_args.get(config['arg'])
if obj_id:
obj = config['model'].query.get(obj_id)
if obj:
crumbs.append({
'label': getattr(obj, config['label_attr'], str(obj)),
'url': config['url_func'](obj)
})
else:
# fallback to ugly slashes
path = request.path.strip('/').split('/')
accumulated = ''
for segment in path:
accumulated += '/' + segment
crumbs.append({'label': segment.title(), 'url': accumulated})
return crumbs