Index: common/common.php
===================================================================
--- common/common.php	(revision 1075)
+++ common/common.php	(working copy)
@@ -174,6 +174,12 @@
         strlen($round_id) < 64;
 }
 
+// Checks if round_rated is a valid round rated status
+function is_round_rated($round_rated) {
+    return in_array($round_rated,
+        array('not-updated', 'updated', 'waiting-update', 'waiting-reset'));
+}
+
 // Check valid score names.
 // Does not check existence.
 function is_score_name($score_name) {
Index: common/db/round.php
===================================================================
--- common/db/round.php	(revision 1075)
+++ common/db/round.php	(working copy)
@@ -65,6 +65,14 @@
     }
 }
 
+// Update round rated status
+function round_update_rated($round, $rated_status) {
+    log_assert_valid(round_validate($round));
+    log_assert(is_round_rated($rated_status));
+    $round['rated'] = $rated_status;
+    round_update($round);
+}
+
 // Returns array with all tasks attached to the specified round
 //
 // :WARNING: This does not select all fields related to each task,
Index: common/db/score.php
===================================================================
--- common/db/score.php	(revision 1075)
+++ common/db/score.php	(working copy)
@@ -105,7 +105,7 @@
     $where = score_build_where_clauses($user, $task, $round);
     $where[] = sprintf("ia_score.`name` = '%s'", db_escape($score_name));
     $query = sprintf("SELECT
-                ia_score.`name` AS `score_name`, `user_id`, `task_id`, `round_id`, SUM(`score`) AS score, 
+                ia_score.`name` AS `score_name`, `user_id`, `task_id`, `round_id`, SUM(`score`) AS score,
                 ia_user.username AS user_name, ia_user.full_name AS user_full,
                 ia_user.rating_cache AS user_rating
             FROM ia_score
@@ -122,7 +122,7 @@
         // in the requested range.
         $where = score_build_where_clauses($user, $task, $round);
         $where[] = sprintf("ia_score.`name` = '%s'", db_escape($score_name));
-        $query = sprintf("SELECT SUM(`score`) AS score 
+        $query = sprintf("SELECT SUM(`score`) AS score
                           FROM ia_score
                           WHERE %s GROUP BY %s
                           HAVING score > %s",
@@ -259,7 +259,8 @@
         SELECT
                object_id AS round_id, `value` AS `timestamp`,
                ia_round.page_name AS round_page_name,
-               ia_round.title AS round_title
+               ia_round.title AS round_title,
+               ia_round.rated AS round_rated
         FROM `ia_parameter_value`
         LEFT JOIN ia_round ON ia_round.id = ia_parameter_value.object_id
         WHERE parameter_id = 'rating_timestamp' AND object_type = 'round'
@@ -272,7 +273,8 @@
         $rounds[$row['round_id']] = array(
             'timestamp' => $row['timestamp'],
             'round_page_name' => $row['round_page_name'],
-            'round_title' => $row['round_title']
+            'round_title' => $row['round_title'],
+            'round_rated' => $row['round_rated']
         );
     }
 
@@ -345,7 +347,7 @@
     // FIXME: We should filter out rounds having rating_update off
     // but these should not have any ratings stored in database anyway...
 
-    // parse rows 
+    // parse rows
     $users = array();
     foreach ($rows as $row) {
         $username = $row['username'];
@@ -429,7 +431,7 @@
 
 
         $rows[0]['position'] = $users_before + 1;
-        $equal_scores = $start - $users_before + 1;          
+        $equal_scores = $start - $users_before + 1;
         for ($i = 1; $i < count($rows); ++$i) {
             $last_row = $rows[$i - 1];
             $row =& $rows[$i];
@@ -461,6 +463,7 @@
 function rating_clear() {
     db_query("DELETE FROM ia_score WHERE `name` IN ('rating', 'deviation')");
     db_query("UPDATE ia_user SET rating_cache = NULL");
+    db_query("UPDATE ia_round SET rated = 'not-updated'");
 }
 
 ?>
Index: common/round.php
===================================================================
--- common/round.php	(revision 1075)
+++ common/round.php	(working copy)
@@ -78,6 +78,7 @@
             'state' => 'waiting',
             'start_time' => NULL,
             'public_eval' => (($round_type == 'archive') ? 1 : 0),
+            'rated' => 'not-updated',
             'user_id' => $user['id']
     );
 
@@ -119,6 +120,9 @@
     if (!is_db_date(getattr($round, 'start_time', db_date_format()))) {
         $errors['start_time'] = "Timpul trebuie specificat ca YYYY-MM-DD HH:MM:SS";
     }
+    if (!is_round_rated(getattr($round, 'rated'))) {
+        $errors['rated'] = "rated este invalid";
+    }
 
     if (!is_user_id(getattr($round, 'user_id', ''))) {
         $errors['user_id'] = "ID-ul userului este invalid";
@@ -167,4 +171,14 @@
     }
 }
 
+// Return the next round id that needs rating update
+function round_get_rating_update() {
+    foreach (rating_rounds() as $key => $round) {
+        if (in_array($round['round_rated'],
+            array('waiting-update', 'waiting-reset'))) {
+            return $key;
+        }
+    }
+}
+
 ?>
Index: common/security.php
===================================================================
--- common/security.php	(revision 1075)
+++ common/security.php	(working copy)
@@ -147,6 +147,7 @@
         case 'textblock-tag':
         case 'job-reeval':
         case 'simple-critical':
+        case 'round-rating-update':
             return 'simple-critical';
 
         // Special actions fall through
Index: eval/eval
===================================================================
--- eval/eval	(revision 1075)
+++ eval/eval	(working copy)
@@ -61,6 +61,19 @@
             $job['round_id']);
 }
 
