162 lines
6 KiB
Python
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
|