Skip to content
Snippets Groups Projects

Sazba výsledkovek TeXem

Merged
Martin Marešrequested to merge
mj/vysledky-pdf into devel
All threads resolved!
2 files
+ 283
13
Compare changes
  • Side-by-side
  • Inline

Files

+ 101
13
@@ -4,19 +4,21 @@ import decimal
import json
import os
import subprocess
import re
import requests
from typing import Any, Dict, Iterable, Optional
from typing import Any, Dict, Iterable, Optional, List
import mo
import mo.config as config
import mo.db as db
from mo.jobs import TheJob, job_handler
from mo.score import Score
from mo.score import Score, ScoreResult
from mo.util import tex_arg, assert_not_none
from mo.util_format import format_decimal
#
# Job snapshot_score: Vytvoří kopii aktuální výsledkovky (TODO: a pdf k ní)
# Job snapshot_score: Vytvoří kopii aktuální výsledkovky
#
# Vstupní JSON:
# { 'contest_id': int,
@@ -45,17 +47,95 @@ class OrderKeyEncoder(json.JSONEncoder):
return super().encode(o)
def make_snapshot_score_pdf(the_job: TheJob, score: db.ScoreTable) -> str:
job = the_job.job
contest = score.contest
round = contest.round
def order_to_tex(result: ScoreResult) -> str:
if not result.show_order:
return ""
order = result.order
if order.continuation:
return ""
elif order.span > 1:
return f'{order.place}.--{order.place + order.span -1}.'
else:
return f'{order.place}.'
temp_dir = job.dir_path()
tex_src = os.path.join(temp_dir, 'score.tex')
def parse_tex_hacks(tex_hacks: str) -> Dict[str, str]:
hacks = {}
fields = re.split(r'(\w+)={([^}]*)}', tex_hacks)
for i, f in enumerate(fields):
if i % 3 == 0:
if f.strip() != "":
raise RuntimeError('Chyba při parsování tex_hacks')
elif i % 3 == 1:
hacks[f] = fields[i + 1]
return hacks
def format_hacks(tex_hacks: str) -> str:
# Nemůžeme uživatelům dovolit předávat TeXu libovolné příkazy,
# protože bychom jim například zpřístupnili celý filesystem.
lines = []
for k, v in parse_tex_hacks(tex_hacks).items():
lines.append('\\hack' + k + tex_arg(v) + '\n')
return "".join(lines)
def make_score_pdf(temp_dir: str, score: Score, results: List[ScoreResult]) -> str:
# Pozor, toto se volá i z pomocných skriptů
contest = assert_not_none(score.contest)
round = contest.round
tasks = score.get_tasks()
tex_src = os.path.join(temp_dir, 'score.tex')
with open(tex_src, 'w') as f:
f.write('Zde bude výsledkovka\\bye\n')
f.write('\\input vysledky.tex\n\n')
hlavicka = f'Výsledková listina {db.round_type_names_genitive[round.round_type]} {round.year}. ročníku MO kategorie {round.category}'
f.write('\\def\\hlavicka' + tex_arg(hlavicka) + '\n')
if round.level > 0 and contest.place.name:
f.write('\\def\\misto' + tex_arg(contest.place.name) + '\n')
f.write(format_hacks(contest.tex_hacks))
f.write('\n')
last_type = ""
f.write('\\scoretable{\n')
for result in score.get_sorted_results():
if result.winner:
type = 'winner'
elif result.successful:
type = 'successful'
else:
type = 'normal'
if type != last_type:
f.write('\\section' + tex_arg(type) + '\n')
last_type = type
cols = [
order_to_tex(result),
result.user.full_name(),
result.pant.grade,
result.pant.school_place.name,
]
f.write('\\row' + "".join(map(tex_arg, cols)))
f.write('{')
sols = result.get_sols_map()
for task in tasks:
sol = sols.get(task.task_id)
if sol is not None and sol.points is not None:
pts = assert_not_none(format_decimal(sol.points))
else:
pts = '\\n'
f.write('\\p{' + pts + '}')
f.write('}')
f.write(tex_arg(format_decimal(result.get_total_points())) + '\n')
f.write('}\n')
f.write('\n\\bye\n')
env = dict(os.environ)
env['TEXINPUTS'] = mo.util.part_path('tex') + '//:'
@@ -69,10 +149,17 @@ def make_snapshot_score_pdf(the_job: TheJob, score: db.ScoreTable) -> str:
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
dir = str(contest.contest_id)
return os.path.join(temp_dir, 'score.pdf')
def make_snapshot_score_pdf(the_job: TheJob, contest: db.Contest, score: Score, results: List[ScoreResult]) -> str:
temp_dir = the_job.job.dir_path()
temp_pdf = make_score_pdf(temp_dir, score, results)
dir = contest.round.round_code_short()
full_dir = os.path.join(mo.util.data_dir('score'), dir)
os.makedirs(full_dir, exist_ok=True)
full_name = mo.util.link_to_dir(os.path.join(temp_dir, 'score.pdf'), full_dir, suffix='.pdf')
full_name = mo.util.link_to_dir(temp_pdf, full_dir, suffix='.pdf')
return os.path.join(dir, os.path.basename(full_name))
@@ -125,7 +212,7 @@ def handle_snapshot_score(the_job: TheJob):
}
pdf_file = make_snapshot_score_pdf(the_job, score)
pdf_file = make_snapshot_score_pdf(the_job, contest, score, results)
score_table = db.ScoreTable(
contest_id=ct_id,
@@ -175,6 +262,7 @@ def api_params(contest: db.Contest) -> Dict[str, Any]:
'region': contest.place.nuts,
}
def schedule_export_score_to_mo_web(score_table: db.ScoreTable) -> None:
the_job = TheJob()
job = the_job.create(db.JobType.export_score_to_mo_web, db.get_system_user())
Loading