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>
183 lines
6.1 KiB
Python
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,
|
|
}
|