diff --git a/inventory/routes/helpers.py b/inventory/routes/helpers.py index 53bc469..356d169 100644 --- a/inventory/routes/helpers.py +++ b/inventory/routes/helpers.py @@ -1,7 +1,10 @@ +import base64 +import csv import hashlib +import io import os -from flask import url_for +from flask import url_for, jsonify from ..models import Inventory @@ -82,3 +85,22 @@ def get_image_attachable_class_by_name(name: str): 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) + }) \ No newline at end of file diff --git a/inventory/routes/inventory.py b/inventory/routes/inventory.py index 48855a1..0100936 100644 --- a/inventory/routes/inventory.py +++ b/inventory/routes/inventory.py @@ -7,7 +7,7 @@ from flask import request, render_template, url_for, jsonify from sqlalchemy.inspection import inspect from . import main -from .helpers import FILTER_MAP, inventory_headers, worklog_headers +from .helpers import FILTER_MAP, inventory_headers, worklog_headers, make_csv from .. import db from ..models import Inventory, User, Room, Item, RoomFunction, Brand, WorkLog @@ -237,9 +237,6 @@ def get_inventory_csv(): return jsonify({"success": False, "error": "No IDs provided"}), 400 rows = eager_load_inventory_relationships(db.session.query(Inventory).filter(Inventory.id.in_(ids))).all() - - output = io.StringIO() - writer = csv.writer(output) columns = [ "id", @@ -257,19 +254,7 @@ def get_inventory_csv(): "shared" ] - writer.writerow(columns) - - for item in rows: - writer.writerow([export_value(item, 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) - }) + return make_csv(export_value, columns, rows) @main.route("/inventory_available") def inventory_available(): diff --git a/inventory/routes/user.py b/inventory/routes/user.py index fb70c9a..91c2812 100644 --- a/inventory/routes/user.py +++ b/inventory/routes/user.py @@ -5,7 +5,7 @@ import io from flask import render_template, request, jsonify from . import main -from .helpers import ACTIVE_STATUSES, user_headers, inventory_headers, worklog_headers +from .helpers import ACTIVE_STATUSES, user_headers, inventory_headers, worklog_headers, make_csv from .. import db from ..utils.load import eager_load_user_relationships, eager_load_room_relationships, eager_load_inventory_relationships, eager_load_worklog_relationships from ..models import User, Room, Inventory, WorkLog @@ -148,9 +148,6 @@ def get_user_csv(): return jsonify({"success": False, "error": "No IDs provided"}), 400 rows = eager_load_user_relationships(db.session.query(User).filter(User.id.in_(ids))).all() - - output = io.StringIO() - writer = csv.writer(output) columns = [ "id", @@ -162,16 +159,4 @@ def get_user_csv(): "supervisor" ] - writer.writerow(columns) - - for user in rows: - writer.writerow([export_value(user, 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) - }) \ No newline at end of file + return make_csv(export_value, columns, rows) diff --git a/inventory/routes/worklog.py b/inventory/routes/worklog.py index 3604cb6..57798d5 100644 --- a/inventory/routes/worklog.py +++ b/inventory/routes/worklog.py @@ -6,7 +6,7 @@ import io from flask import request, render_template, jsonify from . import main -from .helpers import worklog_headers +from .helpers import worklog_headers, make_csv from .. import db from ..models import WorkLog, User, Inventory, WorkNote from ..utils.load import eager_load_worklog_relationships, eager_load_user_relationships, eager_load_inventory_relationships @@ -172,9 +172,6 @@ def get_worklog_csv(): return jsonify({"success": False, "error": "No IDs provided"}), 400 rows = eager_load_worklog_relationships(db.session.query(WorkLog).filter(WorkLog.id.in_(ids))).all() - - output = io.StringIO() - writer = csv.writer(output) columns = [ "id", @@ -188,16 +185,10 @@ def get_worklog_csv(): "latest_update" ] - writer.writerow(columns) + return make_csv(export_value, columns, rows) - for user in rows: - writer.writerow([export_value(user, 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) - }) \ No newline at end of file + # return jsonify({ + # "success": True, + # "csv": base64.b64encode(csv_string.encode()).decode(), + # "count": len(rows) + # }) \ No newline at end of file diff --git a/inventory/static/js/csv.js b/inventory/static/js/csv.js new file mode 100644 index 0000000..a484dc1 --- /dev/null +++ b/inventory/static/js/csv.js @@ -0,0 +1,35 @@ +async function export_csv(ids, csv_route) { + const payload = ids; + + try { + const response = await fetch(`/api/${csv_route}/export`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json" + }, + body: JSON.stringify(payload) + }); + + const result = await response.json(); + + if (result.success) { + const decodedCsv = atob(result.csv); + const blob = new Blob([decodedCsv], { type: "text/csv" }); + const url = URL.createObjectURL(blob); + + const link = document.createElement("a"); + link.href = url; + link.download = `${csv_route}_export.csv`; + link.click(); + + console.log(url); + + URL.revokeObjectURL(url); + } else { + renderToast({ message: `Export failed: ${result.error}`, type: 'danger' }); + } + } catch (err) { + renderToast({ message: `Export failed: ${err}`, type: 'danger' }); + } +} \ No newline at end of file diff --git a/inventory/templates/layout.html b/inventory/templates/layout.html index 4b9a81b..6b01a75 100644 --- a/inventory/templates/layout.html +++ b/inventory/templates/layout.html @@ -74,6 +74,7 @@ integrity="sha384-zqgMe4cx+N3TuuqXt4kWWDluM5g1CiRwqWBm3vpvY0GcDoXTwU8d17inavaLy3p3" crossorigin="anonymous"> +