mirror of https://github.com/BOINC/boinc.git
parent
6caccb258b
commit
562d7ac2d7
|
@ -271,3 +271,20 @@ David Oct 30 2008
|
|||
user/
|
||||
bolt.css
|
||||
bolt_sched.php
|
||||
|
||||
David Oct 30 2008
|
||||
- moved snapshot code to its own file
|
||||
- added link to questions in Map
|
||||
- added "mode" to question table
|
||||
|
||||
db/
|
||||
bolt_schema.sql
|
||||
html/
|
||||
inc/
|
||||
bolt_snap.inc
|
||||
bolt_util.inc
|
||||
ops/
|
||||
bolt_map.php
|
||||
bolt_compare.php
|
||||
user/
|
||||
bolt_sched.php
|
||||
|
|
|
@ -145,6 +145,8 @@ create table bolt_question (
|
|||
course_id integer not null,
|
||||
name varchar(255) not null,
|
||||
-- logical name of item where question was asked
|
||||
mode integer not null,
|
||||
-- distinguishes exercise show/answer
|
||||
question text not null,
|
||||
state integer not null,
|
||||
-- whether question has been handled
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
<?php
|
||||
|
||||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// BOINC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
////// stuff related to snapshots
|
||||
//
|
||||
// There are 2 kinds of snapshots: "compare" and "map".
|
||||
//
|
||||
// A "compare snapshot" is a condensed representation of the results
|
||||
// for a particular select/xset pair.
|
||||
// Namely, it's an array whose elements contain
|
||||
// bolt_user: the user
|
||||
// xset_result: the user's first completion of the xset
|
||||
// select_finished: the user's last completion of the select before this
|
||||
//
|
||||
// A "map snapshot" is:
|
||||
// - an assoc array "views" mapping unit name to a list of views
|
||||
// - an assoc array "results" mapping unit name to a list of results
|
||||
// - an assoc array "xset_results" mapping unit name to a list of xset results
|
||||
// - an assoc array "questions" mapping unit name to a list of questions
|
||||
// - an assoc array "users" mapping user ID to user record
|
||||
//
|
||||
|
||||
|
||||
function compare_snapshot_filename($course_id, $select_name, $xset_name) {
|
||||
@mkdir("../bolt_snap");
|
||||
$x = urlencode($course_id."_".$select_name."_".$xset_name);
|
||||
return "../bolt_snap/compare_snapshot_$x";
|
||||
}
|
||||
|
||||
function write_compare_snapshot($course_id, $select_name, $xset_name, $dur) {
|
||||
$now = time();
|
||||
$start = $now - $dur*86400;
|
||||
$xrs = BoltXsetResult::enum(
|
||||
"course_id=$course_id and name='$xset_name' and create_time >= $start"
|
||||
);
|
||||
$sfs = BoltSelectFinished::enum(
|
||||
"course_id=$course_id and name='$select_name' and end_time >= $start"
|
||||
);
|
||||
|
||||
// make an array $a, keyed by user ID, of earliest xset result
|
||||
//
|
||||
$a = array();
|
||||
foreach ($xrs as $xr) {
|
||||
$uid = $xr->user_id;
|
||||
if (!array_key_exists($uid, $a) || $xr->create_time < $a[$uid]->xr->create_time) {
|
||||
$x = null;
|
||||
$x->xr = $xr;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
// now scan select finishes, and for each user find last one before xset
|
||||
//
|
||||
foreach ($sfs as $sf) {
|
||||
$uid = $sf->user_id;
|
||||
if (!array_key_exists($uid, $a)) {
|
||||
echo "no xset result";
|
||||
continue;
|
||||
}
|
||||
$x = $a[$uid];
|
||||
$xr = $x->xr;
|
||||
if ($sf->end_time > $xr->create_time) {
|
||||
//echo "select finish is too late";
|
||||
continue;
|
||||
}
|
||||
if (!isset($x->sf) || $sf->end_time > $x->sf->end_time) {
|
||||
$x->sf = $sf;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
// cull array elements for which we didn't find a select finish.
|
||||
// Look up user records for other elements.
|
||||
//
|
||||
foreach ($a as $uid=>$x) {
|
||||
if (!isset($x->sf)) {
|
||||
unset($a[$uid]);
|
||||
} else {
|
||||
$user = BoincUser::lookup_id($uid);
|
||||
BoltUser::lookup($user);
|
||||
$x->user = $user;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
$filename = compare_snapshot_filename($course_id, $select_name, $xset_name);
|
||||
$f = fopen($filename, "w");
|
||||
|
||||
$s = null;
|
||||
$s->recs = $a;
|
||||
$s->dur = $dur;
|
||||
$s->time = $now;
|
||||
fwrite($f, serialize($s));
|
||||
fclose($f);
|
||||
return $s;
|
||||
}
|
||||
|
||||
function read_compare_snapshot($course_id, $select_name, $xset_name) {
|
||||
$filename = compare_snapshot_filename($course_id, $select_name, $xset_name);
|
||||
$f = @fopen($filename, "r");
|
||||
if (!$f) return null;
|
||||
$x = fread($f, filesize($filename));
|
||||
fclose($f);
|
||||
return unserialize($x);
|
||||
}
|
||||
|
||||
|
||||
function map_snapshot_filename($course_id) {
|
||||
return "../bolt_snap/map_snapshot_".$course_id;
|
||||
}
|
||||
|
||||
function write_map_snapshot($course_id, $dur) {
|
||||
$now = time();
|
||||
$start = $now - $dur*86400;
|
||||
|
||||
$views = array();
|
||||
$results = array();
|
||||
$xset_results = array();
|
||||
$users = array();
|
||||
$questions = array();
|
||||
|
||||
$vs = BoltView::enum("course_id=$course_id and start_time>$start");
|
||||
foreach ($vs as $v) {
|
||||
if (array_key_exists($v->item_name, $views)) {
|
||||
$x = $views[$v->item_name];
|
||||
$x[] = $v;
|
||||
$views[$v->item_name] = $x;
|
||||
} else {
|
||||
$views[$v->item_name] = array($v);
|
||||
}
|
||||
if (!array_key_exists($v->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($v->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$v->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$rs = BoltResult::enum("course_id=$course_id and create_time>$start");
|
||||
foreach ($rs as $r) {
|
||||
if (array_key_exists($r->item_name, $results)) {
|
||||
$x = $results[$r->item_name];
|
||||
$x[] = $r;
|
||||
$results[$r->item_name] = $x;
|
||||
} else {
|
||||
$results[$r->item_name] = array($r);
|
||||
}
|
||||
if (!array_key_exists($r->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($r->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$r->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$xrs = BoltXsetResult::enum("course_id=$course_id and create_time>$start");
|
||||
foreach ($xrs as $xr) {
|
||||
if (array_key_exists($xr->name, $xset_results)) {
|
||||
$x = $xset_results[$xr->name];
|
||||
$x[] = $xr;
|
||||
$xset_results[$xr->name] = $x;
|
||||
} else {
|
||||
$xset_results[$xr->name] = array($xr);
|
||||
}
|
||||
if (!array_key_exists($xr->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($xr->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$xr->user_id] = $user;
|
||||
}
|
||||
}
|
||||
$qs = BoltQuestion::enum("course_id=$course_id and create_time>$start");
|
||||
foreach ($qs as $q) {
|
||||
if (array_key_exists($q->name, $questions)) {
|
||||
$x = $questions[$q->name];
|
||||
$x[] = $q;
|
||||
$questions[$q->name] = $x;
|
||||
} else {
|
||||
$questions[$q->name] = array($q);
|
||||
}
|
||||
if (!array_key_exists($q->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($q->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$q->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$y = null;
|
||||
$y->views = $views;
|
||||
$y->results = $results;
|
||||
$y->xset_results = $xset_results;
|
||||
$y->users = $users;
|
||||
$y->questions = $questions;
|
||||
$y->dur = $dur;
|
||||
$y->time = $now;
|
||||
|
||||
$filename = map_snapshot_filename($course_id);
|
||||
$f = fopen($filename, "w");
|
||||
fwrite($f, serialize($y));
|
||||
fclose($f);
|
||||
|
||||
return $y;
|
||||
}
|
||||
|
||||
function read_map_snapshot($course_id) {
|
||||
$filename = map_snapshot_filename($course_id);
|
||||
$f = @fopen($filename, "r");
|
||||
if (!$f) return null;
|
||||
$x = fread($f, filesize($filename));
|
||||
fclose($f);
|
||||
return unserialize($x);
|
||||
}
|
||||
|
||||
?>
|
|
@ -126,191 +126,6 @@ function request_info($user, $course) {
|
|||
page_tail();
|
||||
}
|
||||
|
||||
////// stuff related to snapshots
|
||||
|
||||
function compare_snapshot_filename($course_id, $select_name, $xset_name) {
|
||||
@mkdir("../bolt_snap");
|
||||
$x = urlencode($course_id."_".$select_name."_".$xset_name);
|
||||
return "../bolt_snap/compare_snapshot_$x";
|
||||
}
|
||||
|
||||
// a "snapshot" is a condensed representation of the results
|
||||
// for a particular select/xset pair.
|
||||
// Namely, it's an array whose elements contain
|
||||
// bolt_user: the user
|
||||
// xset_result: the user's first completion of the xset
|
||||
// select_finished: the user's last completion of the select before this
|
||||
|
||||
function write_compare_snapshot($course_id, $select_name, $xset_name, $dur) {
|
||||
$now = time();
|
||||
$start = $now - $dur*86400;
|
||||
$xrs = BoltXsetResult::enum(
|
||||
"course_id=$course_id and name='$xset_name' and create_time >= $start"
|
||||
);
|
||||
$sfs = BoltSelectFinished::enum(
|
||||
"course_id=$course_id and name='$select_name' and end_time >= $start"
|
||||
);
|
||||
|
||||
// make an array $a, keyed by user ID, of earliest xset result
|
||||
//
|
||||
$a = array();
|
||||
foreach ($xrs as $xr) {
|
||||
$uid = $xr->user_id;
|
||||
if (!array_key_exists($uid, $a) || $xr->create_time < $a[$uid]->xr->create_time) {
|
||||
$x = null;
|
||||
$x->xr = $xr;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
// now scan select finishes, and for each user find last one before xset
|
||||
//
|
||||
foreach ($sfs as $sf) {
|
||||
$uid = $sf->user_id;
|
||||
if (!array_key_exists($uid, $a)) {
|
||||
echo "no xset result";
|
||||
continue;
|
||||
}
|
||||
$x = $a[$uid];
|
||||
$xr = $x->xr;
|
||||
if ($sf->end_time > $xr->create_time) {
|
||||
//echo "select finish is too late";
|
||||
continue;
|
||||
}
|
||||
if (!isset($x->sf) || $sf->end_time > $x->sf->end_time) {
|
||||
$x->sf = $sf;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
// cull array elements for which we didn't find a select finish.
|
||||
// Look up user records for other elements.
|
||||
//
|
||||
foreach ($a as $uid=>$x) {
|
||||
if (!isset($x->sf)) {
|
||||
unset($a[$uid]);
|
||||
} else {
|
||||
$user = BoincUser::lookup_id($uid);
|
||||
BoltUser::lookup($user);
|
||||
$x->user = $user;
|
||||
$a[$uid] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
$filename = compare_snapshot_filename($course_id, $select_name, $xset_name);
|
||||
$f = fopen($filename, "w");
|
||||
|
||||
$s = null;
|
||||
$s->recs = $a;
|
||||
$s->dur = $dur;
|
||||
$s->time = $now;
|
||||
fwrite($f, serialize($s));
|
||||
fclose($f);
|
||||
return $s;
|
||||
}
|
||||
|
||||
function read_compare_snapshot($course_id, $select_name, $xset_name) {
|
||||
$filename = compare_snapshot_filename($course_id, $select_name, $xset_name);
|
||||
$f = @fopen($filename, "r");
|
||||
if (!$f) return null;
|
||||
$x = fread($f, filesize($filename));
|
||||
fclose($f);
|
||||
return unserialize($x);
|
||||
}
|
||||
|
||||
|
||||
function map_snapshot_filename($course_id) {
|
||||
return "../bolt_snap/map_snapshot_".$course_id;
|
||||
}
|
||||
|
||||
// a "map snapshot" is:
|
||||
// - an assoc array "views" mapping unit name to a list of views
|
||||
// - an assoc array "results" mapping unit name to a list of results
|
||||
// - an assoc array "xset_results" mapping unit name to a list of xset results
|
||||
// - an assoc array "users" mapping user ID to user record
|
||||
//
|
||||
function write_map_snapshot($course_id, $dur) {
|
||||
$now = time();
|
||||
$start = $now - $dur*86400;
|
||||
|
||||
$views = array();
|
||||
$results = array();
|
||||
$xset_results = array();
|
||||
$users = array();
|
||||
|
||||
$vs = BoltView::enum("course_id=$course_id and start_time>$start");
|
||||
foreach ($vs as $v) {
|
||||
if (array_key_exists($v->item_name, $views)) {
|
||||
$x = $views[$v->item_name];
|
||||
$x[] = $v;
|
||||
$views[$v->item_name] = $x;
|
||||
} else {
|
||||
$views[$v->item_name] = array($v);
|
||||
}
|
||||
if (!array_key_exists($v->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($v->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$v->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$rs = BoltResult::enum("course_id=$course_id and create_time>$start");
|
||||
foreach ($rs as $r) {
|
||||
if (array_key_exists($r->item_name, $results)) {
|
||||
$x = $results[$r->item_name];
|
||||
$x[] = $r;
|
||||
$results[$r->item_name] = $x;
|
||||
} else {
|
||||
$results[$r->item_name] = array($r);
|
||||
}
|
||||
if (!array_key_exists($r->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($r->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$r->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$xrs = BoltXsetResult::enum("course_id=$course_id and create_time>$start");
|
||||
foreach ($xrs as $xr) {
|
||||
if (array_key_exists($xr->name, $xset_results)) {
|
||||
$x = $xset_results[$xr->name];
|
||||
$x[] = $xr;
|
||||
$xset_results[$xr->name] = $x;
|
||||
} else {
|
||||
$xset_results[$xr->name] = array($xr);
|
||||
}
|
||||
if (!array_key_exists($xr->user_id, $users)) {
|
||||
$user = BoincUser::lookup_id($xr->user_id);
|
||||
BoltUser::lookup($user);
|
||||
$users[$xr->user_id] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$y = null;
|
||||
$y->views = $views;
|
||||
$y->results = $results;
|
||||
$y->xset_results = $xset_results;
|
||||
$y->users = $users;
|
||||
$y->dur = $dur;
|
||||
$y->time = $now;
|
||||
|
||||
$filename = map_snapshot_filename($course_id);
|
||||
$f = fopen($filename, "w");
|
||||
fwrite($f, serialize($y));
|
||||
fclose($f);
|
||||
|
||||
return $y;
|
||||
}
|
||||
|
||||
function read_map_snapshot($course_id) {
|
||||
$filename = map_snapshot_filename($course_id);
|
||||
$f = @fopen($filename, "r");
|
||||
if (!$f) return null;
|
||||
$x = fread($f, filesize($filename));
|
||||
fclose($f);
|
||||
return unserialize($x);
|
||||
}
|
||||
|
||||
////// Statistics
|
||||
|
||||
// compute the mean and stdev of an array
|
||||
|
|
|
@ -33,6 +33,7 @@ require_once("../inc/bolt_db.inc");
|
|||
require_once("../inc/bolt_util.inc");
|
||||
require_once("../inc/bolt.inc");
|
||||
require_once("../inc/bolt_cat.inc");
|
||||
require_once("../inc/bolt_snap.inc");
|
||||
|
||||
function compare_case(
|
||||
$title, $select_unit, $snap, $filter, $filter_cat, $breakdown, $breakdown_cat
|
||||
|
|
|
@ -49,6 +49,7 @@ require_once("../inc/bolt_db.inc");
|
|||
require_once("../inc/bolt_cat.inc");
|
||||
require_once("../inc/bolt_util.inc");
|
||||
require_once("../inc/bolt.inc");
|
||||
require_once("../inc/bolt_snap.inc");
|
||||
|
||||
// the following are to minimize argument passing
|
||||
|
||||
|
@ -108,7 +109,8 @@ function spaces($level) {
|
|||
return $x;
|
||||
}
|
||||
|
||||
// used to filter arrays of views or xset_results
|
||||
// filter arrays of anything that has a user_id field
|
||||
// (view, xset_result, question)
|
||||
//
|
||||
function filter_array($array) {
|
||||
global $snap, $filter, $filter_cat, $breakdown, $breakdown_cat;
|
||||
|
@ -171,6 +173,20 @@ function outcomes($views) {
|
|||
return $x;
|
||||
}
|
||||
|
||||
function get_nquestions($unit, $mode) {
|
||||
global $snap;
|
||||
|
||||
if (array_key_exists($unit->name, $snap->questions)) {
|
||||
$a = filter_array($snap->questions[$unit->name]);
|
||||
$n = 0;
|
||||
foreach ($a as $q) {
|
||||
if ($q->mode == $mode) $n++;
|
||||
}
|
||||
return $n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function get_views($unit, $mode) {
|
||||
global $snap;
|
||||
|
||||
|
@ -217,7 +233,7 @@ $rownum = 0;
|
|||
|
||||
function show_unit_row($unit, $class, $level, $is_answer) {
|
||||
global $breakdown, $breakdown_cat;
|
||||
global $rownum;
|
||||
global $rownum, $course_id;
|
||||
|
||||
$a = $is_answer?" (answer)":"";
|
||||
$j = ($rownum++)%2;
|
||||
|
@ -243,21 +259,36 @@ function show_unit_row($unit, $class, $level, $is_answer) {
|
|||
}
|
||||
switch ($class) {
|
||||
case "BoltLesson":
|
||||
$views = get_views($unit, BOLT_MODE_LESSON);
|
||||
$mode = BOLT_MODE_LESSON;
|
||||
$views = get_views($unit, $mode);
|
||||
$n = count($views);
|
||||
$out = outcomes($views);
|
||||
$t = avg_time($views);
|
||||
echo "<td>$n</td>";
|
||||
$n = get_nquestions($unit, $mode);
|
||||
if ($n) {
|
||||
echo "<td><a href=bolt_map.php?action=questions&course_id=$course_id&name=$unit->name&mode=$mode>$n</a></td>\n";
|
||||
} else {
|
||||
echo "<td>0</td>\n";
|
||||
}
|
||||
|
||||
echo outcome_graph($out, 200);
|
||||
echo empty_cell();
|
||||
echo time_graph($t, 200);
|
||||
break;
|
||||
case "BoltExercise":
|
||||
$views = get_views($unit, $is_answer?BOLT_MODE_ANSWER:BOLT_MODE_SHOW);
|
||||
$mode = $is_answer?BOLT_MODE_ANSWER:BOLT_MODE_SHOW;
|
||||
$views = get_views($unit, $mode);
|
||||
$n = count($views);
|
||||
$out = outcomes($views);
|
||||
$t = avg_time($views);
|
||||
echo "<td>$n</td>";
|
||||
$n = get_nquestions($unit, $mode);
|
||||
if ($n) {
|
||||
echo "<td><a href=bolt_map.php?action=questions&course_id=$course_id&name=$unit->name&mode=$mode>$n</a></td>\n";
|
||||
} else {
|
||||
echo "<td>0</td>\n";
|
||||
}
|
||||
echo outcome_graph($out, 200);
|
||||
if ($is_answer) {
|
||||
echo empty_cell();
|
||||
|
@ -273,6 +304,7 @@ function show_unit_row($unit, $class, $level, $is_answer) {
|
|||
$n = count($xr);
|
||||
echo "<td>$n</td>";
|
||||
echo empty_cell();
|
||||
echo empty_cell();
|
||||
$score = avg_score($xr);
|
||||
echo score_graph($score, 200);
|
||||
echo empty_cell();
|
||||
|
@ -282,6 +314,7 @@ function show_unit_row($unit, $class, $level, $is_answer) {
|
|||
echo empty_cell();
|
||||
echo empty_cell();
|
||||
echo empty_cell();
|
||||
echo empty_cell();
|
||||
}
|
||||
echo "</tr>\n";
|
||||
}
|
||||
|
@ -369,6 +402,7 @@ function show_map() {
|
|||
}
|
||||
echo "
|
||||
<th>Views</th>
|
||||
<th>Questions</th>
|
||||
<th>Outcome<br>
|
||||
<span class=green>Next</span>
|
||||
<span class=yellow>Back</span>
|
||||
|
@ -398,6 +432,32 @@ function show_map() {
|
|||
page_tail();
|
||||
}
|
||||
|
||||
function show_questions() {
|
||||
$name = get_str('name');
|
||||
global $course_id;
|
||||
$snap = read_map_snapshot($course_id);
|
||||
$qs = $snap->questions[$name];
|
||||
page_head("Questions about $name");
|
||||
start_table();
|
||||
echo "<tr>
|
||||
<th>When</th>
|
||||
<th>Who</th>
|
||||
<th>Question</th>
|
||||
</tr>
|
||||
";
|
||||
foreach ($qs as $q) {
|
||||
$user = $snap->users[$q->user_id];
|
||||
echo "<tr>
|
||||
<td>".time_str($q->create_time)."</td>
|
||||
<td><a href=student>$user->name</td>
|
||||
<td>$q->question</td>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
end_table();
|
||||
page_tail();
|
||||
}
|
||||
|
||||
$course_id = get_int('course_id');
|
||||
$course = BoltCourse::lookup_id($course_id);
|
||||
if (!$course) error_page("no course");
|
||||
|
@ -414,6 +474,9 @@ case "snap_action":
|
|||
case "map":
|
||||
show_map();
|
||||
break;
|
||||
case "questions":
|
||||
show_questions();
|
||||
break;
|
||||
default:
|
||||
error_page("Unknown action $action");
|
||||
}
|
||||
|
|
|
@ -642,7 +642,7 @@ case 'question':
|
|||
debug_show_state(unserialize($view->state), "Initial");
|
||||
$now = time();
|
||||
$question = BoltDb::escape_string(get_str('question'));
|
||||
BoltQuestion::insert("(create_time, user_id, course_id, name, question, state) values ($now, $user->id, $course->id, '$view->item_name', '$question', 0)");
|
||||
BoltQuestion::insert("(create_time, user_id, course_id, name, mode, question, state) values ($now, $user->id, $course->id, '$view->item_name', $view->mode, '$question', 0)");
|
||||
page_header();
|
||||
echo "
|
||||
Thanks; we have recorded your question.
|
||||
|
|
Loading…
Reference in New Issue