- report PDF generation is a makeshift, but works

This commit is contained in:
Wiesner András 2024-09-26 18:22:21 +02:00
parent ef6b98f036
commit 1e6590f6bb
2 changed files with 82 additions and 21 deletions

View File

@ -26,7 +26,32 @@ class ReportBuilder
}
}
class Answer {
class TeXUtils
{
static public function processCodeInserts(string $str) : string
{
$parts = explode("`", $str);
$output = "";
for ($i = 0; $i < count($parts); $i++) {
$output .= $parts[$i];
if ($i < count($parts) - 1) {
if (($i % 2) === 0) {
$output .= "\\texttt{";
} else {
$output .= "}";
}
}
}
return $output;
}
static public function escape(string $str) : string {
return preg_replace("/([#%&])/", "\\\\$1", $str);
}
}
class Answer
{
const CORRECT = "Correct";
const INCORRECT = "Incorrect";
@ -34,19 +59,22 @@ class Answer {
private string $type; // Answer's type
private float $ratio; // Answer's ratio
public function __construct(string $type, string $text, float $ratio) {
public function __construct(string $type, string $text, float $ratio)
{
$this->type = $type;
$this->text = $text;
$this->ratio = $ratio;
}
// Convert answer into TeX format.
public function genTeX(): string {
return "\\answer" . $this->type . "{" . $this->ratio . "}{" . $this->text . "}\n";
public function genTeX(): string
{
return "\\answer" . $this->type . "{" . $this->ratio . "}{" . $this->text . "}\n";
}
}
class Challenge {
class Challenge
{
private string $question;
private array $answers;
@ -56,23 +84,26 @@ class Challenge {
for ($i = 0; $i < count($data["answers"]); $i++) {
$answer = $data["answers"][$i];
$ratio = $data["answer_ratio"][$i];
$type = $answer === $data["correctAnswer"] ? Answer::CORRECT : Answer::INCORRECT;
$type = $answer === $data["correct_answer"] ? Answer::CORRECT : Answer::INCORRECT;
$this->answers[] = new Answer($type, $answer, $ratio);
}
}
public function getQuestion(): string {
public function getQuestion(): string
{
return $this->question;
}
public function getAnswers(): array {
public function getAnswers(): array
{
return $this->answers;
}
// Generate TeX representation.
public function genTeX(): string {
public function genTeX(): string
{
$tex = "\\begin{question}{" . $this->question . "}\n";
foreach ($this->answers as $answer) {
foreach ($this->answers as &$answer) {
$tex .= $answer->genTeX();
}
$tex .= "\\end{question}\n";
@ -80,23 +111,30 @@ class Challenge {
}
}
class ReportSection {
class ReportSection
{
private string $title;
private array $challenges;
function __construct(string $title, array $stats) {
$this->stats = $stats;
function __construct(string $title, array $challenges)
{
$this->title = $title;
$this->challenges = array_map(fn($ch) => new Challenge($ch), $challenges);
}
function getChallenges() : array {
function getChallenges(): array
{
return $this->challenges;
}
function getTitle() : string {
function getTitle(): string
{
return $this->title;
}
// Generate TeX representation of this report.
function genTeX() : string {
function genTeX(): string
{
$tex = "\\begin{quiz}{" . $this->title . "}\n";
foreach ($this->challenges as $challenge) {
$tex .= $challenge->genTeX();
@ -110,6 +148,7 @@ class Report
{
private string $title;
private array $sections;
function __construct(string $title)
{
$this->title = $title;
@ -118,18 +157,20 @@ class Report
// Add a new section to the report.
function addSection(ReportSection &$section) : void
function addSection(ReportSection &$section): void
{
$this->sections[] = $section;
}
// Generate TeX representation.
function genTeX() :string
function genTeX(): string
{
$tex = "";
foreach ($this->sections as $section) {
$tex .= $section->genTeX() . "\n\n";
}
$tex = TeXUtils::processCodeInserts($tex);
$tex = TeXUtils::escape($tex);
return $tex;
}
@ -137,7 +178,8 @@ class Report
const TITLE_FILE = "title.tex";
// Save TeX representation.
function saveTeX(string $dir) : void {
function saveTeX(string $dir): void
{
file_put_contents($dir . DIRECTORY_SEPARATOR . self::CONTENT_FILE, $this->genTeX());
file_put_contents($dir . DIRECTORY_SEPARATOR . self::TITLE_FILE, $this->title);
}

View File

@ -551,7 +551,26 @@ function generate_report_by_groups(ReqHandler &$rh, array $params): string
}
// generate latex
$report->saveTeX("report/");
$report_dir = "report";
$report->saveTeX($report_dir . DIRECTORY_SEPARATOR . "stats");
// run LuaLaTeX twice
chdir($report_dir);
$tex_cmd = "lualatex -interaction=nonstopmode report.tex";
exec($tex_cmd);
exec($tex_cmd);
$output = "report.pdf";
header("Content-Type: application/pdf");
header("Content-Length: " . filesize($output));
// deploy the generated PDF
$pdf = fopen($output, "r");
if ($pdf !== false) {
fpassthru($pdf);
fclose($pdf);
}
return "OK";
}
@ -583,7 +602,7 @@ $rh->add("delete_games", ["ids"], PRIVILEGE_CREATOR, "delete_games", RESP_PLAIN,
$rh->add("export_game_file_csv", ["gameid"], PRIVILEGE_CREATOR, "export_game_file_csv", RESP_NONE, "Export game CSV file.");
$rh->add("get_results_by_gameid", ["gameid"], PRIVILEGE_CREATOR, "get_results_by_gameid", RESP_JSON, "Get game results.");
$rh->add("generate_detailed_stats", ["gameid", "testids"], PRIVILEGE_CREATOR, "generate_detailed_game_stats", RESP_JSON, "Generate detailed game stats.");
$rh->add("generate_report_by_groups", ["gameid", "groups"], PRIVILEGE_CREATOR, "generate_report_by_groups", RESP_PLAIN, "Generate game reports for each specified group.");
$rh->add("generate_report_by_groups", ["gameid", "groups"], PRIVILEGE_CREATOR, "generate_report_by_groups", RESP_NONE, "Generate game reports for each specified group.");
$rh->add("delete_tests", ["ids"], PRIVILEGE_CREATOR, "delete_tests", RESP_PLAIN, "Delete tests.");
// execute processing if user is a creator