Index: common/security.php
===================================================================
--- common/security.php	(revision 1144)
+++ common/security.php	(working copy)
@@ -145,6 +145,7 @@
         case 'textblock-change-security':
         case 'task-edit-owner':
         case 'task-edit-ratings':
+        case 'round-liveeval':
         case 'round-tag':
         case 'round-view-progress':
         case 'textblock-tag':
Index: www/controllers/liveeval.php
===================================================================
--- www/controllers/liveeval.php	(revision 0)
+++ www/controllers/liveeval.php	(revision 0)
@@ -0,0 +1,165 @@
+<?php
+
+require_once(IA_ROOT_DIR."www/format/pager.php");
+require_once(IA_ROOT_DIR."common/db/job.php");
+require_once(IA_ROOT_DIR."common/db/task.php");
+require_once(IA_ROOT_DIR."www/controllers/job_filters.php");
+
+function liveeval_job_get_range_wheres_job($filters) {
+    $rounds = getattr($filters, 'round');
+    $remote_ip_info = getattr($filters, 'remote_ip_info');
+
+    $wheres_job = array("TRUE");
+    if (!is_null($rounds)) {
+        $wheres_job[] = "`job`.`round_id` IN (" .
+                        implode(", ", array_map('db_quote', $rounds)) . ")";
+    }
+    if (!is_null($remote_ip_info)) {
+        $wheres_job[] = sprintf("`job`.`remote_ip_info` LIKE '%s'",
+                                db_escape($remote_ip_info));
+    }
+    return $wheres_job;
+}
+
+// Get a range of jobs, ordered by submit time. Really awesome filterss!
+function liveeval_job_get_range($filters, $start, $range) {
+    log_assert(is_whole_number($start));
+    log_assert(is_whole_number($range));
+    log_assert($start >= 0);
+    log_assert($range >= 0);
+
+    $query = "
+        SELECT
+            `job`.`id`,
+            `job`.`user_id` AS `user_id`,
+            `job`.`round_id` AS `round_id`,
+            `job`.`task_id` AS `task_id`,
+            `job`.`submit_time`,
+            `job`.`compiler_id`,
+            `job`.`status`,
+            `job`.`score`,
+            `job`.`eval_message`,
+            `job`.`eval_log`,
+            `job`.`remote_ip_info`,
+            OCTET_LENGTH(`job`.`file_contents`) AS `job_size`,
+            `user`.`username` AS `user_name`,
+            `user`.`full_name` AS `user_fullname`,
+            `task`.`page_name` AS `task_page_name`,
+            `task`.`title` AS `task_title`,
+            `task`.`hidden` AS `task_hidden`,
+            `task`.`user_id` AS `task_owner_id`,
+            `task`.`open_source` AS `task_open_source`,
+            `round`.`page_name` AS `round_page_name`,
+            `round`.`title` AS `round_title`,
+            `round`.`state` AS `round_state`,
+            `round`.`type` AS `round_type`,
+            `round`.`public_eval` AS `round_public_eval`
+        #    (CASE WHEN `status` = 'processing' THEN
+        #        (SELECT `value` FROM `ia_parameter_value` WHERE
+        #            `ia_parameter_value`.`object_id` = `task_id` AND
+        #            `ia_parameter_value`.`object_type` = 'task' AND
+        #            `ia_parameter_value`.`parameter_id` = 'tests')
+        #        ELSE NULL END) AS `total_tests`,
+        #    (CASE WHEN `status` = 'processing' THEN
+        #        (SELECT COUNT(*) FROM `ia_job_test`
+        #            WHERE `ia_job_test`.`job_id` = `job`.`id`)
+        #        ELSE NULL END) AS `done_tests`
+        FROM `ia_job` AS `job`
+        LEFT JOIN `ia_task` AS `task` ON `job`.`task_id` = `task`.`id`
+        LEFT JOIN `ia_round` AS `round` ON `job`.`round_id` = `round`.`id`
+        LEFT JOIN `ia_user` AS `user` ON `job`.`user_id` = `user`.`id`";
+
+    $wheres_job = liveeval_job_get_range_wheres_job($filters);
+    $subquery = "
+        SELECT `job`.`id` AS `ID`
+        FROM `ia_job` as `job`
+        WHERE (" . implode(") AND (", $wheres_job) . ")
+        ORDER BY `id` DESC LIMIT {$start}, {$range}";
+
+    $job_ids_fetched = db_fetch_all($subquery);
+    foreach ($job_ids_fetched as $job_id) {
+        $job_ids[] = $job_id["ID"];
+    }
+    if (empty($job_ids)) {
+        return array();
+    }
+    $query .= "
+        WHERE `job`.`id` IN (" . implode(", ", array_map('db_quote', $job_ids)) . ")
+        ORDER BY `job`.`id` DESC";
+
+    $result = db_fetch_all($query);
+
+    return $result;
+}
+
+// Counts jobs based on complex filters
+function liveeval_job_get_count($filters) {
+    $query = "
+        SELECT COUNT(*) AS `cnt`
+        FROM
+            `ia_job` AS `job`";
+
+    if (getattr($filters, 'task_hidden')) {
+        $query .= "
+            LEFT JOIN `ia_task` AS `task` ON `job`.`task_id` = `task`.`id`";
+    }
+
+    // score_begin and score_end filters shouldn't work on rounds
+    // without public eval, so we join with ia_round
+    if (getattr($filters, 'score_begin') || getattr($filters, 'score_end')) {
+        $query .= "
+            LEFT JOIN `ia_round` AS `round` ON `job`.`round_id` = `round`.`id`";
+    }
+
+    $wheres_job = liveeval_job_get_range_wheres_job($filters);
+    $query .= "
+        WHERE (".implode(") AND (", $wheres_job).")";
+
+    $res = db_fetch($query);
+    return $res['cnt'];
+}
+
+// Job monitor controller.
+function controller_liveeval() {
+    global $identity_user;
+
+    identity_require('round-liveeval');
+
+    $view = array();
+    $view['filters'] = job_get_filters();
+    $view['user_name'] = getattr($identity_user, 'username');
+
+    // First row.
+    // FIXME: shouldn't this constant be in config.php?
+    $options = pager_init_options(array('display_entries' => 25));
+
+    $job_data = liveeval_job_get_range($view['filters'], $options['first_entry'], $options['display_entries']);
+    $jobs = array();
+    foreach ($job_data as $job) {
+        if (!identity_can("job-view-score", $job)) {
+            $job["score"] = NULL;
+            if (identity_can("job-view-partial-feedback", $job)) {
+                $task = task_get($job["task_id"]);
+                if ($task["public_tests"]) {
+                    $job["feedback_available"] = true;
+                }
+            }
+        }
+        if (!identity_can('job-view-source-size', $job)) {
+            $job["job_size"] = NULL;
+        }
+
+        $jobs[] = $job;
+    }
+
+    $view['title'] = 'Monitorul de evaluare';
+    $view['jobs'] = $jobs;
+    $view['total_entries'] = liveeval_job_get_count($view['filters']);
+    $view['first_entry'] = $options['first_entry'];
+    $view['display_entries'] = $options['display_entries'];
+    $view['display_only_table'] = request('only_table', false);
+
+    execute_view_die('views/liveeval.php', $view);
+}
+
+?>
Index: www/index.php
===================================================================
--- www/index.php	(revision 1144)
+++ www/index.php	(working copy)
@@ -49,7 +49,8 @@
                                'login', 'logout', 'json', 'job_detail',
                                'monitor', 'projector', 'submit', 'userinfo',
                                'plot', 'search',
