from flask import Flask, render_template, request, redirect, url_for from werkzeug.utils import secure_filename import json import sqlite3 from dotenv import load_dotenv from pathlib import Path import os class PrefixMiddleware(object): def __init__(self, app, prefix=""): self.app = app self.prefix = prefix def __call__(self, environ, start_response): if environ["PATH_INFO"].startswith(self.prefix): environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix) :] environ["SCRIPT_NAME"] = self.prefix return self.app(environ, start_response) else: start_response("404", [("Content-Type", "text/plain")]) return ["This url does not belong to the app.".encode()] load_dotenv() Path(f'static/panels/').mkdir(exist_ok=True) Path(f'static/cables/').mkdir(exist_ok=True) Path(f'static/snippets/').mkdir(exist_ok=True) app = Flask(__name__) # register the middleware to prefix all the requests with our base_url app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=os.environ.get('BASE_URL', '')) def get_db_connection(): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row return conn def dict_from_row(row): return dict(zip(row.keys(), row)) def create_instrument(name, description, params, sockets, panel): slug = secure_filename(name) panel.save(f'static/panels/{slug}.svg') connection = get_db_connection() cur = connection.cursor() cur.execute( "INSERT INTO instruments (name, slug, description, panel) VALUES (?, ?, ?, ?)", (name, slug, description, f'{slug}.svg') ) instrument_id = cur.lastrowid for param in params: cur.execute( "INSERT OR IGNORE INTO params (param_name) VALUES (?)",(param,) ) cur.execute( "INSERT INTO instrument_param (instrument, param_name) VALUES (?, ?)", (slug, param ) ) for socket in sockets: cur.execute( "INSERT OR IGNORE INTO sockets (socket_name) VALUES (?)", (socket,) ) cur.execute( "INSERT INTO instrument_socket (instrument, socket_name) VALUES (?, ?)", (slug, socket ) ) connection.commit() connection.close() @app.route("/") def workbook(): return render_template('workbook.html') @app.route("/") def page(slug): return render_template(f'{slug}.html') @app.route("/instruments") def instruments(): connection = get_db_connection() instruments = connection.execute('SELECT * FROM instruments').fetchall() connection.close() return render_template('instruments.html', instruments=instruments) @app.route("/instruments/") def patches(instrument): with open(f'static/panels/{instrument}.svg', 'r') as f: panel = f.read() connection = get_db_connection() cursor = connection.cursor() instrument = cursor.execute("SELECT * FROM instruments WHERE slug = ?", (instrument, )).fetchone() instrument = dict_from_row(instrument) patches = cursor.execute("SELECT * FROM patches WHERE instrument = ?", (instrument['slug'],)).fetchall() connection.close() return render_template('patches.html', instrument=instrument, patches=patches, panel=panel) @app.route("/instruments/add", methods=['GET', 'POST']) def add_instrument(): if request.method == 'POST': name = request.form.get('name') description = request.form.get('description') params = json.loads(request.form.get('params')) sockets = json.loads(request.form.get('sockets')) panel = request.files['panel'] create_instrument(name, description, params, sockets, panel) return redirect(url_for('instruments')) return render_template('add_instrument.html') @app.route("/instruments//add", methods=['GET', 'POST']) def add_patch(instrument): connection = get_db_connection() cursor = connection.cursor() if request.method == 'POST': patch = request.form.to_dict() patch = {k: v for k, v in patch.items() if v} slug = secure_filename(patch["name"]) with open(f'static/cables/{slug}.svg', 'w') as f: f.write(patch['cables']) cursor.execute( 'INSERT INTO patches (name, slug, description, cables, instrument) VALUES (?,?,?,?,?)', (patch['name'], slug, patch['description'], f"{slug}.svg", instrument) ) patch_id = cursor.lastrowid instrument_params = cursor.execute('SELECT param_name FROM instrument_param WHERE instrument = ?', (instrument,)).fetchall() instrument_sockets = cursor.execute('SELECT socket_name FROM instrument_socket WHERE instrument = ?', (instrument,)).fetchall() instrument_params = [row[0] for row in instrument_params] instrument_sockets = [row[0] for row in instrument_sockets] for key, value in patch.items(): destination = None if key in instrument_params: destination = 'param' elif key in instrument_sockets: destination = 'socket' if destination is not None: print(f'Insert {key} into {destination}') cursor.execute(f'INSERT INTO patch_{destination} (patch_id, {destination}_name, value) VALUES (?,?,?)', (patch_id, key, value)) connection.commit() connection.close() return redirect(url_for('patches', instrument=instrument)) with open(f'static/panels/{instrument}.svg', 'r') as f: panel = f.read() instrument = cursor.execute('SELECT * FROM instruments WHERE slug = ?', (instrument,)).fetchone() connection.close() return render_template('add_patch.html', instrument=instrument, panel = panel) @app.route("/instruments//", methods=['GET', 'POST']) def patch(instrument, name): if request.method == 'POST': connection = get_db_connection() cursor = connection.cursor() file = request.files['snippet'] if file: filename = secure_filename(file.filename) file.save(f'static/snippets/{instrument}_{name}_{filename}') cursor.execute('INSERT INTO snippets (filename, instrument, patch_name, description) VALUES (?,?,?,?)', (filename, instrument, name, request.form.get('description')) ) connection.commit() connection.close() redirect(url_for('patch', instrument=instrument, name=name)) connection = get_db_connection() cursor = connection.cursor() snippets = cursor.execute('SELECT * FROM snippets WHERE instrument = ? AND patch_name = ?', (instrument, name)).fetchall() patch = cursor.execute('SELECT * FROM patches WHERE instrument = ? AND slug = ?', (instrument, name)).fetchone() params = cursor.execute('SELECT * FROM patch_param WHERE patch_id = ?', (patch['id'],)).fetchall() sockets = cursor.execute('SELECT * FROM patch_socket WHERE patch_id = ?', (patch['id'],)).fetchall() instrument = cursor.execute('SELECT * FROM instruments WHERE slug = ?', (instrument,)).fetchone() with open(f'static/panels/{instrument["slug"]}.svg') as f: panel = f.read() connection.close() return render_template('patch.html', instrument=instrument, patch=patch, params=params, sockets=sockets, panel=panel, snippets=snippets) app.run(port=os.environ.get('FLASK_RUN_PORT'), debug=True)