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 "
\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";
?>