feat(reporting): Implement 'Report Mistake' feature with API and UI [2f388f42]
This commit is contained in:
@@ -17,7 +17,7 @@ setup_logging()
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from .database import init_db, get_db, Company, Signal, EnrichmentData, RoboticsCategory, Contact, Industry, JobRoleMapping
|
||||
from .database import init_db, get_db, Company, Signal, EnrichmentData, RoboticsCategory, Contact, Industry, JobRoleMapping, ReportedMistake
|
||||
from .services.deduplication import Deduplicator
|
||||
from .services.discovery import DiscoveryService
|
||||
from .services.scraping import ScraperService
|
||||
@@ -61,6 +61,14 @@ class AnalysisRequest(BaseModel):
|
||||
class IndustryUpdateModel(BaseModel):
|
||||
industry_ai: str
|
||||
|
||||
class ReportMistakeRequest(BaseModel):
|
||||
field_name: str
|
||||
wrong_value: Optional[str] = None
|
||||
corrected_value: Optional[str] = None
|
||||
source_url: Optional[str] = None
|
||||
quote: Optional[str] = None
|
||||
user_comment: Optional[str] = None
|
||||
|
||||
# --- Events ---
|
||||
@app.on_event("startup")
|
||||
def on_startup():
|
||||
@@ -240,6 +248,47 @@ def list_industries(db: Session = Depends(get_db)):
|
||||
def list_job_roles(db: Session = Depends(get_db)):
|
||||
return db.query(JobRoleMapping).order_by(JobRoleMapping.pattern.asc()).all()
|
||||
|
||||
@app.get("/api/mistakes")
|
||||
def list_reported_mistakes(
|
||||
status: Optional[str] = Query(None),
|
||||
skip: int = 0,
|
||||
limit: int = 50,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
query = db.query(ReportedMistake).options(joinedload(ReportedMistake.company))
|
||||
|
||||
if status:
|
||||
query = query.filter(ReportedMistake.status == status.upper())
|
||||
|
||||
total = query.count()
|
||||
items = query.order_by(ReportedMistake.created_at.desc()).offset(skip).limit(limit).all()
|
||||
|
||||
return {"total": total, "items": items}
|
||||
|
||||
class MistakeUpdateStatusRequest(BaseModel):
|
||||
status: str # PENDING, APPROVED, REJECTED
|
||||
|
||||
@app.put("/api/mistakes/{mistake_id}")
|
||||
def update_reported_mistake_status(
|
||||
mistake_id: int,
|
||||
request: MistakeUpdateStatusRequest,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
mistake = db.query(ReportedMistake).filter(ReportedMistake.id == mistake_id).first()
|
||||
if not mistake:
|
||||
raise HTTPException(404, detail="Reported mistake not found")
|
||||
|
||||
if request.status.upper() not in ["PENDING", "APPROVED", "REJECTED"]:
|
||||
raise HTTPException(400, detail="Invalid status. Must be PENDING, APPROVED, or REJECTED.")
|
||||
|
||||
mistake.status = request.status.upper()
|
||||
mistake.updated_at = datetime.utcnow()
|
||||
db.commit()
|
||||
db.refresh(mistake)
|
||||
|
||||
logger.info(f"Updated status for mistake {mistake_id} to {mistake.status}")
|
||||
return {"status": "success", "mistake": mistake}
|
||||
|
||||
@app.post("/api/enrich/discover")
|
||||
def discover_company(req: AnalysisRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
|
||||
company = db.query(Company).filter(Company.id == req.company_id).first()
|
||||
@@ -317,35 +366,115 @@ def override_website(company_id: int, url: str, db: Session = Depends(get_db)):
|
||||
return {"status": "updated", "website": company.website}
|
||||
|
||||
@app.post("/api/companies/{company_id}/override/impressum")
|
||||
|
||||
def override_impressum(company_id: int, url: str, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
|
||||
|
||||
company = db.query(Company).filter(Company.id == company_id).first()
|
||||
|
||||
if not company:
|
||||
|
||||
raise HTTPException(404, detail="Company not found")
|
||||
|
||||
|
||||
|
||||
# Create or update manual impressum lock
|
||||
|
||||
existing = db.query(EnrichmentData).filter(
|
||||
|
||||
EnrichmentData.company_id == company_id,
|
||||
|
||||
EnrichmentData.source_type == "impressum_override"
|
||||
|
||||
).first()
|
||||
|
||||
|
||||
|
||||
if not existing:
|
||||
|
||||
db.add(EnrichmentData(
|
||||
|
||||
company_id=company_id,
|
||||
|
||||
source_type="impressum_override",
|
||||
|
||||
content={"url": url},
|
||||
|
||||
is_locked=True
|
||||
|
||||
))
|
||||
|
||||
else:
|
||||
|
||||
existing.content = {"url": url}
|
||||
|
||||
existing.is_locked = True
|
||||
|
||||
|
||||
|
||||
db.commit()
|
||||
|
||||
return {"status": "updated"}
|
||||
|
||||
|
||||
|
||||
@app.post("/api/companies/{company_id}/report-mistake")
|
||||
|
||||
def report_company_mistake(
|
||||
|
||||
company_id: int,
|
||||
|
||||
request: ReportMistakeRequest,
|
||||
|
||||
db: Session = Depends(get_db)
|
||||
|
||||
):
|
||||
|
||||
company = db.query(Company).filter(Company.id == company_id).first()
|
||||
|
||||
if not company:
|
||||
|
||||
raise HTTPException(404, detail="Company not found")
|
||||
|
||||
|
||||
|
||||
new_mistake = ReportedMistake(
|
||||
|
||||
company_id=company_id,
|
||||
|
||||
field_name=request.field_name,
|
||||
|
||||
wrong_value=request.wrong_value,
|
||||
|
||||
corrected_value=request.corrected_value,
|
||||
|
||||
source_url=request.source_url,
|
||||
|
||||
quote=request.quote,
|
||||
|
||||
user_comment=request.user_comment
|
||||
|
||||
)
|
||||
|
||||
db.add(new_mistake)
|
||||
|
||||
db.commit()
|
||||
|
||||
db.refresh(new_mistake)
|
||||
|
||||
|
||||
|
||||
logger.info(f"Reported mistake for company {company_id}: {request.field_name} -> {request.corrected_value}")
|
||||
|
||||
return {"status": "success", "mistake_id": new_mistake.id}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def run_wikipedia_reevaluation_task(company_id: int):
|
||||
|
||||
from .database import SessionLocal
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
company = db.query(Company).filter(Company.id == company_id).first()
|
||||
|
||||
Reference in New Issue
Block a user