- 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 {
 | 
			
		||||
    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;
 | 
			
		||||
@ -130,6 +169,8 @@ class Report
 | 
			
		||||
        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