- report PDF generation is a makeshift, but works
This commit is contained in:
parent
ef6b98f036
commit
1e6590f6bb
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user