*/
// must be run within Dokuwiki
if (!defined('DOKU_INC')) {
die();
}
class action_plugin_judge extends DokuWiki_Action_Plugin
{
/**
* Register the events
*
* @param Doku_Event_Handler $controller
*/
public function register(Doku_Event_Handler $controller)
{
/**
* Submission button in top user menu bar
*/
$controller->register_hook('TEMPLATE_USERTOOLS_DISPLAY', 'BEFORE', $this, 'addButton');
/**
* Submissions page content
*/
$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'submissionsPageAction');
$controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'submissionsPageContent');
/**
* Remove page cache after login
*/
$controller->register_hook('AUTH_LOGIN_CHECK', 'AFTER', $this, 'removePageCache');
/**
* export to csv icon in submissions page
*/
$controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'addCsvButton', array());
$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'exportToCSV');
/**
* Ajax calls
*/
$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajaxHandler');
}
public function addButton(Doku_Event $event)
{
if ($_SERVER['REMOTE_USER']) {
$event->data['items'] = array_slice($event->data['items'], 0, -1, true)
+ array('submissions' => '
' . $this->getLang('btn_my_submissions') . '')
+ array_slice($event->data['items'], -1, 1, true);
}
}
public function submissionsPageAction(&$event)
{
if ($event->data != 'submissions') {
return;
}
$event->preventDefault();
return true;
}
public function submissionsPageContent(&$event)
{
if ($event->data != 'submissions') {
return;
}
$event->preventDefault();
$table_html = $this->buildResultTable();
print $table_html;
}
public function buildResultTable()
{
$crud = plugin_load('helper', 'judge_crud');
$table_html = '
' . $this->getLang('programming_questions') . '
' . $this->getLang('count_number') . ' | ' . $this->getLang('question_name') . ' | ' . $this->getLang('timestamp') . ' | ' . $this->getLang('language') . ' | ' . $this->getLang('status') . ' |
';
$table_html .= $crud->tableRender(array('type' => "test-case", 'user' => $_SERVER['REMOTE_USER']), "html", 1, "timestamp")["submissions_table"];
$table_html .= '
';
$table_html .= '
' . $this->getLang('outputonly_questions') . '
';
return $table_html;
}
public function addCsvButton(Doku_Event $event)
{
global $ID, $ACT;
if ($ACT != 'submissions') {
return;
}
if ($event->data['view'] == 'main') {
$params = array('do' => 'export_csv');
// insert button at position before last (up to top)
$event->data['items'] = array_slice($event->data['items'], 0, -1, true) +
array('export_pdf' =>
''
. ''
. '' . $this->getLang('btn_export_csv') . ''
. ''
. ''
) +
array_slice($event->data['items'], -1, 1, true);
}
}
public function exportToCSV(&$event)
{
if ($event->data != 'export_csv') {
return;
}
$event->preventDefault();
$crud = plugin_load('helper', 'judge_crud');
ob_start('ob_gzhandler');
ob_clean();
$csvOutput = "#\tType\tProblem name\tTimestamp\tLanguage\tStatus\n";
$csvOutput .= $crud->tableRender(array('type' => "output-only", 'user' => $_SERVER['REMOTE_USER']), "csv", 1, "timestamp")["submissions_table"];
$csvOutput .= $crud->tableRender(array('type' => "test-case", 'user' => $_SERVER['REMOTE_USER']), "csv", 1, "timestamp")["submissions_table"];
print $csvOutput;
ob_end_flush();
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=" . $_SERVER['REMOTE_USER'] . "_submissions_" . date("Y-m-d_H-i", time()) . ".csv");
header("Pragma: no-cache");
header("Expires: 0");
}
public function removePageCache(&$event)
{
global $config_cascade;
@touch(reset($config_cascade['main']['local']));
}
function ajaxHandler(Doku_Event $event, $param)
{
if ($event->data !== 'plugin_judge') {
return;
}
//no other ajax call handlers needed
$event->stopPropagation();
$event->preventDefault();
global $INPUT;
$task = $INPUT->str('name');
//data
$data = array();
switch ($task) {
case "submit":
define('DBFILE', dirname(__FILE__) . '/submissions.sqlite');
define('DBENGINE', 'sqlite3');
if (file_exists(DBFILE)) {
$data = $this->submit_to_db();
}
case "outputonlyResult":
$data[] = $this->compare($INPUT->str('user_output'), $INPUT->str('problem_name'));
break;
case "resultRefresh":
$crud = plugin_load('helper', 'judge_crud');
$data[] = $crud->tableRender(array('problem_name' => $INPUT->str('problem_name'), 'type' => $INPUT->str('type'), 'user' => $INPUT->str('user')), "html", 1, "timestamp")["submissions_table"];
break;
case "judge":
sleep(10);
$run_status = rand(0, 4);
define('DBFILE', dirname(__FILE__) . '/submissions.sqlite');
$db = new SQLite3(DBFILE);
$query = 'UPDATE submissions SET status_code =1 WHERE submit_id = ' . $_POST['id'] . ';';
$db->exec($query);
$query = 'UPDATE submission_test_case SET valid =' . $run_status . ' WHERE submit_id = ' . $_POST['id'] . ';';
$db->exec($query);
break;
case "upload":
$data[] = $this->upload($INPUT->str('file_name'), $INPUT->str('path'), $INPUT->str('code'));
break;
case "scoreboardRefresh":
$crud = plugin_load('helper', 'judge_crud');
$i = 1;
$html = "";
foreach (explode(",",$INPUT->str('questions')) as &$problem_name) {
$submissions = $crud->tableRender(array('problem_name' => $problem_name, 'type' => "test-case", 'user' => null), "html", $i, "timestamp");
$html .= $submissions["submissions_table"];
$i = $submissions["count"];
}
$data[] = $html;
break;
}
//json library of DokuWiki
$json = new JSON();
//set content type
header('Content-Type: application/json');
echo $json->encode($data);
}
function submit_to_db()
{
if (!defined('DOKU_INC')) {
define('DOKU_INC', dirname(__FILE__) . '/../../../../');
include_once DOKU_INC . 'inc/init.php';
include_once DOKU_INC . 'inc/plugin.php';
}
global $conf;
include_once dirname(__FILE__) . '/helper/jdatetime.class.php';
$pdate = new jDateTime(false, true, 'Asia/Tehran');
date_default_timezone_set('Asia/Tehran');
$query = 'INSERT INTO submissions VALUES (NULL,"' . time() . '","' . $_POST['problem_name'] . '","' . $_POST['user'] . '","' . $_POST['type'] . '",' . $_POST['status_code'] . ')';
$db = new SQLite3(DBFILE);
$db->exec($query);
$id = $db->lastInsertRowID();
$result_id_query = 'SELECT COUNT(*) FROM submissions WHERE problem_name = "' . $_POST['problem_name'] . '"AND username="' . $_POST['user'] . '"';
$row_number = $db->querySingle($result_id_query);
if ($conf['lang'] == "fa") {
$date = $pdate->date("l j F Y H:i:s");
} else {
$date = date('l j F Y H:i:s');
}
if ($_POST['type'] === "output-only") {
$result = array('date' => $date, 'row_number' => $row_number);
} elseif ($_POST['type'] === "test-case") {
$test_case_query = 'INSERT INTO submission_test_case VALUES (' . $id . ',"' . $_POST['language'] . '",' . '0,"' . $_POST['runtime'] . '")';
$db->exec($test_case_query);
$result = array('date' => $date, 'row_number' => $row_number, 'id' => $id);
}
return $result;
}
public function compare($user_output, $problem_name)
{
$extension = $this->loadHelper('judge_numbers');
$answer = $extension->parseNumber(rawWiki("داوری:" . $problem_name));
if ($answer == $extension->parseNumber($user_output)) {
return true;
} else {
return false;
}
}
public function upload($filename, $path, $code)
{
$allowedExts = array("java", "py", "c", "cpp");
if (!in_array(pathinfo(basename($filename), PATHINFO_EXTENSION), $allowedExts, true)) {
return $this->getLang('err_file_format');
}
$targetdir = $path;
if (substr($targetdir, -1) != "/") {
$targetdir .= "/";
}
if (substr($targetdir, 1) != "/") {
$targetdir = "/" . $targetdir;
}
$temp = explode(".", $filename);
if (file_exists(TARGETFILE)) {
return $filename . $this->getLang('err_file_exist');
} elseif (!file_exists($targetdir)) {
return $this->getLang('err_dir') . $targetdir . $this->getLang('err_upload_dir');
} else {
define('DBFILE', dirname(__FILE__) . '/submissions.sqlite');
$db = new SQLite3(DBFILE);
$query = 'SELECT submit_id FROM submissions ORDER BY submit_id DESC LIMIT 1';
$id = $db->exec($query);
define('TARGETFILE', $targetdir . $id . "." . end($temp));
file_put_contents(TARGETFILE, $code);
}
}
}