bmc_hub/app/devportal/backend/router.py

293 lines
9.3 KiB
Python
Raw Permalink Normal View History

from fastapi import APIRouter, HTTPException
from app.core.database import execute_query
from typing import List, Optional, Dict, Any
from pydantic import BaseModel
from datetime import date, datetime
import logging
logger = logging.getLogger(__name__)
router = APIRouter()
# Pydantic Models
class Feature(BaseModel):
id: Optional[int] = None
title: str
description: Optional[str] = None
version: Optional[str] = None
status: str = 'planlagt'
priority: int = 50
expected_date: Optional[date] = None
completed_date: Optional[date] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class FeatureCreate(BaseModel):
title: str
description: Optional[str] = None
version: Optional[str] = None
status: str = 'planlagt'
priority: int = 50
expected_date: Optional[date] = None
class Idea(BaseModel):
id: Optional[int] = None
title: str
description: Optional[str] = None
category: Optional[str] = None
votes: int = 0
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class IdeaCreate(BaseModel):
title: str
description: Optional[str] = None
category: Optional[str] = None
class Workflow(BaseModel):
id: Optional[int] = None
title: str
description: Optional[str] = None
category: Optional[str] = None
diagram_xml: str
thumbnail_url: Optional[str] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class WorkflowCreate(BaseModel):
title: str
description: Optional[str] = None
category: Optional[str] = None
diagram_xml: str
# Features/Roadmap Endpoints
@router.get("/features", response_model=List[Feature])
async def get_features(version: Optional[str] = None, status: Optional[str] = None):
"""Get all roadmap features with optional filters"""
query = "SELECT * FROM dev_features WHERE 1=1"
params = []
if version:
query += " AND version = %s"
params.append(version)
if status:
query += " AND status = %s"
params.append(status)
query += " ORDER BY priority DESC, expected_date ASC"
result = execute_query(query, tuple(params) if params else None)
return result or []
@router.get("/features/{feature_id}", response_model=Feature)
async def get_feature(feature_id: int):
"""Get a specific feature"""
result = execute_query("SELECT * FROM dev_features WHERE id = %s", (feature_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Feature not found")
return result
@router.post("/features", response_model=Feature)
async def create_feature(feature: FeatureCreate):
"""Create a new roadmap feature"""
query = """
INSERT INTO dev_features (title, description, version, status, priority, expected_date)
VALUES (%s, %s, %s, %s, %s, %s)
RETURNING *
"""
result = execute_query(query, (
feature.title, feature.description, feature.version,
feature.status, feature.priority, feature.expected_date
), fetchone=True)
logger.info(f"✅ Created feature: {feature.title}")
return result
@router.put("/features/{feature_id}", response_model=Feature)
async def update_feature(feature_id: int, feature: FeatureCreate):
"""Update a roadmap feature"""
query = """
UPDATE dev_features
SET title = %s, description = %s, version = %s, status = %s,
priority = %s, expected_date = %s
WHERE id = %s
RETURNING *
"""
result = execute_query(query, (
feature.title, feature.description, feature.version,
feature.status, feature.priority, feature.expected_date, feature_id
), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Feature not found")
logger.info(f"✅ Updated feature: {feature_id}")
return result
@router.delete("/features/{feature_id}")
async def delete_feature(feature_id: int):
"""Delete a roadmap feature"""
result = execute_query("DELETE FROM dev_features WHERE id = %s RETURNING id", (feature_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Feature not found")
logger.info(f"✅ Deleted feature: {feature_id}")
return {"message": "Feature deleted successfully"}
# Ideas Endpoints
@router.get("/ideas", response_model=List[Idea])
async def get_ideas(category: Optional[str] = None):
"""Get all ideas with optional category filter"""
query = "SELECT * FROM dev_ideas WHERE 1=1"
params = []
if category:
query += " AND category = %s"
params.append(category)
query += " ORDER BY votes DESC, created_at DESC"
result = execute_query(query, tuple(params) if params else None)
return result or []
@router.post("/ideas", response_model=Idea)
async def create_idea(idea: IdeaCreate):
"""Create a new idea"""
query = """
INSERT INTO dev_ideas (title, description, category)
VALUES (%s, %s, %s)
RETURNING *
"""
result = execute_query(query, (idea.title, idea.description, idea.category), fetchone=True)
logger.info(f"✅ Created idea: {idea.title}")
return result
@router.post("/ideas/{idea_id}/vote")
async def vote_idea(idea_id: int):
"""Increment vote count for an idea"""
query = """
UPDATE dev_ideas
SET votes = votes + 1
WHERE id = %s
RETURNING *
"""
result = execute_query(query, (idea_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Idea not found")
return result
@router.delete("/ideas/{idea_id}")
async def delete_idea(idea_id: int):
"""Delete an idea"""
result = execute_query("DELETE FROM dev_ideas WHERE id = %s RETURNING id", (idea_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Idea not found")
logger.info(f"✅ Deleted idea: {idea_id}")
return {"message": "Idea deleted successfully"}
# Workflows Endpoints
@router.get("/workflows", response_model=List[Workflow])
async def get_workflows(category: Optional[str] = None):
"""Get all workflows with optional category filter"""
query = "SELECT * FROM dev_workflows WHERE 1=1"
params = []
if category:
query += " AND category = %s"
params.append(category)
query += " ORDER BY created_at DESC"
result = execute_query(query, tuple(params) if params else None)
return result or []
@router.get("/workflows/{workflow_id}", response_model=Workflow)
async def get_workflow(workflow_id: int):
"""Get a specific workflow"""
result = execute_query("SELECT * FROM dev_workflows WHERE id = %s", (workflow_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Workflow not found")
return result
@router.post("/workflows", response_model=Workflow)
async def create_workflow(workflow: WorkflowCreate):
"""Create a new workflow diagram"""
query = """
INSERT INTO dev_workflows (title, description, category, diagram_xml)
VALUES (%s, %s, %s, %s)
RETURNING *
"""
result = execute_query(query, (
workflow.title, workflow.description, workflow.category, workflow.diagram_xml
), fetchone=True)
logger.info(f"✅ Created workflow: {workflow.title}")
return result
@router.put("/workflows/{workflow_id}", response_model=Workflow)
async def update_workflow(workflow_id: int, workflow: WorkflowCreate):
"""Update a workflow diagram"""
query = """
UPDATE dev_workflows
SET title = %s, description = %s, category = %s, diagram_xml = %s
WHERE id = %s
RETURNING *
"""
result = execute_query(query, (
workflow.title, workflow.description, workflow.category,
workflow.diagram_xml, workflow_id
), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Workflow not found")
logger.info(f"✅ Updated workflow: {workflow_id}")
return result
@router.delete("/workflows/{workflow_id}")
async def delete_workflow(workflow_id: int):
"""Delete a workflow"""
result = execute_query("DELETE FROM dev_workflows WHERE id = %s RETURNING id", (workflow_id,), fetchone=True)
if not result:
raise HTTPException(status_code=404, detail="Workflow not found")
logger.info(f"✅ Deleted workflow: {workflow_id}")
return {"message": "Workflow deleted successfully"}
# Stats endpoint
@router.get("/stats")
async def get_devportal_stats():
"""Get DEV Portal statistics"""
features_count = execute_query("SELECT COUNT(*) as count FROM dev_features", fetchone=True)
ideas_count = execute_query("SELECT COUNT(*) as count FROM dev_ideas", fetchone=True)
workflows_count = execute_query("SELECT COUNT(*) as count FROM dev_workflows", fetchone=True)
features_by_status = execute_query("""
SELECT status, COUNT(*) as count
FROM dev_features
GROUP BY status
""")
return {
"features_count": features_count['count'] if features_count else 0,
"ideas_count": ideas_count['count'] if ideas_count else 0,
"workflows_count": workflows_count['count'] if workflows_count else 0,
"features_by_status": features_by_status or []
}