diff --git a/checkin_notes b/checkin_notes index 13e7497ff6..745d2cd914 100644 --- a/checkin_notes +++ b/checkin_notes @@ -11781,3 +11781,18 @@ Rom 28 Nov 2007 win_build/installerv2/redist/Windows/x64/ boinccas.dll boinccas95.dll + +David 288 2007 + - Bolt development + + db/ + bolt_schema.sql + html/ + inc/ + bolt.inc + bolt_db.inc + ops/ + bolt_setup_sample.php + user/ + bolt.php + bolt_sched.php diff --git a/db/bolt_schema.sql b/db/bolt_schema.sql index 6b4433b43f..1650e230aa 100644 --- a/db/bolt_schema.sql +++ b/db/bolt_schema.sql @@ -1,3 +1,11 @@ +create table bolt_user ( + user_id integer not null, + birth_year integer not null, + sex smallint not null, + attrs text not null, + primary key (user_id) +); + create table bolt_course ( id integer not null auto_increment, create_time integer not null, @@ -12,6 +20,9 @@ create table bolt_enrollment ( create_time integer not null, user_id integer not null, course_id integer not null, + last_view integer not null, + fraction_done double not null, + mastery double not null, state text not null ); diff --git a/doc/boinc_news.php b/doc/boinc_news.php index ad7bda4cf4..c1ce5dd6dc 100644 --- a/doc/boinc_news.php +++ b/doc/boinc_news.php @@ -2,6 +2,12 @@ $project_news = array( +array("November 28, 2007", + "Live in Washington DC? Get together with other BOINC users via + Meetup + (or create a Meetup + in your own city)." +), array("November 16, 2007", "Leiden Classical allows students (and the public) to submit particle-system simulation jobs, diff --git a/html/inc/bolt.inc b/html/inc/bolt.inc index d120970981..bc89c0a80b 100644 --- a/html/inc/bolt.inc +++ b/html/inc/bolt.inc @@ -26,7 +26,9 @@ class BoltFrame { abstract class BoltUnit { public $name; // logical name. - abstract function walk($old_stack, &$new_stack, $next, &$item); + abstract function walk( + $old_stack, &$new_stack, $next, &$item, &$frac_done + ); // multi-purpose function for traversing a course. // if $old_stack is null // set up initial state for this unit. @@ -40,6 +42,7 @@ abstract class BoltUnit { // Append frames to $new_stack for this unit and descendants // if $next, the bottom-level non-item unit should increment. // return value: true if the caller should increment + // frac_done: Fraction done (of this unit and any subunits) abstract function is_item(); } @@ -59,9 +62,9 @@ class BoltIter { // get current item // - function at() { + function at(&$frac_done) { $new_stack = array(); - $this->top->walk($this->stack, $new_stack, false, $item); + $this->top->walk($this->stack, $new_stack, false, $item, $frac_done); $this->stack = $new_stack; return $item; } @@ -69,10 +72,10 @@ class BoltIter { // move to the next item (and return it) // return true if we're off the end // - function next() { + function next(&$frac_done) { $item = null; $new_stack = array(); - $this->top->walk($this->stack, $new_stack, true, $item); + $this->top->walk($this->stack, $new_stack, true, $item, $frac_done); $this->stack = $new_stack; return $item; } @@ -85,8 +88,9 @@ class BoltSeq extends BoltUnit { $this->units = $u; } - function walk($old_stack, &$new_stack, $next, &$item) { + function walk($old_stack, &$new_stack, $next, &$item, &$frac_done) { //echo "call to walk() for $this->name: next: $next\n"; + $n = count($this->units); if ($old_stack) { //echo "old stack: \n"; //var_dump($old_stack); @@ -94,39 +98,52 @@ class BoltSeq extends BoltUnit { $frame = $old_stack[0]; $state = $frame->state; $i = $state->i; - $restart = false; - if ($i >= count($this->units)) { - echo "index too large - restarting\n"; - $restart = true; + + // first, look up unit by name + // + $child = null; + for ($j=0; $j<$n; $j++) { + $c = $this->units[$j]; + if ($c->name == $state->child_name) { + $child = $c; + break; + } } - $child = $this->units[$i]; - if ($state->child_name != $child->name) { - echo "bad name - restarting\n"; - $restart = true; + // if not there, look up by index + // + if (!$child) { + if ($i >= $n) { + // and if index is too big, use last unit + // + $i = $n-1; + } + $child = $this->units[$i]; } - if (!$restart) { - if ($next) { - $inc = false; - if ($child->is_item()) { - $inc = true; - } else { - array_shift($old_stack); - $inc = $child->walk($old_stack, $new_stack, true, &$item); - } - if ($inc) { - $i++; - if ($i == count($this->units)) { - return true; - } + + // at this point, $child is the right unit + // + if ($next) { + $inc = false; + if ($child->is_item()) { + $inc = true; + } else { + array_shift($old_stack); + $inc = $child->walk( + $old_stack, $new_stack, true, $item, $frac_done + ); + } + if ($inc) { + $i++; + if ($i == $n) { + $frac_done = 1; + return true; } } } } else { - $restart = true; - } - if ($restart) { $i = 0; } + $frac_done = $i/$n; $child = $this->units[$i]; $state->i = $i; $state->child_name = $child->name; @@ -135,7 +152,8 @@ class BoltSeq extends BoltUnit { if ($child->is_item()) { $item = $child; } else { - $child->walk(null, $new_stack, false, $item); + $child->walk(null, $new_stack, false, $item, $f); + $frac_done += $f*(1/$n); } } function is_item() { @@ -158,7 +176,7 @@ class BoltItem extends BoltUnit { function is_item() { return true; } - function walk($old_stack, &$new_stack, $next, &$item) { + function walk($old_stack, &$new_stack, $next, &$item, &$frac_done) { echo "SHOULDN'T BE HERE\n"; } } @@ -182,4 +200,50 @@ function enum_course($course) { echo "course over\n"; } +function info_incomplete($user) { + if (!$user->bolt->birth_year) return true; + if (!$user->bolt->sex) return true; + return false; +} + +function birth_year_select($user) { + $this_year = date("Y"); + $x = "\n"; + return $x; +} + +function sex_select($user) { + $x = "\n"; + return $x; +} + +function request_info($user, $course) { + page_head("Student info"); + echo "
+ + id> + "; + start_table(); + row2("Birth year", birth_year_select($user)); + row2("Sex", sex_select($user)); + row2("", ""); + end_table(); + echo "
\n"; + page_tail(); +} + ?> diff --git a/html/inc/bolt_db.inc b/html/inc/bolt_db.inc index 83b7c3896b..1064359bdf 100644 --- a/html/inc/bolt_db.inc +++ b/html/inc/bolt_db.inc @@ -4,9 +4,22 @@ require_once("../inc/db_conn.inc"); require_once("../inc/util.inc"); class BoltDb extends DbConn { - public static $instance; + static $instance; static function get() { + if (web_stopped()) { + if ($generating_xml) { + xml_error(-183); + } else { + page_head("Page not available"); + echo "This page requires database access. + Our database server is temporarily shut down for maintenance. + Please try again later. + "; + page_tail(); + } + exit(); + } if (!isset($instance)) { $config = get_config(); $user = parse_config($config, ''); @@ -24,22 +37,47 @@ class BoltDb extends DbConn { } } -class BoltCourse { - function insert() { - $db = BoltDb::get(); - $now = time(); - $query = "insert into DBNAME.bolt_course (create_time, short_name, name, description, doc_file) values ($now, '$this->short_name', '$this->name', '$this->description', '$this->doc_file')"; - $result = $db->do_query($query); - if (!$result) return false; - $this->id = $db->insert_id(); - return true; +class BoltUser { + static $cache; + static function lookup_userid($id) { + $db = BoincDb::get(); + return $db->lookup('bolt_user', 'BoltUser', "user_id=$id"); } + static function insert($clause) { + $db = BoltDb::get(); + return $db->insert('bolt_user', $clause); + } + static function lookup(&$user) { + if (!$user) return; + if (isset($user->bolt)) return; + if (isset(self::$cache[$user->id])) { + $bolt = self::$cache[$user->id]; + } else { + $bolt = self::lookup_userid($user->id); + if (!$bolt) { + self::insert("(user_id) values ($user->id)"); + $bolt = self::lookup_userid($user->id); + } + self::$cache[$user->id] = $bolt; + } + $user->bolt = $bolt; + } + function update($clause) { + $db = BoltDb::get(); + $clause = "$clause where user_id=$this->user_id"; + return $db->update_aux('bolt_user', $clause); + } +} +class BoltCourse { + static function insert($clause) { + $db = BoltDb::get(); + return $db->insert('bolt_course', $clause); + } static function lookup_id($id) { $db = BoltDb::get(); return $db->lookup_id($id, 'bolt_course', 'BoltCourse'); } - static function enum() { $db = BoltDb::get(); return $db->enum('bolt_course', 'BoltCourse'); @@ -47,31 +85,26 @@ class BoltCourse { } class BoltEnrollment { - function insert() { + function insert($clause) { $db = BoltDb::get(); - $now = time(); - $query = "insert into DBNAME.bolt_enrollment (create_time, user_id, course_id) values ($now, $this->user_id, $this->course_id)"; - return $db->do_query($query); + return $db->insert('bolt_enrollment', $clause); } - function lookup($userid, $courseid) { + function lookup($user_id, $course_id) { $db = BoltDb::get(); - return $db->lookup('bolt_enrollment', 'BoltEnrollment', "user_id=$userid and course_id=$courseid"); + return $db->lookup('bolt_enrollment', 'BoltEnrollment', "user_id=$user_id and course_id=$course_id"); } - function update_aux($clause) { + function update($clause) { $db = BoltDb::get(); - $db->update_aux('bolt_enrollment', $clause); + $db->update_aux('bolt_enrollment', "$clause where user_id=$this->user_id and course_id=$this->course_id"); } } class BoltView { - function insert() { + static function insert($clause) { $db = BoltDb::get(); - $now = time(); - $query = "insert into DBNAME.bolt_view (user_id, course_id, item_name, start_time) values ($this->user_id, $this->course_id, '$this->item_name', $now)"; - $result = $db->do_query($query); - if (!$result) return false; - $this->id = $db->insert_id(); - return true; + $ret = $db->insert('bolt_view', $clause); + if (!$ret) return null; + return $db->insert_id(); } static function lookup_id($id) { $db = BoltDb::get(); diff --git a/html/ops/bolt_setup_sample.php b/html/ops/bolt_setup_sample.php index 08081108b3..a3310ab2be 100644 --- a/html/ops/bolt_setup_sample.php +++ b/html/ops/bolt_setup_sample.php @@ -2,13 +2,13 @@ require_once("../inc/bolt_db.inc"); -$c = new BoltCourse(); -$c->short_name = 'test_course'; -$c->name = 'A test course'; -$c->description = 'This course is a demonstration of Bolt'; -$c->doc_file = 'bolt_course_sample.php'; +$short_name = 'test_course'; +$name = 'Test course'; +$description = 'This course is a demonstration of Bolt'; +$doc_file = 'bolt_course_sample.php'; +$now = time(); -if ($c->insert()) { +if (BoltCourse::insert("(create_time, short_name, name, description, doc_file) values ($now, '$short_name', '$name', '$description', '$doc_file')")) { echo "all done\n"; } else { echo "database error\n"; diff --git a/html/user/bolt.php b/html/user/bolt.php index d01c7c01c8..ba76697666 100644 --- a/html/user/bolt.php +++ b/html/user/bolt.php @@ -8,18 +8,27 @@ page_head("Courses"); $user = get_logged_in_user(true); $courses = BoltCourse::enum(); +start_table(); +table_header( + "Course
Click to start, resume, or review + ", "Status" +); foreach ($courses as $course) { - $e = BoltEnrollment::lookup($user->id, $course->id); - echo "$course->name id&action=start>start - "; + $e = $user?BoltEnrollment::lookup($user->id, $course->id):null; + $start = date_str($e->create_time); + $ago = time_diff(time() - $e->last_view); if ($e) { - echo "id>resume - "; + $pct = number_format($e->fraction_done*100, 0); + $status = "Started $start; last visit $ago ago; $pct% done"; + } else { + $status = "Not started"; } - echo " -
$course->description - "; + row2("id&action=start>$course->name +
$course->description", + $status + ); } +end_table(); page_tail(); ?> diff --git a/html/user/bolt_sched.php b/html/user/bolt_sched.php index cbf4749825..a9c5dea748 100644 --- a/html/user/bolt_sched.php +++ b/html/user/bolt_sched.php @@ -1,9 +1,10 @@ bolt->update("sex=$sex, birth_year=$birth_year"); + $action = ""; +} + +if ($action == 'start' && info_incomplete($user)) { + request_info($user, $course); + exit(); +} + $course_doc = require_once($course->doc_file); if ($view_id) { @@ -32,20 +46,20 @@ if ($view_id) { } } +$frac_done = 0; $e = BoltEnrollment::lookup($user->id, $course_id); - if ($e) { $iter = new BoltIter($course_doc); $iter->stack = json_decode($e->state); if ($action == 'next') { - $item = $iter->next(); + $item = $iter->next($frac_done); $state = json_encode($iter->stack); - $e->update_aux("state='$state' where user_id=$user->id and course_id=$course_id"); + $e->update("state='$state'"); } else if ($action == 'start') { $iter->stack = null; - $item = $iter->at(); + $item = $iter->at($frac_done); $state = json_encode($iter->stack); - $e->update_aux("state='$state' where user_id=$user->id and course_id=$course_id"); + $e->update("state='$state'"); } else { $item = $iter->at(); } @@ -53,11 +67,10 @@ if ($e) { $iter = new BoltIter($course_doc); $item = $iter->at(); - $e = new BoltEnrollment($course); - $e->user_id = $user->id; - $e->course_id = $course_id; - $e->state = json_encode($iter->stack); - $e->insert(); + $now = time(); + $state = json_encode($iter->stack); + BoltEnrollment::insert("(create_time, user_id, course_id, state) values ($now, $user->id, $course_id, '$state')"); + $e = BoltEnrollment::lookup($user->id, $course_id); } if (!$item) { @@ -67,13 +80,13 @@ if (!$item) { exit(); } -$view = new BoltView(); -$view->user_id = $user->id; -$view->course_id = $course_id; -$view->item_name = $item->name; -$view->insert(); +$now = time(); +$e->update("last_view=$now, fraction_done=$frac_done"); +$view_id = BoltView::insert("(user_id, course_id, item_name, start_time) values ($user->id, $course_id, '$item->name', $now)"); require_once($item->filename); -echo "

id>Next"; +echo "

Next"; + +echo "

Fraction done: $frac_done"; ?>