diff --git a/app.py b/app.py index 5216b08..dab939f 100644 --- a/app.py +++ b/app.py @@ -38,7 +38,7 @@ init_app(app) app.register_blueprint(timer, url_prefix='/timer') app.register_blueprint(test, url_prefix='/test') app.register_blueprint(home, url_prefix='/home') -app.register_blueprint(http, url_prefix='/dashboard/http_functions') +app.register_blueprint(http, url_prefix='/http') class User(UserMixin): def __init__(self, id, username, password_hash, created_at): @@ -123,11 +123,7 @@ def documentation(): @ app.route("/dashboard", methods=["GET"]) @login_required def dashboard(): - user_id = current_user.id - http_functions = db.get_http_functions_for_user(user_id) - http_functions = create_http_functions_view_model(http_functions) - return render_template("dashboard/http_functions/overview.html", http_functions=http_functions) - + return redirect(url_for("home.index")) def _generate_script_from_natural_language(natural_query): """Generates a Javascript function from natural language using Gemini REST API.""" diff --git a/routes/http.py b/routes/http.py index ea9e5ca..af76b17 100644 --- a/routes/http.py +++ b/routes/http.py @@ -30,7 +30,7 @@ DECLARE next_version INT; BEGIN IF TG_OP = 'INSERT' THEN - INSERT INTO http_function_versions (http_function_id, script_content, version_number) + INSERT INTO http_functions_versions (http_function_id, script_content, version_number) VALUES (NEW.id, NEW.script_content, 1); UPDATE http_functions @@ -43,10 +43,10 @@ BEGIN IF NEW.script_content IS DISTINCT FROM OLD.script_content THEN SELECT COALESCE(MAX(version_number), 0) + 1 INTO next_version - FROM http_function_versions + FROM http_functions_versions WHERE http_function_id = NEW.id; - INSERT INTO http_function_versions (http_function_id, script_content, version_number) + INSERT INTO http_functions_versions (http_function_id, script_content, version_number) VALUES (NEW.id, NEW.script_content, next_version); UPDATE http_functions @@ -101,51 +101,52 @@ DEFAULT_ENVIRONMENT = """{ http = Blueprint('http', __name__) -@http.route("/", methods=["GET"]) +@http.route("/overview", methods=["GET"]) @login_required -def dashboard_http_functions(): +def overview(): user_id = current_user.id - http_functions = db.get_http_functions_for_user(user_id) + http_functions = db.execute( + 'SELECT id, user_id, NAME, script_content, invoked_count, environment_info, is_public, log_request, log_response, version_number FROM http_functions WHERE user_id=%s ORDER by id DESC', [user_id]) http_functions = create_http_functions_view_model(http_functions) if htmx: return render_block(environment, "dashboard/http_functions/overview.html", "page", http_functions=http_functions) return render_template("dashboard/http_functions/overview.html", http_functions=http_functions) -@http.route("/add_form", methods=["GET"]) +@http.route("/new", methods=["GET", "POST"]) @login_required -def get_http_function_add_form(): +def new(): user_id = current_user.id - if htmx: - return render_block(environment, 'dashboard/http_functions/new.html', 'page', user_id=user_id, name='foo', script=DEFAULT_SCRIPT, environment_info=DEFAULT_ENVIRONMENT, is_public=False, log_request=True, log_response=False) - return render_template("dashboard/http_functions/new.html", user_id=user_id, name='foo', script=DEFAULT_SCRIPT, environment_info=DEFAULT_ENVIRONMENT, is_public=False, log_request=True, log_response=False) - - -@http.route("/create", methods=["POST"]) -@login_required -def create_http_function(): + if request.method == "GET": + if htmx: + return render_block(environment, 'dashboard/http_functions/new.html', 'page', user_id=user_id, name='foo', script=DEFAULT_SCRIPT, environment_info=DEFAULT_ENVIRONMENT, is_public=False, log_request=True, log_response=False) + return render_template("dashboard/http_functions/new.html", user_id=user_id, name='foo', script=DEFAULT_SCRIPT, environment_info=DEFAULT_ENVIRONMENT, is_public=False, log_request=True, log_response=False) try: - user_id = current_user.id - name = request.form.get('name') - script_content = request.form.get('script_content') - environment_info = request.form.get('environment_info') - is_public = request.form.get('is_public') - log_request = request.form.get('log_request') - log_response = request.form.get('log_response') - - db.create_new_http_function(user_id, name, script_content, environment_info, is_public, log_request, log_response) + name = request.json.get('name') + script_content = request.json.get('script_content') + environment_info = request.json.get('environment_info') + is_public = request.json.get('is_public') + log_request = request.json.get('log_request') + log_response = request.json.get('log_response') - http_functions = db.get_http_functions_for_user(user_id) - http_functions = create_http_functions_view_model(http_functions) - return render_block(environment, "dashboard/http_functions/overview.html", "page", http_functions=http_functions), 200, {"HX-Push-Url": url_for('http.dashboard_http_functions')} + db.execute( + 'INSERT INTO http_functions (user_id, NAME, script_content, environment_info, is_public, log_request, log_response) VALUES (%s, %s, %s, %s, %s, %s, %s)', + [user_id, name, script_content, environment_info, is_public, log_request, log_response], + commit=True + ) + + return jsonify({ + "status": "success", + "message": "Http function created successfully" + }), 200 except Exception as e: print(e) return { "status": "error", "message": str(e) } -@http.route("//edit", methods=["POST"]) +@http.route("/edit/", methods=["POST"]) @login_required -def edit_http_function(function_id): +def edit(function_id): try: user_id = current_user.id name = request.json.get('name') @@ -155,35 +156,45 @@ def edit_http_function(function_id): log_request = request.json.get('log_request') log_response = request.json.get('log_response') - updated_version = db.edit_http_function(user_id, function_id, name, script_content, environment_info, is_public, log_request, log_response) + updated_version = db.execute( + 'UPDATE http_functions SET NAME=%s, script_content=%s, environment_info=%s, is_public=%s, log_request=%s, log_response=%s WHERE user_id=%s AND id=%s RETURNING version_number', + [name, script_content, environment_info, is_public, log_request, log_response, user_id, function_id], + commit=True, one=True + ) return { "status": "success", "message": f'{name} updated' } except Exception as e: print(e) return { "status": "error", "message": str(e) } -@http.route("//delete", methods=["DELETE"]) +@http.route("/delete/", methods=["DELETE"]) @login_required -def delete_http_function(function_id): +def delete(function_id): try: user_id = current_user.id - db.delete_http_function(user_id, function_id) + + db.execute( + 'DELETE FROM http_functions WHERE user_id=%s AND id=%s', [user_id, function_id], commit=True) - http_functions = db.get_http_functions_for_user(user_id) - http_functions = create_http_functions_view_model(http_functions) - return render_block(environment, "dashboard/http_functions/overview.html", "page", http_functions=http_functions), 200, {"HX-Push-Url": url_for('http.dashboard_http_functions')} + return { "status": "success", "message": f'Function deleted' } except Exception as e: return jsonify({"status": 'error', "message": str(e)}), 500 -@http.route("//logs", methods=["GET"]) +@http.route("/logs/", methods=["GET"]) @login_required -def get_http_function_logs(function_id): +def logs(function_id): user_id = current_user.id - http_function = db.get_http_function_by_id(user_id, function_id) + http_function = db.execute( + 'SELECT id, user_id, NAME, script_content, invoked_count, environment_info, is_public, log_request, log_response, version_number, created_at FROM http_functions WHERE user_id=%s AND id=%s', + [user_id, function_id], one=True) if not http_function: return jsonify({'error': 'Function not found'}), 404 name = http_function['name'] - http_function_invocations = db.get_http_function_invocations(function_id) + http_function_invocations = db.execute(""" + SELECT id, http_function_id, STATUS, invocation_time, request_data, response_data, LOGS, version_number + FROM http_function_invocations + WHERE http_function_id=%s + ORDER BY invocation_time DESC""", [function_id]) if htmx: return render_block(environment, 'dashboard/http_functions/logs.html', 'page', user_id=user_id, function_id=function_id, name=name, http_function_invocations=http_function_invocations) return render_template("dashboard/http_functions/logs.html", user_id=user_id, name=name, function_id=function_id, http_function_invocations=http_function_invocations) @@ -192,7 +203,9 @@ def get_http_function_logs(function_id): @login_required def client(function_id): user_id = current_user.id - http_function = db.get_http_function_by_id(user_id, function_id) + http_function = db.execute( + 'SELECT id, user_id, NAME, script_content, invoked_count, environment_info, is_public, log_request, log_response, version_number, created_at FROM http_functions WHERE user_id=%s AND id=%s', + [user_id, function_id], one=True) if not http_function: return jsonify({'error': 'Function not found'}), 404 @@ -201,44 +214,46 @@ def client(function_id): return render_block(environment, 'dashboard/http_functions/client.html', 'page', function_id=function_id, **http_function) return render_template("dashboard/http_functions/client.html", function_id=function_id, **http_function) -@http.route("//history", methods=["GET"]) +@http.route('/history/') @login_required -def get_http_function_history(function_id): - user_id = current_user.id - http_function = db.get_http_function_by_id(user_id, function_id) +def history(function_id): + # Fetch the http function to verify ownership + http_function = db.execute(""" + SELECT id, name, script_content AS code, version_number + FROM http_functions + WHERE id = %s AND user_id = %s + """, [function_id, current_user.id], one=True) + if not http_function: - return jsonify({'error': 'Function not found'}), 404 - - name = http_function['name'] - version_number = http_function['version_number'] - original_script = http_function['script_content'] if version_number == 1 else None + flash('Http function not found', 'error') + return redirect(url_for('http.overview')) - http_function_history = [] - if version_number > 1: - raw_history = db.get_http_function_history(function_id) + # Fetch all versions + versions = db.execute(""" + SELECT version_number, script_content AS script, updated_at AS versioned_at + FROM http_functions_versions + WHERE http_function_id = %s + ORDER BY version_number DESC + """, [function_id]) - for i in range(len(raw_history) - 1): - pre_version = raw_history[i + 1] - post_version = raw_history[i] + # Convert datetime objects to ISO format strings + for version in versions: + version['versioned_at'] = version['versioned_at'].isoformat() if version['versioned_at'] else None - http_function_history.append({ - 'pre': pre_version['script_content'], - 'post': post_version['script_content'], - 'version_id': post_version['version_id'], - 'version_number': post_version['version_number'], - 'updated_at': post_version['updated_at'] - }) - - if raw_history: - original_script = raw_history[-1]['script_content'] + args = { + 'user_id': current_user.id, + 'function_id': function_id, + 'http_function': http_function, + 'versions': versions + } if htmx: - return render_block(environment, 'dashboard/http_functions/history.html', 'page', user_id=user_id, function_id=function_id, name=name, http_function=http_function, http_function_history=http_function_history, original_script=original_script) - return render_template("dashboard/http_functions/history.html", user_id=user_id, name=name, function_id=function_id, http_function=http_function, http_function_history=http_function_history, original_script=original_script) + return render_block(environment, 'dashboard/http_functions/history.html', 'page', **args) + return render_template('dashboard/http_functions/history.html', **args) @http.route("/editor/", methods=["GET"]) @login_required -def http_function_editor(function_id): +def editor(function_id): user_id = current_user.id http_function = db.get_http_function_by_id(user_id, function_id) if not http_function: @@ -257,104 +272,11 @@ def http_function_editor(function_id): 'user_id': user_id, 'function_id': function_id, # Add new URLs for navigation - 'cancel_url': url_for('http.dashboard_http_functions'), - 'edit_url': url_for('http.http_function_editor', function_id=function_id), + 'cancel_url': url_for('http.overview'), + 'edit_url': url_for('http.editor', function_id=function_id), } if htmx: return render_block(environment, "dashboard/http_functions/editor.html", "page", **editor_data) - return render_template("dashboard/http_functions/editor.html", **editor_data) -@http.route("/api", methods=["POST"]) -@login_required -def api_create_http_function(): - try: - user_id = current_user.id - data = request.get_json() - name = data.get('name') - script_content = data.get('script_content') - environment_info = data.get('environment_info') - is_public = data.get('is_public') - log_request = data.get('log_request') - log_response = data.get('log_response') - - # Check if function with same name already exists for this user - existing_function = db.get_http_function(user_id, name) - if existing_function: - return jsonify({ - "status": "error", - "message": f"A function with the name '{name}' already exists" - }), 400 - - http_function = db.create_new_http_function( - user_id, - name, - script_content, - environment_info, - is_public, - log_request, - log_response - ) - - return jsonify({ - "status": "success", - "message": f'{name} created', - "function": http_function - }) - except Exception as e: - return jsonify({ - "status": "error", - "message": str(e) - }), 400 - -@http.route("/api/", methods=["POST"]) -@login_required -def api_update_http_function(function_id): - try: - user_id = current_user.id - data = request.get_json() - name = data.get('name') - script_content = data.get('script_content') - environment_info = data.get('environment_info') - is_public = data.get('is_public') - log_request = data.get('log_request') - log_response = data.get('log_response') - - updated_function = db.edit_http_function( - user_id, - function_id, - name, - script_content, - environment_info, - is_public, - log_request, - log_response - ) - - return jsonify({ - "status": "success", - "message": f'{name} updated', - "function": updated_function - }) - except Exception as e: - return jsonify({ - "status": "error", - "message": str(e) - }), 400 - -@http.route("/api/", methods=["DELETE"]) -@login_required -def api_delete_http_function(function_id): - try: - user_id = current_user.id - db.delete_http_function(user_id, function_id) - - return jsonify({ - "status": "success", - "message": "Function deleted successfully" - }) - except Exception as e: - return jsonify({ - "status": "error", - "message": str(e) - }), 400 \ No newline at end of file + return render_template("dashboard/http_functions/editor.html", **editor_data) \ No newline at end of file diff --git a/static/js/mithril/editor.js b/static/js/mithril/editor.js index ed35c5c..1b0bc11 100644 --- a/static/js/mithril/editor.js +++ b/static/js/mithril/editor.js @@ -168,6 +168,9 @@ const Editor = { name: this.name, script_content: this.jsValue, environment_info: this.jsonValue, + is_public: this.isPublic, + log_request: this.logRequest, + log_response: this.logResponse, }; const response = await m.request({ diff --git a/templates/dashboard.html b/templates/dashboard.html index d321315..b8a8c59 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -33,10 +33,9 @@ Home + data-id="15" hx-get="{{ url_for('http.overview') }}" hx-target="#container" hx-swap="innerHTML" + hx-push-url="true"> diff --git a/templates/dashboard/home.html b/templates/dashboard/home.html index 5fa06c7..70780e5 100644 --- a/templates/dashboard/home.html +++ b/templates/dashboard/home.html @@ -270,7 +270,7 @@ class="inline-flex items-center justify-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200"> View Timer Functions - View HTTP Functions diff --git a/templates/dashboard/http_functions/client.html b/templates/dashboard/http_functions/client.html index d6f1f1f..4982000 100644 --- a/templates/dashboard/http_functions/client.html +++ b/templates/dashboard/http_functions/client.html @@ -8,10 +8,10 @@ show_edit_form=True, show_logs=True, show_client=True, show_history=True, -edit_url=url_for('http.http_function_editor', function_id=function_id), -cancel_url=url_for('http.dashboard_http_functions'), -logs_url=url_for('http.get_http_function_logs', function_id=function_id), -history_url=url_for('http.get_http_function_history', function_id=function_id)) }} +edit_url=url_for('http.editor', function_id=function_id), +cancel_url=url_for('http.overview'), +logs_url=url_for('http.logs', function_id=function_id), +history_url=url_for('http.history', function_id=function_id)) }}
diff --git a/templates/dashboard/http_functions/editor.html b/templates/dashboard/http_functions/editor.html index c1f536e..876621c 100644 --- a/templates/dashboard/http_functions/editor.html +++ b/templates/dashboard/http_functions/editor.html @@ -10,8 +10,8 @@ show_client=True, show_history=True, edit_url=edit_url, cancel_url=cancel_url, -logs_url=url_for('http.get_http_function_logs', function_id=function_id), -history_url=url_for('http.get_http_function_history', function_id=function_id)) }} +logs_url=url_for('http.logs', function_id=function_id), +history_url=url_for('http.history', function_id=function_id)) }}
@@ -33,8 +33,9 @@ history_url=url_for('http.get_http_function_history', function_id=function_id)) logResponse: {{ log_response | tojson }}, versionNumber: {{ version_number }}, executeUrl: "{{ url_for('execute_code', playground='true') }}", - saveUrl: "{{ url_for('http.api_update_http_function', function_id=id) if id else url_for('http.api_create_http_function') }}", - deleteUrl: "{{ url_for('http.api_delete_http_function', function_id=id) if id else '' }}", + saveUrl: "{{ url_for('http.edit', function_id=id) if id else url_for('http.new') }}", + deleteUrl: "{{ url_for('http.delete', function_id=id) if id else '' }}", + cancelUrl: "{{ url_for('http.overview') }}", showDeleteButton: true }) }) diff --git a/templates/dashboard/http_functions/history.html b/templates/dashboard/http_functions/history.html index 64f51e5..e4285d2 100644 --- a/templates/dashboard/http_functions/history.html +++ b/templates/dashboard/http_functions/history.html @@ -8,196 +8,17 @@ show_edit_form=True, show_logs=True, show_client=True, show_history=True, -edit_url=url_for('http.http_function_editor', function_id=function_id), -cancel_url=url_for('http.dashboard_http_functions'), -logs_url=url_for('http.get_http_function_logs', function_id=function_id), -history_url=url_for('http.get_http_function_history', function_id=function_id)) }} - - -
- {% if http_function.version_number > 1 %} - {% for entry in http_function_history %} - -
- -
- {{ entry.updated_at.strftime('%b %d %Y %I:%M %p').lstrip("0").replace(" - 0", " ") }} - -
- - - -
-
-
-
-
- - - -
-

- v{{ entry.version_number }} -

-

-

- - - -
- -
-
-
-
- - - - {% endfor %} - -
- -
- {{ http_function.created_at.strftime('%b %d %Y %I:%M - %p').lstrip("0").replace(" - 0", " ") }} - -
- - - -
-
-
-
-
- - - -
-

- v1 -

-

-

- -
- -
- -
{{ original_script }}
- - - {% else %} - - -
- -
- {{ http_function.created_at.strftime('%b %d %Y %I:%M - %p').lstrip("0").replace(" - 0", " ") }} - -
- - - -
-
-
-
-
- - - -
-

- v1 -

-

-

- -
- - -
- -
{{ original_script }}
- - - - {% endif %} - -
- +edit_url=url_for('http.editor', function_id=function_id), +cancel_url=url_for('http.overview'), +logs_url=url_for('http.logs', function_id=function_id), +history_url=url_for('http.history', function_id=function_id)) }} +
+ {% endblock %} \ No newline at end of file diff --git a/templates/dashboard/http_functions/logs.html b/templates/dashboard/http_functions/logs.html index c3096c4..2ca6685 100644 --- a/templates/dashboard/http_functions/logs.html +++ b/templates/dashboard/http_functions/logs.html @@ -8,10 +8,10 @@ show_edit_form=True, show_logs=True, show_client=True, show_history=True, -edit_url=url_for('http.http_function_editor', function_id=function_id), -cancel_url=url_for('http.dashboard_http_functions'), -logs_url=url_for('http.get_http_function_logs', function_id=function_id), -history_url=url_for('http.get_http_function_history', function_id=function_id)) }} +edit_url=url_for('http.editor', function_id=function_id), +cancel_url=url_for('http.overview'), +logs_url=url_for('http.logs', function_id=function_id), +history_url=url_for('http.history', function_id=function_id)) }}
diff --git a/templates/dashboard/http_functions/new.html b/templates/dashboard/http_functions/new.html index 8fcd785..5776e35 100644 --- a/templates/dashboard/http_functions/new.html +++ b/templates/dashboard/http_functions/new.html @@ -9,8 +9,8 @@ show_refresh=False, show_logs=False, show_client=False, show_link=False, -dashboardUrl=url_for('http.dashboard_http_functions'), -cancel_url=url_for('http.dashboard_http_functions'), +dashboardUrl=url_for('http.overview'), +cancel_url=url_for('http.overview'), title='New HTTP Function') }} @@ -32,9 +32,9 @@ title='New HTTP Function') logRequest: {{ log_request | tojson }}, logResponse: {{ log_response | tojson }}, executeUrl: "{{ url_for('execute_code', playground='true') }}", - saveUrl: "{{ url_for('http.api_create_http_function') }}", + saveUrl: "{{ url_for('http.new') }}", showDeleteButton: false, - dashboardUrl: "{{ url_for('http.dashboard_http_functions') }}" + dashboardUrl: "{{ url_for('http.overview') }}" }) }) diff --git a/templates/dashboard/http_functions/overview.html b/templates/dashboard/http_functions/overview.html index 0342c9e..c36b5e1 100644 --- a/templates/dashboard/http_functions/overview.html +++ b/templates/dashboard/http_functions/overview.html @@ -7,8 +7,7 @@

HTTP Functions