+function round_rating_update_handle($roundid) {
+    $round = round_get($roundid);
+    if ($round['rated'] == 'waiting-update') {
+        log_print("Update Rating for ".$roundid);
+        system(IA_ROOT_DIR.'scripts/update-ratings '.$roundid);
+        $round['rated'] = 'updated';
+        round_update($round);
+    } else if ($round['rated'] == 'waiting-reset') {
+        log_print("Clearing Ratings!");
+        rating_clear();
+    }
+}
+
 // Main loop. It works by polling the sql server
 // every IA_judge_POLL_INTERVAL
 function judge_main_loop() {
@@ -87,6 +100,10 @@
             job_handle($job);
             continue;
         }
+        if ($roundid = round_get_rating_update()) {
+            round_rating_update_handle($roundid);
+            continue;
+        }
         milisleep(IA_JUDGE_POLL_INTERVAL);
     }
 }
Index: scripts/migrate-update-rating
===================================================================
--- scripts/migrate-update-rating	(revision 0)
+++ scripts/migrate-update-rating	(revision 0)
@@ -0,0 +1,10 @@
+#! /usr/bin/env php
+<?php
+require_once(dirname($argv[0]).'/utilities.php');
+db_connect();
+db_query("
+	ALTER TABLE `infoarena2`.`ia_round` ADD COLUMN`rated`
+	ENUM('not-updated','updated','waiting-update','waiting-reset')
+	NOT NULL DEFAULT 'not-updated';
+");
+?>

Property changes on: scripts/migrate-update-rating
___________________________________________________________________
Added: svn:executable
   + *

Index: www/controllers/rating.php
===================================================================
--- www/controllers/rating.php	(revision 0)
+++ www/controllers/rating.php	(revision 0)
@@ -0,0 +1,32 @@
+<?php
+
+require_once(IA_ROOT_DIR.'www/utilities.php');
+require_once(IA_ROOT_DIR.'common/db/round.php');
+require_once(IA_ROOT_DIR.'common/db/score.php');
+require_once(IA_ROOT_DIR.'common/round.php');
+require_once(IA_ROOT_DIR.'www/format/pager.php');
+
+function controller_rating_view() {
+    identity_require('round-rating-update', null);
+    if (request_is_post()) {
+        if (request('round')) {
+            foreach (rating_rounds() as $key => $round) {
+                if ($round['round_rated'] == 'not-updated') {
+                    round_update_rated(round_get($key), 'waiting-update');
+                }
+                if ($key == request('round')) {
+                    break;
+                }
+            }
+        } else if (request('cleanup')) {
+            foreach (rating_rounds() as $key => $round) {
+                round_update_rated(round_get($key), 'waiting-reset');
+                break;
+            }
+        }
+    }
+    $view['title'] = 'Actualizare rating-uri';
+    execute_view_die('views/rating.php', $view);
+}
+
+?>
Index: www/format/form.php
===================================================================
--- www/format/form.php	(revision 1075)
+++ www/format/form.php	(working copy)
@@ -99,7 +99,7 @@
     } else if ($type == 'bool' || $type == 'enum' || $type == 'set') {
         // All these are handled as a select.
         // Set uses a smart selctor with two lists.
-        
+
         if ($type == 'bool') {
             // Convert bools to enums.
             $values = array(
@@ -245,4 +245,24 @@
     return format_tag('input', null, $args);
 }
 
+// Format rating update button
+function format_rating_update_button() {
+    $args = array(
+                'type' => 'submit',
+                'value' => 'Actualizeaza Rating',
+                'class' => 'button important'
+            );
+    return format_tag('input', null, $args);
+}
+
+// Format rating cleanup button
+function format_rating_cleanup_button() {
+    $args = array(
+                'type' => 'submit',
+                'value' => 'Reseteaza Rating',
+                'class' => 'button important'
+            );
+    return format_tag('input', null, $args);
+}
+
 ?>
Index: www/index.php
===================================================================
--- www/index.php	(revision 1075)
+++ www/index.php	(working copy)
@@ -102,7 +102,7 @@
     controller_round_details($obj_id);
 }
 
-// Round registration 
+// Round registration
 else if ($urlstart == 'inregistrare-runda') {
     $obj_id = implode("/", array_slice($pagepath, 1));
     require_once(IA_ROOT_DIR.'www/controllers/round_register.php');
@@ -140,6 +140,12 @@
     controller_blog_view($page, request('revision'));
 }
 
+// Calculate ratings
+else if ($page == 'admin/rating') {
+    require_once(IA_ROOT_DIR.'www/controllers/rating.php');
+    controller_rating_view();
+}
+
 // textblock controllers
 // FIXME: quick array of sorts?
 //  - edit textblock
Index: www/url.php
===================================================================
--- www/url.php	(revision 1075)
+++ www/url.php	(working copy)
@@ -346,4 +346,8 @@
             'preview' => 'body'));
 }
 
