import hashlib from urllib.parse import urljoin from app.config import settings from app.services.paperless_client import PaperlessClient from app.services.repository import get_repository from app.services.store import JsonStore class PaperlessService: def __init__(self) -> None: self.store = JsonStore() self.repo = get_repository() self.client = PaperlessClient() def assignment_intake_payload(self, submission: dict) -> dict: return { "target_url": urljoin(settings.n8n_base_url, settings.n8n_assignment_webhook), "class_name": submission.get("class_name"), "assignment_name": submission.get("assignment_name"), "submission_kind": submission.get("submission_kind") or "assignment_turn_in", "semester": submission.get("semester"), "course_code": submission.get("course_code"), "paper_kind": submission.get("paper_kind"), "notes": submission.get("notes", ""), "source": submission.get("source") or "doris-schoolhouse", "telegram_chat_id": submission.get("telegram_chat_id"), "telegram_message_id": submission.get("telegram_message_id"), "local_file": submission.get("stored_path"), "version": submission.get("version_label"), } def recording_intake_payload(self, recording: dict) -> dict: return { "target_url": urljoin(settings.n8n_base_url, settings.n8n_recording_webhook), "class_name": recording.get("class_name"), "lecture_title": f"{recording.get('class_name')} {recording.get('session_date')}", "notes": recording.get("notes", ""), "local_file": recording.get("mp3_path") or recording.get("stored_path"), "source": "doris-schoolhouse", } def build_grade_note(self, assignment_id: str) -> str: submissions = self.repo.list_submissions() assignments = {item.get("id"): item for item in self.repo.list_assignments()} assignment = assignments.get(str(assignment_id), {}) linked = [s for s in submissions if str(s.get("assignment_id")) == str(assignment_id)] note_lines = [ "Grade sync from Doris Schoolhouse", f"Assignment: {assignment.get('title', 'unknown')}", ] if assignment.get("grade"): note_lines.append(f"Grade: {assignment['grade']}") if assignment.get("points"): note_lines.append(f"Points: {assignment['points']}") if assignment.get("comments"): note_lines.append(f"Professor comments: {assignment['comments']}") if linked: note_lines.append(f"Linked submissions: {len(linked)}") return "\n".join(note_lines) def describe_grade_note_plan(self, assignment_id: str) -> dict: submissions = self.repo.list_submissions() linked = [s for s in submissions if str(s.get("assignment_id")) == str(assignment_id)] return { "status": "stub", "backend": self.repo.backend, "assignment_id": assignment_id, "paperless_base_url": settings.paperless_base_url, "linked_submission_count": len(linked), "note_preview": self.build_grade_note(assignment_id), "message": "Resolve linked Paperless submission document, hash latest grade/comment payload, and append a dated Schoolhouse note if changed.", } def append_grade_note(self, assignment_id: str) -> dict: submissions = self.repo.list_submissions() linked = [s for s in submissions if str(s.get("assignment_id")) == str(assignment_id)] if not linked: raise ValueError("No linked submissions for assignment") target = next((s for s in linked if s.get("paperless_document_id")), linked[0]) document_id = target.get("paperless_document_id") if not document_id: raise ValueError("Linked submission has no Paperless document id yet") note = self.build_grade_note(assignment_id) note_hash = hashlib.sha256(note.encode('utf-8')).hexdigest() if target.get("paperless_note_last_hash") == note_hash: return { "status": "skipped", "reason": "note-unchanged", "assignment_id": assignment_id, "document_id": document_id, "note_hash": note_hash, } response = self.client.add_note(document_id, note) self.repo.update_submission( str(target.get("id")), { "paperless_note_last_hash": note_hash, "paperless_title": target.get("paperless_title"), "status": target.get("status", "paperless-linked"), }, ) return { "status": "ok", "assignment_id": assignment_id, "document_id": document_id, "note_hash": note_hash, "paperless_response": response, }