Files
breakpilot-lehrer/backend-lehrer/classroom_engine/repository_feedback.py
Benjamin Admin b2a0126f14 [split-required] Split remaining Python monoliths (Phase 1 continued)
klausur-service (7 monoliths):
- grid_editor_helpers.py (1,737 → 5 files: columns, filters, headers, zones)
- cv_cell_grid.py (1,675 → 7 files: build, legacy, streaming, merge, vocab)
- worksheet_editor_api.py (1,305 → 4 files: models, AI, reconstruct, routes)
- legal_corpus_ingestion.py (1,280 → 3 files: registry, chunking, ingestion)
- cv_review.py (1,248 → 4 files: pipeline, spell, LLM, barrel)
- cv_preprocessing.py (1,166 → 3 files: deskew, dewarp, barrel)
- rbac.py, admin_api.py, routes/eh.py remain (next batch)

backend-lehrer (1 monolith):
- classroom_engine/repository.py (1,705 → 7 files by domain)

All re-export barrels preserve backward compatibility.
Zero import errors verified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 22:47:59 +02:00

183 lines
6.1 KiB
Python

"""
Teacher Feedback Repository.
CRUD-Operationen fuer Lehrer-Feedback (Phase 7).
Ermoeglicht Lehrern, Bugs, Feature-Requests und Verbesserungen zu melden.
"""
from datetime import datetime
from typing import Optional, List, Dict, Any
from sqlalchemy.orm import Session as DBSession
from .db_models import (
TeacherFeedbackDB, FeedbackTypeEnum, FeedbackStatusEnum,
FeedbackPriorityEnum,
)
class TeacherFeedbackRepository:
"""
Repository fuer Lehrer-Feedback CRUD-Operationen.
Ermoeglicht Lehrern, Feedback (Bugs, Feature-Requests, Verbesserungen)
direkt aus dem Lehrer-Frontend zu senden.
"""
def __init__(self, db: DBSession):
self.db = db
def create(
self,
teacher_id: str,
title: str,
description: str,
feedback_type: str = "improvement",
priority: str = "medium",
teacher_name: str = "",
teacher_email: str = "",
context_url: str = "",
context_phase: str = "",
context_session_id: str = None,
user_agent: str = "",
related_feature: str = None,
) -> TeacherFeedbackDB:
"""Erstellt neues Feedback."""
import uuid
db_feedback = TeacherFeedbackDB(
id=str(uuid.uuid4()),
teacher_id=teacher_id,
teacher_name=teacher_name,
teacher_email=teacher_email,
title=title,
description=description,
feedback_type=FeedbackTypeEnum(feedback_type),
priority=FeedbackPriorityEnum(priority),
status=FeedbackStatusEnum.NEW,
related_feature=related_feature,
context_url=context_url,
context_phase=context_phase,
context_session_id=context_session_id,
user_agent=user_agent,
)
self.db.add(db_feedback)
self.db.commit()
self.db.refresh(db_feedback)
return db_feedback
def get_by_id(self, feedback_id: str) -> Optional[TeacherFeedbackDB]:
"""Holt Feedback nach ID."""
return self.db.query(TeacherFeedbackDB).filter(
TeacherFeedbackDB.id == feedback_id
).first()
def get_all(
self,
status: str = None,
feedback_type: str = None,
limit: int = 100,
offset: int = 0
) -> List[TeacherFeedbackDB]:
"""Holt alle Feedbacks mit optionalen Filtern."""
query = self.db.query(TeacherFeedbackDB)
if status:
query = query.filter(TeacherFeedbackDB.status == FeedbackStatusEnum(status))
if feedback_type:
query = query.filter(TeacherFeedbackDB.feedback_type == FeedbackTypeEnum(feedback_type))
return query.order_by(
TeacherFeedbackDB.created_at.desc()
).offset(offset).limit(limit).all()
def get_by_teacher(self, teacher_id: str, limit: int = 50) -> List[TeacherFeedbackDB]:
"""Holt Feedback eines bestimmten Lehrers."""
return self.db.query(TeacherFeedbackDB).filter(
TeacherFeedbackDB.teacher_id == teacher_id
).order_by(
TeacherFeedbackDB.created_at.desc()
).limit(limit).all()
def update_status(
self,
feedback_id: str,
status: str,
response: str = None,
responded_by: str = None
) -> Optional[TeacherFeedbackDB]:
"""Aktualisiert den Status eines Feedbacks."""
db_feedback = self.get_by_id(feedback_id)
if not db_feedback:
return None
db_feedback.status = FeedbackStatusEnum(status)
if response:
db_feedback.response = response
db_feedback.responded_at = datetime.utcnow()
db_feedback.responded_by = responded_by
self.db.commit()
self.db.refresh(db_feedback)
return db_feedback
def delete(self, feedback_id: str) -> bool:
"""Loescht ein Feedback."""
db_feedback = self.get_by_id(feedback_id)
if not db_feedback:
return False
self.db.delete(db_feedback)
self.db.commit()
return True
def get_stats(self) -> Dict[str, Any]:
"""Gibt Statistiken ueber alle Feedbacks zurueck."""
all_feedback = self.db.query(TeacherFeedbackDB).all()
stats = {
"total": len(all_feedback),
"by_status": {},
"by_type": {},
"by_priority": {},
}
for fb in all_feedback:
# By Status
status = fb.status.value
stats["by_status"][status] = stats["by_status"].get(status, 0) + 1
# By Type
fb_type = fb.feedback_type.value
stats["by_type"][fb_type] = stats["by_type"].get(fb_type, 0) + 1
# By Priority
priority = fb.priority.value
stats["by_priority"][priority] = stats["by_priority"].get(priority, 0) + 1
return stats
def to_dict(self, db_feedback: TeacherFeedbackDB) -> Dict[str, Any]:
"""Konvertiert DB-Model zu Dictionary."""
return {
"id": db_feedback.id,
"teacher_id": db_feedback.teacher_id,
"teacher_name": db_feedback.teacher_name,
"teacher_email": db_feedback.teacher_email,
"title": db_feedback.title,
"description": db_feedback.description,
"feedback_type": db_feedback.feedback_type.value,
"priority": db_feedback.priority.value,
"status": db_feedback.status.value,
"related_feature": db_feedback.related_feature,
"context_url": db_feedback.context_url,
"context_phase": db_feedback.context_phase,
"context_session_id": db_feedback.context_session_id,
"user_agent": db_feedback.user_agent,
"response": db_feedback.response,
"responded_at": db_feedback.responded_at.isoformat() if db_feedback.responded_at else None,
"responded_by": db_feedback.responded_by,
"created_at": db_feedback.created_at.isoformat() if db_feedback.created_at else None,
"updated_at": db_feedback.updated_at.isoformat() if db_feedback.updated_at else None,
}