From 96e6ae3bfc04127bf808ff7b51949b4640df5efa Mon Sep 17 00:00:00 2001 From: Chase Eller Date: Mon, 13 Apr 2026 04:33:39 -0400 Subject: [PATCH] Init Of work --- .gitignore | 4 ++ .vscode/launch.json | 14 ++++ README.md | 17 ++++- dockerfile | 15 ++++ main.py | 111 +++++++++++++++++++++++++++++ requirements.txt | 10 +++ static/style.css | 41 +++++++++++ templates/embed.html | 17 +++++ templates/graphs.html | 162 ++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 46 ++++++++++++ 10 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 dockerfile create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 static/style.css create mode 100644 templates/embed.html create mode 100644 templates/graphs.html create mode 100644 templates/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da652e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +/__pycache__ +/__pycache__ +*.pyc diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ee8422d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lua", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/Untitled-1.lua" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 28619b5..c163bc3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ -# STONKS +# stonk GUI App -Dev for handling stonk data so i can figure all this out web wise. \ No newline at end of file +## Setup + +1. Install dependencies: + pip install -r requirements.txt + +2. Update .env with your Authentik details + +3. Update DB connection string in main.py + +4. Run: + uvicorn main:app --reload + +5. Open: + http://localhost:8000 diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..9c0b476 --- /dev/null +++ b/dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim + +WORKDIR /usr/src/app + +# Install dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of your code (do not copy .env) +COPY . . + +# Expose port if web app +EXPOSE 8000 + +CMD ["python", "main.py"] \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..988f53b --- /dev/null +++ b/main.py @@ -0,0 +1,111 @@ +import os +from fastapi import FastAPI, Depends, Query +from fastapi.staticfiles import StaticFiles +from fastapi.responses import HTMLResponse +from sqlalchemy import create_engine, text +from dotenv import load_dotenv + +load_dotenv() + +DB_USER = os.getenv("DB_USER") +DB_PASS = os.getenv("DB_PASS") +DB_HOST = os.getenv("DB_HOST") +DB_NAME = os.getenv("DB_NAME") + +if not all([DB_USER, DB_PASS, DB_HOST, DB_NAME]): + raise EnvironmentError("Missing DB environment variables") + +app = FastAPI() + +engine = create_engine( + f"mysql+pymysql://{DB_USER}:{DB_PASS}@{DB_HOST}/{DB_NAME}", + pool_pre_ping=True +) + +app.mount("/static", StaticFiles(directory="static"), name="static") + + +# ----------------------- +# PAGE 1: DEFAULT / +# ----------------------- +@app.get("/") +async def index(): + with open("templates/index.html", "r", encoding="utf-8") as f: + return HTMLResponse(f.read()) + +@app.get("/embed") +async def index(): + with open("templates/embed.html", "r", encoding="utf-8") as f: + return HTMLResponse(f.read()) + +# ----------------------- +# PAGE 2: /graphs +# ----------------------- +@app.get("/graphs") +async def graphs(): + with open("templates/graphs.html", "r", encoding="utf-8") as f: + return HTMLResponse(f.read()) + + +# ----------------------- +# API 1 (used by /) +# ----------------------- +@app.get("/api/data") +async def api_data(): + query = text("SELECT * FROM STOCKMARKET_HISTORY WHERE Ticker = 'FAT' ORDER BY ChangeID DESC LIMIT 28") + + with engine.connect() as conn: + result = conn.execute(query) + rows = [dict(r._mapping) for r in result] + + return { + "columns": list(rows[0].keys()) if rows else [], + "rows": rows + } + + +# ----------------------- +# API 2 (used by /graphs) +# ----------------------- +from fastapi import Depends, Query + +@app.get("/api/graphs") +async def api_graphs( + ticker: str = Query(...), + limit: int = Query(28), +): + tickers = [t.strip().upper() for t in ticker.split(",") if t.strip()] + + with engine.connect() as conn: + results = {} + + for t in tickers: + query = text(""" + SELECT + h.*, + s.CompanyName + FROM STOCKMARKET_HISTORY h + JOIN STOCKMARKET_STOCKS s + ON s.Ticker = h.Ticker + WHERE h.Ticker = :ticker + ORDER BY h.ChangeID DESC + LIMIT :limit; + """) + + result = conn.execute(query, { + "ticker": t, + "limit": limit * 4 + }) + + rows = [dict(r._mapping) for r in result] + results[t] = rows + + return results + + +# ----------------------- +# RUN +# ----------------------- +if __name__ == "__main__": + import uvicorn + uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..506bcbe --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +fastapi +uvicorn +sqlalchemy +pymysql +python-jose[cryptography] +authlib +httpx +python-dotenv +itsdangerous +cryptography \ No newline at end of file diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..060296f --- /dev/null +++ b/static/style.css @@ -0,0 +1,41 @@ +html, body { + height: 100%; + margin: 0; + padding: 0; + background: #ffffff; + color: #ffffff; + font-family: Arial, sans-serif; + overflow: hidden; /* prevents page scroll messing with chart height */ +} + +/* Header area */ +h2 { + margin: 10px 15px 5px 15px; +} + +a { + color: #4da3ff; + margin: 0 15px 10px 15px; + text-decoration: none; + display: inline-block; +} + +a:hover { + text-decoration: underline; +} + +/* FULL SCREEN CHART CONTAINER */ +.chart-container { + width: 100%; + height: calc(100vh - 80px); /* subtract header space */ + display: flex; + padding: 10px 15px; + box-sizing: border-box; +} + +/* CRITICAL: canvas must stretch */ +#chart { + width: 100% !important; + height: 100% !important; + display: block; +} \ No newline at end of file diff --git a/templates/embed.html b/templates/embed.html new file mode 100644 index 0000000..de763f9 --- /dev/null +++ b/templates/embed.html @@ -0,0 +1,17 @@ + + + + Dashboard + + + + +

Main Dashboard

+ + + + + \ No newline at end of file diff --git a/templates/graphs.html b/templates/graphs.html new file mode 100644 index 0000000..0e52b1b --- /dev/null +++ b/templates/graphs.html @@ -0,0 +1,162 @@ + + + + Graphs + + + + + + +

Graphs

+Back + +
+ +
+ + + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..a97fe05 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,46 @@ + + + + Dashboard + + + + +

Main Dashboard

+ +Go to Graphs + +
+ + + + + \ No newline at end of file