Commit dbe0dcba authored by Mahmoud Aglan's avatar Mahmoud Aglan

gitlab try 1

parent 10eb3289
This diff is collapsed.
......@@ -20,9 +20,11 @@ from backend.routes.admin_routes import router as admin_router
from backend.routes.knowledge_routes import router as knowledge_router
from backend.routes.files_routes import router as files_router
from backend.routes.attachment_routes import router as attachment_router
from backend.routes.gitlab_routes import router as gitlab_router
from backend.services.bedrock_service import close_http_client
from backend.services.gitlab_service import close_gitlab_client
APP_VERSION = "2.1.0"
APP_VERSION = "3.0.0"
APP_BUILD_TIME = str(int(time.time()))
......@@ -49,6 +51,18 @@ def _run_migrations():
ChatAttachment.__table__.create(bind=engine, checkfirst=True)
print(" Created chat_attachments table")
# GitLab tables
for table_name in ("gitlab_configs", "gitlab_operations", "gitlab_audit_log"):
if table_name not in existing_tables:
from backend.models import GitLabConfig, GitLabOperation, GitLabAuditLog
table_map = {
"gitlab_configs": GitLabConfig,
"gitlab_operations": GitLabOperation,
"gitlab_audit_log": GitLabAuditLog,
}
table_map[table_name].__table__.create(bind=engine, checkfirst=True)
print(f" Created {table_name} table")
except Exception as e:
print(f" Migration note: {e}")
......@@ -61,6 +75,7 @@ async def lifespan(app: FastAPI):
print(f"Son of Anton v{APP_VERSION} (build {APP_BUILD_TIME}) is online.")
yield
await close_http_client()
await close_gitlab_client()
print("Son of Anton shutting down.")
......@@ -84,28 +99,21 @@ app.add_middleware(
async def add_cache_headers(request: Request, call_next):
response: Response = await call_next(request)
path = request.url.path
# API responses: never cache
if path.startswith("/api"):
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
# Hashed assets (contain hash in filename): cache aggressively
elif path.startswith("/assets/") and any(c in path for c in [".js", ".css"]):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
# HTML and everything else: never cache
elif path.endswith(".html") or not path.startswith("/assets"):
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
# Always add version header for debugging
response.headers["X-App-Version"] = APP_VERSION
response.headers["X-Build-Time"] = APP_BUILD_TIME
return response
# Version endpoint for frontend to check
@app.get("/api/version")
def get_version():
return {"version": APP_VERSION, "build": APP_BUILD_TIME}
......@@ -117,6 +125,7 @@ app.include_router(admin_router, prefix="/api/admin", tags=["Admin"])
app.include_router(knowledge_router, prefix="/api/knowledge", tags=["Knowledge"])
app.include_router(files_router, prefix="/api/files", tags=["Files"])
app.include_router(attachment_router, prefix="/api", tags=["Attachments"])
app.include_router(gitlab_router, prefix="/api/gitlab", tags=["GitLab"])
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
......@@ -135,7 +144,6 @@ async def serve_frontend(full_path: str):
file_path = FRONTEND_DIR / full_path
if full_path and file_path.is_file():
resp = FileResponse(str(file_path))
# Don't cache non-hashed static files
resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
return resp
index = FRONTEND_DIR / "index.html"
......
......@@ -124,3 +124,49 @@ class KnowledgeDocument(Base):
file_size = Column(Integer, default=0)
chunk_count = Column(Integer, default=0)
created_at = Column(DateTime, default=datetime.utcnow)
# ══════════════════════════════════════════════════════
# GitLab CE Integration Models
# ══════════════════════════════════════════════════════
class GitLabConfig(Base):
__tablename__ = "gitlab_configs"
id = Column(String(36), primary_key=True, default=new_id)
gitlab_url = Column(String(500), nullable=False)
access_token_enc = Column(String(500), nullable=False)
default_namespace = Column(String(200), nullable=True)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class GitLabOperation(Base):
__tablename__ = "gitlab_operations"
id = Column(String(36), primary_key=True, default=new_id)
operation_type = Column(String(50), nullable=False)
status = Column(String(20), default="pending")
project_id = Column(Integer, nullable=True)
project_name = Column(String(200), nullable=True)
branch = Column(String(200), nullable=True)
payload = Column(Text, nullable=False)
result = Column(Text, nullable=True)
chat_id = Column(String(36), nullable=True)
message_id = Column(String(36), nullable=True)
created_by = Column(String(36), ForeignKey("users.id"), nullable=False)
approved_by = Column(String(36), nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
executed_at = Column(DateTime, nullable=True)
class GitLabAuditLog(Base):
__tablename__ = "gitlab_audit_log"
id = Column(String(36), primary_key=True, default=new_id)
operation_id = Column(String(36), nullable=True)
action = Column(String(100), nullable=False)
details = Column(Text, nullable=True)
user_id = Column(String(36), nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -7,26 +7,20 @@ import LoginPage from "./pages/LoginPage";
import ChatPage from "./pages/ChatPage";
import AdminPage from "./pages/AdminPage";
import KnowledgePage from "./pages/KnowledgePage";
import GitLabPage from "./pages/GitLabPage";
import { Flame } from "lucide-react";
export default function App() {
const { state, dispatch } = useApp();
const [authChecked, setAuthChecked] = useState(!state.token);
// Connect streamManager to store dispatch
useEffect(() => {
streamManager.setDispatch(dispatch);
}, [dispatch]);
useEffect(() => {
if (!state.token) {
setAuthChecked(true);
return;
}
if (state.user) {
setAuthChecked(true);
return;
}
if (!state.token) { setAuthChecked(true); return; }
if (state.user) { setAuthChecked(true); return; }
(async () => {
try {
const user = await getMe(state.token);
......@@ -52,14 +46,13 @@ export default function App() {
);
}
if (!state.token) {
return <LoginPage />;
}
if (!state.token) return <LoginPage />;
return (
<Routes>
<Route path="/admin" element={<AdminPage />} />
<Route path="/knowledge" element={<KnowledgePage />} />
<Route path="/gitlab" element={<GitLabPage />} />
<Route path="/*" element={<ChatPage />} />
</Routes>
);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment