diff --git a/mo/jobs/protocols.py b/mo/jobs/protocols.py
index f908fc81769c5edd6b9ba4d7146daaaf01c12572..2940757081b9bbb6e6933e00e46a252444ae5d5f 100644
--- a/mo/jobs/protocols.py
+++ b/mo/jobs/protocols.py
@@ -11,7 +11,8 @@ from sqlalchemy import delete
from sqlalchemy.orm import joinedload
from sqlalchemy.orm.query import Query
import subprocess
-from typing import List, Optional
+from typing import Dict, List, Optional, Tuple
+import PyPDF2
import mo
import mo.config as config
@@ -391,6 +392,18 @@ def schedule_sort_scans(job_id: int, for_user: db.User) -> int:
return the_job.job_id
+class SortScansPaper:
+ paper: db.Paper
+ pages: List[db.ScanPage]
+
+ def __init__(self, paper: db.Paper) -> None:
+ self.paper = paper
+ self.pages = []
+
+ def filename(self) -> str:
+ return f"out_{self.paper.task.task_id}_{self.paper.for_user_obj.user_id}.pdf"
+
+
@job_handler(db.JobType.sort_scans)
def handle_sort_scans(the_job: TheJob):
job = the_job.job
@@ -403,17 +416,106 @@ def handle_sort_scans(the_job: TheJob):
sess = db.get_session()
contest = sess.query(db.Contest).options(joinedload(db.Contest.round)).get(contest_id)
assert contest is not None
- round = contest.round
- round_code = round.round_code_short()
user_ids = set(u[0] for u in _get_user_id_query(contest, site_id).all())
+ users = sess.query(db.User).filter(db.User.user_id.in_(user_ids)).all()
+ users_by_id = {u.user_id: u for u in users}
tasks = sess.query(db.Task).filter(db.Task.task_id.in_(task_ids)).all()
- tasks_by_code = {t.code: t for t in tasks}
+ tasks_by_id = {t.task_id: t for t in tasks}
+
+ pages = sess.query(db.ScanPage).filter_by(job_id=the_job.job_id).all()
+
+ sols = sess.query(db.Solution).filter(
+ db.Solution.task_id.in_(task_ids),
+ db.Solution.user_id.in_(user_ids),
+ ).all()
# Jelikož se plánujeme zamyslet na dlouhou dobu, uzavřeme databázovou session.
sess.commit()
- # TODO: paralelně rozstříhat a sestavit správná PDFka
+ # Nejdříve si vše naplánujeme
+ sols_map = {(sol.task_id, sol.user_id): sol for sol in sols}
+ sols_to_create: Dict[Tuple[int, int], db.Solution] = {}
+ papers: Dict[Tuple[int, int], SortScansPaper] = {}
+
+ for p in pages:
+ if p.is_empty():
+ continue
+ task = tasks_by_id[p.task_id]
+ user = users_by_id[p.user_id]
+
+ index = (p.task_id, p.user_id)
+ if index in sols_map:
+ sol = sols_map[index]
+ elif index in sols_to_create:
+ sol = sols_to_create[index]
+ else:
+ sol = db.Solution(task=task, user=user)
+ sols_to_create[index] = sol
+
+ if index not in papers:
+ papers[index] = SortScansPaper(db.Paper(
+ task=task,
+ for_user_obj=user,
+ uploaded_by_obj=job.user,
+ type=db.PaperType.solution,
+ note='Z hromadného skenování',
+ ))
+
+ papers[index].pages.append(p)
+
+ for index in papers:
+ papers[index].pages.sort(key=lambda p: p.seq_id)
+
+ # Poté poskládáme výsledné PDF soubory
+ readers: Dict[int, PyPDF2.PdfFileReader] = {}
+ for index in papers:
+ paper = papers[index]
+ writer = PyPDF2.PdfFileWriter()
+ for p in paper.pages:
+ if p.file_nr not in readers:
+ readers[p.file_nr] = PyPDF2.PdfFileReader(job.file_path(in_files[p.file_nr]), strict=False)
+ # Přihodíme správnou stránku na výstup
+ writer.addPage(
+ readers[p.file_nr].getPage(p.page_nr)
+ )
+ # Zapíšeme vše do správného souboru
+ with open(job.file_path(paper.filename()), 'wb') as f:
+ writer.write(f)
+
+ # ... a uložíme je na správné místo
+ submitter = mo.submit.Submitter()
+
+ for index in papers:
+ paper = papers[index]
+ try:
+ print(paper.paper)
+ submitter.submit_paper(paper.paper, job.file_path(paper.filename()))
+ except mo.submit.SubmitException as e:
+ logger.error(f"Paper task:{paper.paper.for_task}, user:{paper.paper.for_user}: {e}")
+
+ # Nakonec vše uložíme do databáze
+ for index in sols_to_create:
+ sol = sols_to_create[index]
+ sess.add(sol)
+ mo.util.log(
+ type=db.LogType.participant,
+ what=sol.user.user_id,
+ details={
+ 'action': 'solution-created',
+ 'task': sol.task.task_id,
+ },
+ )
- # TODO: založit správná řešení
+ for index in papers:
+ paper = papers[index]
+ sess.add(paper.paper)
+ if index in sols:
+ sols[index].final_submit_obj = paper.paper
+ elif index in sols_to_create:
+ sols_to_create[index].final_submit_obj = paper.paper
+
+ sess.commit()
+ job.result = 'Celkem ' + mo.util_format.inflect_number(len(papers), 'roztříděné řešení', 'roztříděná řešení', 'roztříděných řešení')
+ the_job.expires_in_minutes = config.JOB_EXPIRATION_LONG