Fetch http_functions from database

This commit is contained in:
Peter Stockings
2023-12-16 19:02:04 +11:00
parent 4796b7d8d1
commit e88661dfd2
5 changed files with 99 additions and 8 deletions

18
app.py
View File

@@ -4,11 +4,14 @@ import jinja_partials
from jinja2_fragments import render_block
from flask_htmx import HTMX
import requests
from db import DataBase
from services import create_http_functions_view_model
app = Flask(__name__)
app.config.from_pyfile('config.py')
jinja_partials.register_extensions(app)
htmx = HTMX(app)
db = DataBase(app)
API_URL = 'https://isolator.peterstockings.com/execute'
@@ -62,11 +65,15 @@ def client():
@ app.route("/dashboard", methods=["GET"])
def dashboard():
return render_template("dashboard.html")
http_functions = db.get_http_functions()
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard.html", http_functions=http_functions)
@ app.route("/dashboard/http_functions", methods=["GET"])
def dashboard_http_functions():
return render_template("dashboard/http_functions.html")
http_functions = db.get_http_functions()
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard/http_functions.html", http_functions=http_functions)
@ app.route("/dashboard/timer_functions", methods=["GET"])
def dashboard_timer_functions():
@@ -105,8 +112,13 @@ def execute_code():
@app.route('/f/<function>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'])
def execute_http_function(function):
try:
http_function = db.get_http_function(function)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
# TODO: Get code from database based on function name
code = DEFAULT_SCRIPT
code = http_function['script_content']
print(code)
request_obj = {
'method': request.method,

59
db.py Normal file
View File

@@ -0,0 +1,59 @@
import os
import psycopg2
import numpy as np
from psycopg2.extras import RealDictCursor
from datetime import datetime
from urllib.parse import urlparse
from flask import g
class DataBase():
def __init__(self, app):
db_url = urlparse(os.environ['DATABASE_URL'])
# if db_url is null then throw error
if not db_url:
raise Exception("No DATABASE_URL environment variable set")
def getDB(self):
db = getattr(g, 'database', None)
if db is None:
db_url = urlparse(os.environ['DATABASE_URL'])
g.database = psycopg2.connect(
database=db_url.path[1:],
user=db_url.username,
password=db_url.password,
host=db_url.hostname,
port=db_url.port
)
db = g.database
return db
def close_connection(exception):
db = getattr(g, 'database', None)
if db is not None:
db.close()
def execute(self, query, args=(), one=False, commit=False):
conn = self.getDB()
cur = conn.cursor(cursor_factory=RealDictCursor)
cur.execute(query, args)
rv = None
if cur.description is not None:
rv = cur.fetchall()
if commit:
try:
conn.commit()
except:
conn.rollback()
cur.close()
return (rv[0] if rv else None) if one else rv
def get_http_functions(self):
http_functions = self.execute(
'SELECT id, NAME, script_content, invoked_count FROM http_functions', [])
return http_functions
def get_http_function(self, name):
http_function = self.execute(
'SELECT id, NAME, script_content, invoked_count FROM http_functions WHERE NAME=%s', [name], one=True)
return http_function

18
services.py Normal file
View File

@@ -0,0 +1,18 @@
def create_http_functions_view_model(http_functions):
# Base URL for the function invocation
base_url = "https://function.peterstockings.com/f/"
view_model = []
for function in http_functions:
name = function['name']
function_view_model = {
"id": function['id'],
"name": name,
"script_content": function['script_content'],
"url": f"{base_url}{name}",
"invoke_count": function['invoked_count']
}
view_model.append(function_view_model)
return view_model

View File

@@ -87,7 +87,7 @@
<span class="sr-only" data-id="42">Toggle user menu</span></button>
</header>
<main class="flex flex-1 flex-col gap-4 p-4 md:gap-8 md:p-6" data-id="50" id="container">
{{ render_partial('dashboard/http_functions.html') }}
{{ render_partial('dashboard/http_functions.html', http_functions=http_functions) }}
</main>
</div>
</div>

View File

@@ -20,12 +20,12 @@
</tr>
</thead>
<tbody class="[&amp;_tr:last-child]:border-0" data-id="62">
{% for function in http_functions %}
<tr class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted" data-id="63">
<td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 font-medium cursor-pointer"
data-id="66">HelloWorld</td>
data-id="66">{{ function.name }}</td>
<td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 hidden md:table-cell" data-id="67">
<a
href="https://function.peterstockings.com/f/helloworld">https://function.peterstockings.com/f/helloworld</a>
<a href="{{ function.url }}">{{ function.url }}</a>
<button
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground px-4 text-gray-600 dark:text-gray-400"
data-id="24"><span class="sr-only" data-id="25">Add Link</span><svg
@@ -44,8 +44,10 @@
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 mr-2"
data-id="69">Edit</button><button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-9 rounded-md px-3"
data-id="70">Delete</button></td>
data-id="70">Delete</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>