mirror of https://github.com/BOINC/boinc.git
- Initial checkin for Bolt
svn path=/trunk/boinc/; revision=13998
This commit is contained in:
parent
105d6aaae3
commit
26138742c6
|
@ -10182,3 +10182,22 @@ David 30 Oct 2007
|
|||
forum_thread.php
|
||||
account_finish_action.php
|
||||
account_finish.php
|
||||
|
||||
David 30 Oct 2007
|
||||
- initial checkin for Bolt
|
||||
|
||||
db/
|
||||
bolt_constraints.sql
|
||||
bolt_db.sql
|
||||
html/
|
||||
inc/
|
||||
bolt.inc
|
||||
bolt_db.inc
|
||||
bolt_ex.inc
|
||||
bossa_db.inc
|
||||
ops/
|
||||
bolt_setup_sample.php
|
||||
user/
|
||||
bolt.php
|
||||
bolt_course_sample.php
|
||||
bolt_sched.php
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
alter table bolt_course
|
||||
add unique(name);
|
||||
|
||||
alter table bolt_enrollment
|
||||
add unique(user_id, course_id);
|
||||
|
||||
alter table bolt_view
|
||||
add index bv_cs(course_id, start_time);
|
|
@ -0,0 +1,26 @@
|
|||
create table bolt_course (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
short_name varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
description text not null,
|
||||
doc_file varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table bolt_enrollment (
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
state text not null
|
||||
);
|
||||
|
||||
create table bolt_view (
|
||||
id integer not null auto_increment,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
item_name varchar(255) not null,
|
||||
start_time integer not null,
|
||||
end_time integer not null,
|
||||
primary key (id)
|
||||
);
|
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
// rules about course structures:
|
||||
//
|
||||
// - Each unit has a logical name.
|
||||
// - The members of a set must have distinct logical names
|
||||
// - Different units may have the same logical name;
|
||||
// however, such units should be identical.
|
||||
|
||||
class BoltFrame {
|
||||
public $state;
|
||||
// a data structure that's specific to the unit type,
|
||||
// e.g. a loop counter
|
||||
// Typically this includes the logical name of the current child.
|
||||
// Normally this is implied by the state;
|
||||
// however, it may differ if the course structure has changed.
|
||||
// In general the unit should restart in this case
|
||||
function __construct($state=null) {
|
||||
$this->state = $state;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BoltUnit {
|
||||
public $name; // logical name.
|
||||
|
||||
abstract function walk($old_stack, &$new_stack, $next, &$item);
|
||||
// multi-purpose function for traversing a course.
|
||||
// if $old_stack is null
|
||||
// set up initial state for this unit.
|
||||
// append frames to $new_stack for this unit and descendants
|
||||
// $next is ignored
|
||||
// $item is the initial item
|
||||
// return is ignored
|
||||
// else
|
||||
// The first frame of $old_stack is for this unit.
|
||||
// Check for name mismatch (if changed course).
|
||||
// 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
|
||||
abstract function is_item();
|
||||
}
|
||||
|
||||
// An iterator represents a user's position in a course.
|
||||
// It is stored in the database, and the course may change underneath it.
|
||||
//
|
||||
class BoltIter {
|
||||
public $stack; // array of BoltFrame
|
||||
public $top;
|
||||
|
||||
// point to the start of a course; set up stack.
|
||||
//
|
||||
function __construct($top) {
|
||||
$this->top = $top;
|
||||
$this->stack = null;
|
||||
}
|
||||
|
||||
// get current item
|
||||
//
|
||||
function at() {
|
||||
$new_stack = array();
|
||||
$this->top->walk($this->stack, $new_stack, false, $item);
|
||||
$this->stack = $new_stack;
|
||||
return $item;
|
||||
}
|
||||
|
||||
// move to the next item (and return it)
|
||||
// return true if we're off the end
|
||||
//
|
||||
function next() {
|
||||
$item = null;
|
||||
$new_stack = array();
|
||||
$this->top->walk($this->stack, $new_stack, true, $item);
|
||||
$this->stack = $new_stack;
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
class BoltSeq extends BoltUnit {
|
||||
public $units;
|
||||
function __construct($n, $u) {
|
||||
$this->name = $n;
|
||||
$this->units = $u;
|
||||
}
|
||||
|
||||
function walk($old_stack, &$new_stack, $next, &$item) {
|
||||
//echo "call to walk() for $this->name: next: $next\n";
|
||||
if ($old_stack) {
|
||||
//echo "old stack: \n";
|
||||
//var_dump($old_stack);
|
||||
//echo "------------\n";
|
||||
$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;
|
||||
}
|
||||
$child = $this->units[$i];
|
||||
if ($state->child_name != $child->name) {
|
||||
echo "bad name - restarting\n";
|
||||
$restart = true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$restart = true;
|
||||
}
|
||||
if ($restart) {
|
||||
$i = 0;
|
||||
}
|
||||
$child = $this->units[$i];
|
||||
$state->i = $i;
|
||||
$state->child_name = $child->name;
|
||||
$frame = new BoltFrame($state);
|
||||
$new_stack[] = $frame;
|
||||
if ($child->is_item()) {
|
||||
$item = $child;
|
||||
} else {
|
||||
$child->walk(null, $new_stack, false, $item);
|
||||
}
|
||||
}
|
||||
function is_item() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class BoltItem extends BoltUnit {
|
||||
public $filename;
|
||||
function __construct($name, $filename) {
|
||||
$this->filename = $filename;
|
||||
$this->name = $name;
|
||||
}
|
||||
function begin() {
|
||||
return array(new BoltFrame($this));
|
||||
}
|
||||
function unit_list() {
|
||||
return array(&$this);
|
||||
}
|
||||
function is_item() {
|
||||
return true;
|
||||
}
|
||||
function walk($old_stack, &$new_stack, $next, &$item) {
|
||||
echo "SHOULDN'T BE HERE\n";
|
||||
}
|
||||
}
|
||||
|
||||
class BoltLesson extends BoltItem {
|
||||
}
|
||||
|
||||
class BoltExercise extends BoltItem {
|
||||
}
|
||||
|
||||
function enum_course($course) {
|
||||
$iter = new BoltIter($course);
|
||||
while (1) {
|
||||
$x = $iter->at();
|
||||
if (!$x) break;
|
||||
echo "at: $x->url\n";
|
||||
$x = $iter->next();
|
||||
if (!$x) break;
|
||||
echo "next: $x->filename\n";
|
||||
}
|
||||
echo "course over\n";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/db_conn.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
class BoltDb extends DbConn {
|
||||
public static $instance;
|
||||
|
||||
static function get() {
|
||||
if (!isset($instance)) {
|
||||
$config = get_config();
|
||||
$user = parse_config($config, '<bolt_db_user>');
|
||||
$passwd = parse_config($config, '<bolt_db_passwd>');
|
||||
$host = parse_config($config, '<bolt_db_host>');
|
||||
$name = parse_config($config, '<bolt_db_name>');
|
||||
if ($host == null) {
|
||||
$host = "localhost";
|
||||
}
|
||||
$instance = new DbConn();
|
||||
$retval = $instance->init_conn($user, $passwd, $host, $name);
|
||||
if (!$retval) return null;
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
class BoltEnrollment {
|
||||
function insert() {
|
||||
$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);
|
||||
}
|
||||
function lookup($userid, $courseid) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup('bolt_enrollment', 'BoltEnrollment', "user_id=$userid and course_id=$courseid");
|
||||
}
|
||||
function update_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->update_aux('bolt_enrollment', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltView {
|
||||
function insert() {
|
||||
$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;
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_view', 'BoltView');
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->update($this, 'bolt_view', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
function bolt_exclusive_choice($choices) {
|
||||
foreach ($choices as $choice) {
|
||||
echo "<br><input name=q type=radio> $choice";
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1,17 +1,23 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/db_conn.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
class BossaDb extends DbConn {
|
||||
public static $instance;
|
||||
|
||||
static function get() {
|
||||
if (!isset($instance)) {
|
||||
$config = get_config();
|
||||
$user = parse_config($config, '<bossa_db_user>');
|
||||
$passwd = parse_config($config, '<bossa_db_passwd>');
|
||||
$host = parse_config($config, '<bossa_db_host>');
|
||||
$name = parse_config($config, '<bossa_db_name>');
|
||||
if ($host == null) {
|
||||
$host = "localhost";
|
||||
}
|
||||
$instance = new DbConn();
|
||||
$retval = $instance->init_conn(
|
||||
"<bossa_db_user>", "<bossa_db_passwd>",
|
||||
"<bossa_db_host>", "<bossa_db_name>"
|
||||
);
|
||||
$retval = $instance->init_conn($user, $passwd, $host, $name);
|
||||
if (!$retval) return null;
|
||||
}
|
||||
return $instance;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
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';
|
||||
|
||||
if ($c->insert()) {
|
||||
echo "all done\n";
|
||||
} else {
|
||||
echo "database error\n";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/bolt_db.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
page_head("Courses");
|
||||
|
||||
$user = get_logged_in_user(true);
|
||||
|
||||
$courses = BoltCourse::enum();
|
||||
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>
|
||||
";
|
||||
if ($e) {
|
||||
echo "<a href=bolt_sched.php?course_id=$course->id>resume</a>
|
||||
";
|
||||
}
|
||||
echo "
|
||||
<dd>$course->description
|
||||
";
|
||||
}
|
||||
page_tail();
|
||||
|
||||
?>
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
return new BoltSeq(
|
||||
'course',
|
||||
array(
|
||||
new BoltLesson('lesson 1', 'bolt_sample_lesson1.php'),
|
||||
new BoltLesson('lesson 2', 'bolt_sample_lesson2.php'),
|
||||
new BoltExercise('exercise 1', 'bolt_sample_exercise1.php'),
|
||||
new BoltSeq(
|
||||
'inner seq',
|
||||
array(
|
||||
new BoltLesson('lesson 3', 'bolt_sample_lesson3.php')
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
// Bolt scheduler. POST args:
|
||||
// course_id: course ID
|
||||
// action:
|
||||
// 'show' or none: show current (or first) item
|
||||
// 'next': go to next lesson
|
||||
// answers:
|
||||
// JSON represenation of exercise answers
|
||||
|
||||
require_once("../inc/bolt.inc");
|
||||
require_once("../inc/bolt_db.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
$user = get_logged_in_user();
|
||||
$course_id = get_int('course_id');
|
||||
$view_id = get_int('view_id', true);
|
||||
$action = get_str('action', true);
|
||||
|
||||
$course = BoltCourse::lookup_id($course_id);
|
||||
if (!$course) {
|
||||
error_page("no such course");
|
||||
}
|
||||
|
||||
$course_doc = require_once($course->doc_file);
|
||||
|
||||
if ($view_id) {
|
||||
$view = BoltView::lookup_id($view_id);
|
||||
if ($view && $view->user_id == $user->id && !$view->end_time) {
|
||||
$now = time();
|
||||
$view->update("end_time=$now");
|
||||
}
|
||||
}
|
||||
|
||||
$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();
|
||||
$state = json_encode($iter->stack);
|
||||
$e->update_aux("state='$state' where user_id=$user->id and course_id=$course_id");
|
||||
} else if ($action == 'start') {
|
||||
$iter->stack = null;
|
||||
$item = $iter->at();
|
||||
$state = json_encode($iter->stack);
|
||||
$e->update_aux("state='$state' where user_id=$user->id and course_id=$course_id");
|
||||
} else {
|
||||
$item = $iter->at();
|
||||
}
|
||||
} else {
|
||||
$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();
|
||||
}
|
||||
|
||||
if (!$item) {
|
||||
page_head("Done with course");
|
||||
echo "All done!";
|
||||
page_tail();
|
||||
exit();
|
||||
}
|
||||
|
||||
$view = new BoltView();
|
||||
$view->user_id = $user->id;
|
||||
$view->course_id = $course_id;
|
||||
$view->item_name = $item->name;
|
||||
$view->insert();
|
||||
|
||||
require_once($item->filename);
|
||||
|
||||
echo "<p><a href=bolt_sched.php?course_id=$course_id&action=next&view_id=$view->id>Next</a>";
|
||||
?>
|
Loading…
Reference in New Issue