- 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 CORRECT = "Correct";
 | 
				
			||||||
    const INCORRECT = "Incorrect";
 | 
					    const INCORRECT = "Incorrect";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -34,19 +59,22 @@ class Answer {
 | 
				
			|||||||
    private string $type; // Answer's type
 | 
					    private string $type; // Answer's type
 | 
				
			||||||
    private float $ratio; // Answer's ratio
 | 
					    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->type = $type;
 | 
				
			||||||
        $this->text = $text;
 | 
					        $this->text = $text;
 | 
				
			||||||
        $this->ratio = $ratio;
 | 
					        $this->ratio = $ratio;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Convert answer into TeX format.
 | 
					    // Convert answer into TeX format.
 | 
				
			||||||
    public function genTeX(): string {
 | 
					    public function genTeX(): string
 | 
				
			||||||
        return "\\answer" . $this->type . "{" . $this->ratio . "}{" .  $this->text . "}\n";
 | 
					    {
 | 
				
			||||||
 | 
					        return "\\answer" . $this->type . "{" . $this->ratio . "}{" . $this->text . "}\n";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Challenge {
 | 
					class Challenge
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    private string $question;
 | 
					    private string $question;
 | 
				
			||||||
    private array $answers;
 | 
					    private array $answers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,23 +84,26 @@ class Challenge {
 | 
				
			|||||||
        for ($i = 0; $i < count($data["answers"]); $i++) {
 | 
					        for ($i = 0; $i < count($data["answers"]); $i++) {
 | 
				
			||||||
            $answer = $data["answers"][$i];
 | 
					            $answer = $data["answers"][$i];
 | 
				
			||||||
            $ratio = $data["answer_ratio"][$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);
 | 
					            $this->answers[] = new Answer($type, $answer, $ratio);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getQuestion(): string {
 | 
					    public function getQuestion(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        return $this->question;
 | 
					        return $this->question;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getAnswers(): array {
 | 
					    public function getAnswers(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        return $this->answers;
 | 
					        return $this->answers;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate TeX representation.
 | 
					    // Generate TeX representation.
 | 
				
			||||||
    public function genTeX(): string {
 | 
					    public function genTeX(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        $tex = "\\begin{question}{" . $this->question . "}\n";
 | 
					        $tex = "\\begin{question}{" . $this->question . "}\n";
 | 
				
			||||||
        foreach ($this->answers as $answer) {
 | 
					        foreach ($this->answers as &$answer) {
 | 
				
			||||||
            $tex .= $answer->genTeX();
 | 
					            $tex .= $answer->genTeX();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $tex .= "\\end{question}\n";
 | 
					        $tex .= "\\end{question}\n";
 | 
				
			||||||
@ -80,23 +111,30 @@ class Challenge {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReportSection {
 | 
					class ReportSection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    private string $title;
 | 
					    private string $title;
 | 
				
			||||||
    private array $challenges;
 | 
					    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;
 | 
					        return $this->challenges;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function getTitle() : string {
 | 
					    function getTitle(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        return $this->title;
 | 
					        return $this->title;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate TeX representation of this report.
 | 
					    // Generate TeX representation of this report.
 | 
				
			||||||
    function genTeX() : string {
 | 
					    function genTeX(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        $tex = "\\begin{quiz}{" . $this->title . "}\n";
 | 
					        $tex = "\\begin{quiz}{" . $this->title . "}\n";
 | 
				
			||||||
        foreach ($this->challenges as $challenge) {
 | 
					        foreach ($this->challenges as $challenge) {
 | 
				
			||||||
            $tex .= $challenge->genTeX();
 | 
					            $tex .= $challenge->genTeX();
 | 
				
			||||||
@ -110,6 +148,7 @@ class Report
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    private string $title;
 | 
					    private string $title;
 | 
				
			||||||
    private array $sections;
 | 
					    private array $sections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function __construct(string $title)
 | 
					    function __construct(string $title)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->title = $title;
 | 
					        $this->title = $title;
 | 
				
			||||||
@ -118,18 +157,20 @@ class Report
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add a new section to the report.
 | 
					    // Add a new section to the report.
 | 
				
			||||||
    function addSection(ReportSection &$section) : void
 | 
					    function addSection(ReportSection &$section): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->sections[] = $section;
 | 
					        $this->sections[] = $section;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate TeX representation.
 | 
					    // Generate TeX representation.
 | 
				
			||||||
    function genTeX() :string
 | 
					    function genTeX(): string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $tex = "";
 | 
					        $tex = "";
 | 
				
			||||||
        foreach ($this->sections as $section) {
 | 
					        foreach ($this->sections as $section) {
 | 
				
			||||||
            $tex .= $section->genTeX() . "\n\n";
 | 
					            $tex .= $section->genTeX() . "\n\n";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        $tex = TeXUtils::processCodeInserts($tex);
 | 
				
			||||||
 | 
					        $tex = TeXUtils::escape($tex);
 | 
				
			||||||
        return $tex;
 | 
					        return $tex;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,7 +178,8 @@ class Report
 | 
				
			|||||||
    const TITLE_FILE = "title.tex";
 | 
					    const TITLE_FILE = "title.tex";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Save TeX representation.
 | 
					    // 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::CONTENT_FILE, $this->genTeX());
 | 
				
			||||||
        file_put_contents($dir . DIRECTORY_SEPARATOR . self::TITLE_FILE, $this->title);
 | 
					        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
 | 
					    // 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";
 | 
					    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("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("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_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.");
 | 
					$rh->add("delete_tests", ["ids"], PRIVILEGE_CREATOR, "delete_tests", RESP_PLAIN, "Delete tests.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// execute processing if user is a creator
 | 
					// execute processing if user is a creator
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user