svn path=/trunk/boinc/; revision=14319

This commit is contained in:
David Anderson 2007-11-29 02:56:10 +00:00
parent 2b3dec7557
commit 68ec6e6ce6
8 changed files with 242 additions and 91 deletions

View File

@ -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

View File

@ -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
);

View File

@ -2,6 +2,12 @@
$project_news = array(
array("November 28, 2007",
"Live in Washington DC? Get together with other BOINC users via
<a href=http://opensource.meetup.com/84/?gj=sj2>Meetup</a>
(or <a href=http://opensource.meetup.com/>create a Meetup
in your own city</a>)."
),
array("November 16, 2007",
"<a href=http://boinc.gorlaeus.net/>Leiden Classical</a> allows students (and the public)
to submit particle-system simulation jobs,

View File

@ -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 = "<select name=birth_year>\n";
for ($i=$this_year-100; $i<$this_year; $i++) {
$s = ($i == $user->bolt->birth_year)?"selected":"";
$x .= "<option value=$i $s>$i</option>\n";
}
$s = (!$user->bolt->birth_year)?"selected":"";
$x .= "<option value=$0 $s>Unspecified</option>\n";
$x .= "</select>\n";
return $x;
}
function sex_select($user) {
$x = "<select name=sex>\n";
$s = ($user->bolt->sex == 0)?"selected":"";
$x .= "<option value=0 $s>Unspecified</option>\n";
$s = ($user->bolt->sex == 1)?"selected":"";
$x .= "<option value=1 $s>Male</option>\n";
$s = ($user->bolt->sex == 2)?"selected":"";
$x .= "<option value=2 $s>Female</option>\n";
$x .= "</select>\n";
return $x;
}
function request_info($user, $course) {
page_head("Student info");
echo "<form action=bolt_sched.php>
<input type=hidden name=action value=update_info>
<input type=hidden name=course_id value=$course->id>
";
start_table();
row2("Birth year", birth_year_select($user));
row2("Sex", sex_select($user));
row2("", "<input type=submit value=OK>");
end_table();
echo "</form>\n";
page_tail();
}
?>

View File

@ -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, '<bolt_db_user>');
@ -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();

View File

@ -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";

View File

@ -8,18 +8,27 @@ page_head("Courses");
$user = get_logged_in_user(true);
$courses = BoltCourse::enum();
start_table();
table_header(
"Course<br><span class=note>Click to start, resume, or review</span>
", "Status"
);
foreach ($courses as $course) {
$e = BoltEnrollment::lookup($user->id, $course->id);
echo "$course->name <a href=bolt_sched.php?course_id=$course->id&action=start>start</a>
";
$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 "<a href=bolt_sched.php?course_id=$course->id>resume</a>
";
$pct = number_format($e->fraction_done*100, 0);
$status = "Started $start; last visit $ago ago; $pct% done";
} else {
$status = "Not started";
}
echo "
<dd>$course->description
";
row2("<a href=bolt_sched.php?course_id=$course->id&action=start>$course->name</a>
<br><span class=note>$course->description</span>",
$status
);
}
end_table();
page_tail();
?>

View File

@ -1,9 +1,10 @@
<?php
// Bolt scheduler. POST args:
// Bolt scheduler. GET args:
// course_id: course ID
// action:
// 'show' or none: show current (or first) item
// 'start' or none: show current (or first) item,
// and prompt for user info if any missing
// 'next': go to next lesson
// answers:
// JSON represenation of exercise answers
@ -13,6 +14,7 @@ require_once("../inc/bolt_db.inc");
require_once("../inc/util.inc");
$user = get_logged_in_user();
BoltUser::lookup($user);
$course_id = get_int('course_id');
$view_id = get_int('view_id', true);
$action = get_str('action', true);
@ -22,6 +24,18 @@ if (!$course) {
error_page("no such course");
}
if ($action == 'update_info') {
$sex = get_int('sex');
$birth_year = get_int('birth_year');
$user->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 "<p><a href=bolt_sched.php?course_id=$course_id&action=next&view_id=$view->id>Next</a>";
echo "<p><a href=bolt_sched.php?course_id=$course_id&action=next&view_id=$view_id>Next</a>";
echo "<p>Fraction done: $frac_done";
?>