+function url_rating_update() {
+    return url_complex('admin/rating', array());
+}
+
 ?>
Index: www/views/rating.php
===================================================================
--- www/views/rating.php	(revision 0)
+++ www/views/rating.php	(revision 0)
@@ -0,0 +1,91 @@
+<?php
+
+require_once(IA_ROOT_DIR.'www/format/table.php');
+require_once(IA_ROOT_DIR.'www/format/form.php');
+require_once(IA_ROOT_DIR.'www/format/format.php');
+require_once(IA_ROOT_DIR.'common/db/round.php');
+require_once(IA_ROOT_DIR.'common/db/score.php');
+
+include('header.php');
+
+$column_infos = array(
+        array('title' => 'ID Runda',
+                'key' => 'id'),
+
+        array('title' => 'Titlu',
+                'key' => 'round_title'),
+
+        array('title' => 'Data Rundei',
+                'key' => 'timestamp'),
+
+        array('title' => 'Stare rating',
+                'key' => 'round_rated'),
+
+        array('title' => 'Actualizeaza',
+                'key' => 'update_button'),
+);
+
+$rounds = array();
+foreach (rating_rounds() as $key => $round) {
+    $round['timestamp'] = db_date_format($round['timestamp']);
+    $rounds[] = array_merge(array('id' => $key), $round);
+}
+
+$cleanup = false;
+foreach ($rounds as $key => $round) {
+    if ($round['round_rated'] == 'waiting-reset') {
+        $cleanup = true;
+    }
+
+    if ($round['round_rated'] == 'not-updated' && !$cleanup) {
+        $content = format_rating_update_button() .
+                   format_tag('input', null,
+                           array('type' => 'hidden',
+                                'name' => 'round',
+                                'value' => $round['id']),
+                           false);
+
+        $attribs = array(
+                            'method' => 'post',
+                            'action' => url_rating_update()
+                        );
+        $rounds[$key]['update_button'] = format_tag('form', $content, $attribs, false);
+    } else {
+        $rounds[$key]['update_button'] = 'Indisponibil';
+    }
+}
+
+foreach ($rounds as $key => $round) {
+    switch ($round['round_rated']) {
+        case 'not-updated': $rounds[$key]['round_rated'] = 'Neactualizat'; break;
+        case 'updated': if (!$cleanup) {
+                    $rounds[$key]['round_rated'] = 'Actualizat';
+                } else {
+                    $rounds[$key]['round_rated'] = 'Se sterge';
+                }
+                break;
+        case 'waiting-update': if (!$cleanup) {
+                    $rounds[$key]['round_rated'] = 'In asteptare';
+                } else {
+                    $rounds[$key]['round_rated'] = 'Se sterge';
+                }
+                break;
+        case 'waiting-reset': $rounds[$key]['round_rated'] = 'Se sterge'; break;
+    }
+}
+
+echo format_tag('form', format_rating_cleanup_button() .
+     format_tag('input', null, array('type' => 'hidden',
+                                     'name' => 'cleanup',
+                                     'value' => '1'), false),
+     array('method' => 'post', 'action' => url_rating_update()), false);
+echo format_table($rounds, $column_infos);
+echo format_tag('form', format_rating_cleanup_button() .
+     format_tag('input', null, array('type' => 'hidden',
+                                     'name' => 'cleanup',
+                                     'value' => '1'), false),
+     array('method' => 'post', 'action' => url_rating_update()), false);
+
+include('footer.php');
+
+?>
