[2f888f42] Container neu bauen und testne

Container neu bauen und testne
This commit is contained in:
2026-01-30 11:55:37 +00:00
parent 3c3632b9fa
commit 30b3042e85
8 changed files with 90 additions and 36 deletions

View File

@@ -1 +1 @@
{"task_id": "2ea88f42-8544-806f-8946-e61ada8cc059", "token": "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", "session_start_time": "2026-01-29T10:55:09.010737"}
{"task_id": "2f888f42-8544-81fc-a92d-f5670a995110", "token": "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", "session_start_time": "2026-01-30T11:54:46.937258"}

View File

@@ -8,6 +8,21 @@ from pydantic import BaseModel
from datetime import datetime
import os
import sys
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets
security = HTTPBasic()
async def authenticate_user(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, os.getenv("API_USER", "default_user"))
correct_password = secrets.compare_digest(credentials.password, os.getenv("API_PASSWORD", "default_password"))
if not (correct_username and correct_password):
raise HTTPException(
status_code=401,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
from .config import settings
from .lib.logging_setup import setup_logging
@@ -82,18 +97,18 @@ def on_startup():
# --- Routes ---
@app.get("/api/health")
def health_check():
def health_check(username: str = Depends(authenticate_user)):
return {"status": "ok", "version": settings.VERSION, "db": settings.DATABASE_URL}
@app.get("/api/companies")
def list_companies(
skip: int = 0,
limit: int = 50,
skip: int = 0,
limit: int = 50,
search: Optional[str] = None,
sort_by: Optional[str] = Query("name_asc"),
db: Session = Depends(get_db)
):
try:
db: Session = Depends(get_db),
username: str = Depends(authenticate_user)
): try:
query = db.query(Company)
if search:
query = query.filter(Company.name.ilike(f"%{search}%"))
@@ -129,7 +144,7 @@ def list_companies(
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/companies/export")
def export_companies_csv(db: Session = Depends(get_db)):
def export_companies_csv(db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
"""
Exports a CSV of all companies with their key metrics.
"""
@@ -171,7 +186,7 @@ def export_companies_csv(db: Session = Depends(get_db)):
)
@app.get("/api/companies/{company_id}")
def get_company(company_id: int, db: Session = Depends(get_db)):
def get_company(company_id: int, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).options(
joinedload(Company.enrichment_data),
joinedload(Company.contacts)
@@ -181,7 +196,7 @@ def get_company(company_id: int, db: Session = Depends(get_db)):
return company
@app.post("/api/companies")
def create_company(company: CompanyCreate, db: Session = Depends(get_db)):
def create_company(company: CompanyCreate, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
db_company = db.query(Company).filter(Company.name == company.name).first()
if db_company:
raise HTTPException(status_code=400, detail="Company already registered")
@@ -199,7 +214,7 @@ def create_company(company: CompanyCreate, db: Session = Depends(get_db)):
return new_company
@app.post("/api/companies/bulk")
def bulk_import_companies(req: BulkImportRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
def bulk_import_companies(req: BulkImportRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
imported_count = 0
for name in req.names:
name = name.strip()
@@ -217,7 +232,7 @@ def bulk_import_companies(req: BulkImportRequest, background_tasks: BackgroundTa
return {"status": "success", "imported": imported_count}
@app.post("/api/companies/{company_id}/override/wikipedia")
def override_wikipedia(company_id: int, url: str, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
def override_wikipedia(company_id: int, url: str, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == company_id).first()
if not company:
raise HTTPException(404, detail="Company not found")
@@ -253,15 +268,15 @@ def override_wikipedia(company_id: int, url: str, background_tasks: BackgroundTa
return {"status": "updated"}
@app.get("/api/robotics/categories")
def list_robotics_categories(db: Session = Depends(get_db)):
def list_robotics_categories(db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
return db.query(RoboticsCategory).all()
@app.get("/api/industries")
def list_industries(db: Session = Depends(get_db)):
def list_industries(db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
return db.query(Industry).all()
@app.get("/api/job_roles")
def list_job_roles(db: Session = Depends(get_db)):
def list_job_roles(db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
return db.query(JobRoleMapping).order_by(JobRoleMapping.pattern.asc()).all()
@app.get("/api/mistakes")
@@ -270,7 +285,8 @@ def list_reported_mistakes(
company_id: Optional[int] = Query(None),
skip: int = 0,
limit: int = 50,
db: Session = Depends(get_db)
db: Session = Depends(get_db),
username: str = Depends(authenticate_user)
):
query = db.query(ReportedMistake).options(joinedload(ReportedMistake.company))
@@ -290,11 +306,11 @@ class MistakeUpdateStatusRequest(BaseModel):
@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()
mistake_id: int,
request: MistakeUpdateStatusRequest,
db: Session = Depends(get_db),
username: str = Depends(authenticate_user)
): mistake = db.query(ReportedMistake).filter(ReportedMistake.id == mistake_id).first()
if not mistake:
raise HTTPException(404, detail="Reported mistake not found")
@@ -310,14 +326,14 @@ def update_reported_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)):
def discover_company(req: AnalysisRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == req.company_id).first()
if not company: raise HTTPException(404, "Company not found")
background_tasks.add_task(run_discovery_task, company.id)
return {"status": "queued"}
@app.post("/api/enrich/analyze")
def analyze_company(req: AnalysisRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
def analyze_company(req: AnalysisRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == req.company_id).first()
if not company: raise HTTPException(404, "Company not found")
@@ -329,12 +345,12 @@ def analyze_company(req: AnalysisRequest, background_tasks: BackgroundTasks, db:
@app.put("/api/companies/{company_id}/industry")
def update_company_industry(
company_id: int,
data: IndustryUpdateModel,
company_id: int,
data: IndustryUpdateModel,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db)
):
company = db.query(Company).filter(Company.id == company_id).first()
db: Session = Depends(get_db),
username: str = Depends(authenticate_user)
): company = db.query(Company).filter(Company.id == company_id).first()
if not company:
raise HTTPException(404, detail="Company not found")
@@ -350,7 +366,7 @@ def update_company_industry(
@app.post("/api/companies/{company_id}/reevaluate-wikipedia")
def reevaluate_wikipedia(company_id: int, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
def reevaluate_wikipedia(company_id: int, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == company_id).first()
if not company:
raise HTTPException(404, detail="Company not found")
@@ -360,7 +376,7 @@ def reevaluate_wikipedia(company_id: int, background_tasks: BackgroundTasks, db:
@app.delete("/api/companies/{company_id}")
def delete_company(company_id: int, db: Session = Depends(get_db)):
def delete_company(company_id: int, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == company_id).first()
if not company:
raise HTTPException(404, detail="Company not found")
@@ -375,7 +391,7 @@ def delete_company(company_id: int, db: Session = Depends(get_db)):
return {"status": "deleted"}
@app.post("/api/companies/{company_id}/override/website")
def override_website(company_id: int, url: str, db: Session = Depends(get_db)):
def override_website(company_id: int, url: str, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == company_id).first()
if not company:
raise HTTPException(404, detail="Company not found")
@@ -387,7 +403,7 @@ def override_website(company_id: int, url: str, db: Session = Depends(get_db)):
@app.post("/api/companies/{company_id}/override/impressum")
def override_impressum(company_id: int, url: str, background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
def override_impressum(company_id: int, url: str, background_tasks: BackgroundTasks, db: Session = Depends(get_db), username: str = Depends(authenticate_user)):
company = db.query(Company).filter(Company.id == company_id).first()
@@ -441,14 +457,15 @@ def override_impressum(company_id: int, url: str, background_tasks: BackgroundTa
def report_company_mistake(
company_id: int,
company_id: int,
request: ReportMistakeRequest,
request: ReportMistakeRequest,
db: Session = Depends(get_db)
db: Session = Depends(get_db),
username: str = Depends(authenticate_user)
):
company = db.query(Company).filter(Company.id == company_id).first()
if not company:

View File

@@ -13,5 +13,20 @@ services:
volumes:
- moltbot_data:/home/node/.clawd
company-explorer:
build:
context: ./company-explorer
container_name: company-explorer
restart: unless-stopped
ports:
- "8000:8000"
environment:
API_USER: "your_api_user" # Placeholder
API_PASSWORD: "your_api_password" # Placeholder
volumes:
- ./company-explorer/backend:/app/backend # Sideloading backend changes
- ./company-explorer/frontend_static:/frontend_static # Sideloading frontend changes if any
- ./companies_v3_fixed_2.db:/app/companies_v3_fixed_2.db # Database persistence, as per MIGRATION_PLAN.md
volumes:
moltbot_data: {}

View File

@@ -837,6 +837,28 @@ Dank des Volume-Mountings für die Python-Skripte ist die Entwicklung sehr effiz
Ein zeitaufwändiger `docker-compose build` ist nur bei Änderungen am Frontend-Code, an den `Dockerfile`n oder an den `requirements.txt`/`package.json`-Dateien notwendig.
### API-Authentifizierung (Company Explorer)
Der `company-explorer` Dienst erfordert nun eine HTTP Basic Authentication für alle API-Endpunkte (`/api/*`). Dies dient dem internen Zugriffsschutz.
Um den Dienst zu nutzen, müssen folgende Umgebungsvariablen in der `docker-compose.yml` (oder in einer `.env`-Datei, wenn diese konfiguriert ist) gesetzt werden:
```yaml
services:
company-explorer:
# ... andere Konfigurationen ...
environment:
API_USER: "IhrBenutzername" # Legen Sie hier Ihren gewünschten Benutzernamen fest
API_PASSWORD: "IhrSicheresPasswort" # Legen Sie hier Ihr gewünschtes sicheres Passwort fest
```
Stellen Sie sicher, dass Sie diese Werte vor dem Start des `company-explorer` Dienstes festlegen. Nach dem Aktualisieren der `docker-compose.yml` müssen Sie den Dienst neu starten:
```bash
docker-compose restart company-explorer
```
---
## 11. Market Intelligence: Funktionsweise v2.2 (Update Dez. 2025)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.