-                               'unsubscribe', 'resetpass', 'reeval'
+                               'unsubscribe', 'resetpass', 'reeval',
+                               'liveeval'
 ));
 
 //
Index: www/views/liveeval.php
===================================================================
--- www/views/liveeval.php	(revision 0)
+++ www/views/liveeval.php	(revision 0)
@@ -0,0 +1,191 @@
+<?php
+
+require_once(IA_ROOT_DIR.'www/format/table.php');
+require_once(IA_ROOT_DIR.'www/format/format.php');
+require_once(IA_ROOT_DIR.'www/format/list.php');
+require_once(IA_ROOT_DIR."www/format/form.php");
+
+$view['head'] = '
+<style type="text/css">
+#sidebar, #header, #topnav, #breadcrumbs {
+        display: none;
+}
+#main {
+        margin-left: 0;
+}
+</style>
+';
+if (!$display_only_table) {
+    include('header.php');
+}
+?>
+
+<script type="text/javascript">
+var states = new Array();
+var initialHTML = new Array();
+
+function getStates() {
+    if (document.getElementsByTagName("tbody").length == 0) {
+        return;
+    }
+    var tbody = document.getElementsByTagName("tbody")[0];
+    var rows = tbody.getElementsByTagName("tr");
+    for (var i = 0; i < rows.length; ++i) {
+        var child = rows[i].firstChild;
+        for (var j = 0; j < 3; ++j)
+            child = child.nextSibling;
+        states.push(child);
+        initialHTML.push(child.innerHTML);
+        child.innerHTML = "<a href=''>in asteptare</a>";
+    }
+}
+
+function showScore(node, html) {
+    html = html.replace("hidden", "");
+    node.innerHTML = html;
+}
+
+function stopWait(index) {
+    showScore(states[index], initialHTML[index]);
+    if (index > 0) {
+        startWait(index - 1);
+    }
+}
+
+function startWait(index) {
+    states[index].innerHTML = "<a href=''><img src='" +
+                        "<? echo url_static("images/indicator.gif"); ?>" +
+                        "' />se evaluaza</a>";
+    setTimeout('stopWait(' + index + ')', Math.random() * 1000 + 1500);
+}
+
+function evaluateAll() {
+    startWait(states.length - 1);
+}
+
+function showAllScores() {
+    for (var i = 0; i < states.length; ++i) {
+        showScore(states[i], initialHTML[i]);
+    }
+}
+
+window.onload = function () {
+    getStates();
+}
+</script>
+
+<?php
+
+if (!$display_only_table) {
+    echo '<h1>'.html_escape($view['title']).'</h1>';
+}
+
+if (!$display_only_table) {
+    echo "<div id=\"monitor-table\">";
+}
+
+if (!$jobs) {
+    echo "<div class=\"notice\">Nici o solutie in coada de evaluare</div>";
+} else {
+    echo "<div class='reeval'><a onClick='showAllScores()'>rezultate</a>
+        <a onClick='evaluateAll()'>evalueaza</a></div>";
+
+    // For the score column.
+    function format_state($row) {
+        $url = url_job_detail($row['id']);
+        if ($row['status'] == 'done') {
+            $msg = "<span class=\"hidden\">";
+            if (!is_null($row['score'])) {
+                $msg .= html_escape(sprintf("%s: %s puncte",
+                    $row['eval_message'], $row['score']));
+            } else {
+                $msg .= html_escape($row['eval_message']);
+            }
+            $msg .= "</span>";
+            $msg = "<span class=\"job-status-done\">$msg</span>";
+            return format_link($url, $msg, false);
+        }
+        log_error("Invalid job status");
+    }
+
+    // For the task column.
+    function format_task_link($row) {
+        if (!identity_can("job-view", $row)){
+            return "...";
+        }
+        return format_link(
+                url_textblock($row['task_page_name']),
+                $row['task_title']);
+    }
+
+    // For the round column.
+    function format_round_link($row) {
+    //    return $row['round_id'];
+        return format_link(
+                url_textblock($row['round_page_name']),
+                $row['round_title']);
+    }
+
+    // For the detail column.
+    function format_jobdetail_link($val) {
+        return format_link(url_job_detail($val), "#$val");
+    }
+
+    $column_infos = array(
+        array(
+            'title' => 'Utilizator',
+            'key' => 'username',
+            'rowform' => create_function_cached('$row',
+                 'return format_user_tiny($row["user_name"], $row["user_fullname"]);'),
+        ),
+        array(
+            'title' => 'Problema',
+            'rowform' => 'format_task_link',
+        ),
+        array(
+            'title' => 'Runda',
+            'rowform' => 'format_round_link',
+        ),
+        array(
+            'title' => 'Stare',
+            'rowform' => 'format_state',
+        ),
+    );
+    $options = array(
+        'css_class' => 'monitor',
+        'show_count' => true,
+        'display_entries' => $view['display_entries'],
+        'total_entries' => $view['total_entries'],
+        'first_entry' => $view['first_entry'],
+        'pager_style' => 'standard',
+        'surround_pages' => 3,
+        'url_args' => $view['filters'] + array('page' => 'liveeval'),
+    );
+    print format_table($jobs, $column_infos, $options);
+}
+
+// Please don't use wiki_include() here because this is traffic
+// intensive page.
+
+if (!$display_only_table) {
+    $monitor_params = array('only_table' => 1, 'first_entry' => $first_entry, 'display_entries' => $view['display_entries']);
+    $url_monitor = url_absolute(url_complex('liveeval', $view['filters'] + $monitor_params));
+
+?>
+    </div>
+
+    <script type="text/javascript">
+        Monitor_Url = '<?= $url_monitor ?>';
+    </script>
+
+    <p>
+        <br/>
+        <?= format_link("documentatie/monitorul-de-evaluare", "Ce este si cum se foloseste") ?>
+        monitorul de evaluare.
+    </p>
+
+<?php
+    include('footer.php');
+}
+
+?>
