Add backend support for script execution

This commit is contained in:
Sami Abuzakuk
2025-10-11 12:38:03 +02:00
parent 037d525905
commit 78b19a03a8
4 changed files with 89 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ from fastapi.exceptions import HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from model import Log, SessionLocal, Script
from run_scripts import run_scripts
import uvicorn
app = FastAPI()
@@ -28,15 +29,22 @@ class ScriptCreate(ScriptBase):
pass
class ScriptUpdate(ScriptBase):
enabled: bool
class ScriptResponse(ScriptBase):
id: int
created_at: datetime
enabled: bool
model_config = {"from_attributes": True}
class ScriptLogCreate(BaseModel):
message: str
error_code: int
error_message: str
@app.get("/")
@@ -80,19 +88,25 @@ def delete_script(script_id: int):
if not script:
raise HTTPException(status_code=404, detail="Script not found")
db.delete(script)
logs = db.query(Log).filter(Log.script_id == script_id).all()
for log in logs:
db.delete(log)
db.commit()
db.close()
return {"message": "Script deleted"}
@app.put("/script/{script_id}", response_model=ScriptResponse)
def update_script(script_id: int, script: ScriptCreate):
def update_script(script_id: int, script: ScriptUpdate):
db = SessionLocal()
existing_script = db.query(Script).filter(Script.id == script_id).first()
if not existing_script:
raise HTTPException(status_code=404, detail="Script not found")
existing_script.name = script.name
existing_script.script_content = script.script_content
existing_script.enabled = script.enabled
db.commit()
db.refresh(existing_script)
db.close()
@@ -110,7 +124,12 @@ def get_script_logs(script_id: int):
@app.post("/script/{script_id}/log")
def create_script_log(script_id: int, log: ScriptLogCreate):
db = SessionLocal()
new_log = Log(script_id=script_id, message=log.message)
new_log = Log(
script_id=script_id,
message=log.message,
error_code=log.error_code,
error_message=log.error_message,
)
db.add(new_log)
db.commit()
db.refresh(new_log)
@@ -130,6 +149,12 @@ def delete_script_log(script_id: int, log_id: int):
return {"message": "Log deleted"}
@app.post("/script/{script_id}/execute")
def execute_script(script_id: int):
run_scripts([script_id])
return {"run_script": True}
@app.get("/health")
def health_check():
return {"status": "healthy"}

View File

@@ -3,6 +3,7 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.functions import func
from sqlalchemy.sql.sqltypes import DateTime
from sqlalchemy.types import Boolean
# Initialize the database
DATABASE_URL = "sqlite:///./project_monitor.db"
@@ -22,6 +23,7 @@ class Script(Base):
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
script_content = Column(Text, nullable=True)
enabled = Column(Boolean, default=False)
created_at = Column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)
@@ -32,6 +34,8 @@ class Log(Base):
id = Column(Integer, primary_key=True, index=True)
message = Column(String, nullable=False)
error_code = Column(Integer, nullable=False, default=0)
error_message = Column(String, nullable=True)
created_at = Column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)

57
backend/run_scripts.py Normal file
View File

@@ -0,0 +1,57 @@
import model
import subprocess
import os
def run_scripts(script_ids: list[int] | None = None):
db = model.SessionLocal()
if script_ids:
scripts = db.query(model.Script).filter(model.Script.id.in_(script_ids)).all()
else:
scripts = db.query(model.Script).filter(model.Script.enabled).all()
for script in scripts:
print(f"Running script: {script.name}")
dump_script_to_file(script, f"exec_folder/{script.name}.py")
result = execute_script(f"exec_folder/{script.name}.py")
db.add(
model.Log(
script_id=script.id,
error_code=result.returncode,
message=result.stdout,
error_message=result.stderr,
)
)
db.commit()
delete_script(f"exec_folder/{script.name}.py")
db.close()
def dump_script_to_file(script, filename):
with open(filename, "w") as file:
file.write(script.script_content)
def execute_script(filename) -> subprocess.CompletedProcess:
result = subprocess.run(["python", filename], capture_output=True, text=True)
return result
def delete_script(filename):
try:
os.remove(filename)
except FileNotFoundError:
pass
def main():
run_scripts()
if __name__ == "__main__":
main()