version 1.61, 2003/03/25 22:29:31
|
version 1.107, 2003/10/27 21:07:22
|
Line 104 sub get_sequence_assessment_data {
|
Line 104 sub get_sequence_assessment_data {
|
my $fn=$ENV{'request.course.fn'}; |
my $fn=$ENV{'request.course.fn'}; |
## |
## |
## use navmaps |
## use navmaps |
my $navmap = Apache::lonnavmaps::navmap->new(Apache->request,$fn.".db", |
my $navmap = Apache::lonnavmaps::navmap->new(); |
$fn."_parms.db",1,0); |
|
if (!defined($navmap)) { |
if (!defined($navmap)) { |
return 'Can not open Coursemap'; |
return 'Can not open Coursemap'; |
} |
} |
|
# We explicity grab the top level map because I am not sure we |
|
# are pulling it from the iterator. |
|
my $top_level_map = $navmap->getById('0.0'); |
|
# |
my $iterator = $navmap->getIterator(undef, undef, undef, 1); |
my $iterator = $navmap->getIterator(undef, undef, undef, 1); |
my $curRes = $iterator->next(); # Top level sequence |
my $curRes = $iterator->next(); # Top level sequence |
## |
## |
Line 118 sub get_sequence_assessment_data {
|
Line 121 sub get_sequence_assessment_data {
|
## resources. This means we have to start out with something to look |
## resources. This means we have to start out with something to look |
## at. |
## at. |
my $title = $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; |
my $title = $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; |
my $symb = 'top'; |
my $symb = $top_level_map->symb(); |
my $src = 'not applicable'; |
my $src = $top_level_map->src(); |
|
my $randompick = $top_level_map->randompick(); |
# |
# |
my @Sequences; |
my @Sequences; |
my @Assessments; |
my @Assessments; |
Line 130 sub get_sequence_assessment_data {
|
Line 134 sub get_sequence_assessment_data {
|
type => 'container', |
type => 'container', |
num_assess => 0, |
num_assess => 0, |
num_assess_parts => 0, |
num_assess_parts => 0, |
contents => [], }; |
contents => [], |
|
randompick => $randompick, |
|
}; |
push (@Sequences,$top); |
push (@Sequences,$top); |
push (@Nested_Sequences, $top); |
push (@Nested_Sequences, $top); |
# |
# |
# We need to keep track of which sequences contain homework problems |
# We need to keep track of which sequences contain homework problems |
# |
# |
|
my $previous_too; |
my $previous; |
my $previous; |
$curRes = $iterator->next(); # BEGIN_MAP |
|
$curRes = $iterator->next(); # The first item in the top level map. |
|
while (scalar(@Nested_Sequences)) { |
while (scalar(@Nested_Sequences)) { |
|
$previous_too = $previous; |
$previous = $curRes; |
$previous = $curRes; |
$curRes = $iterator->next(); |
$curRes = $iterator->next(); |
my $currentmap = $Nested_Sequences[-1]; # Last one on the stack |
my $currentmap = $Nested_Sequences[-1]; # Last one on the stack |
if ($curRes == $iterator->BEGIN_MAP()) { |
if ($curRes == $iterator->BEGIN_MAP()) { |
|
if (! ref($previous)) { |
|
$previous = $previous_too; |
|
} |
|
if (! ref($previous)) { |
|
next; |
|
} |
# get the map itself, instead of BEGIN_MAP |
# get the map itself, instead of BEGIN_MAP |
$title = $previous->title(); |
$title = $previous->title(); |
|
$title =~ s/\:/\&\#058;/g; |
$symb = $previous->symb(); |
$symb = $previous->symb(); |
$src = $previous->src(); |
$src = $previous->src(); |
|
# pick up the filename if there is no title available |
|
if (! defined($title) || $title eq '') { |
|
($title) = ($src=~/\/([^\/]*)$/); |
|
} |
|
$randompick = $previous->randompick(); |
my $newmap = { title => $title, |
my $newmap = { title => $title, |
src => $src, |
src => $src, |
symb => $symb, |
symb => $symb, |
type => 'container', |
type => 'container', |
num_assess => 0, |
num_assess => 0, |
|
randompick => $randompick, |
contents => [], |
contents => [], |
}; |
}; |
push (@{$currentmap->{'contents'}},$newmap); # this is permanent |
push (@{$currentmap->{'contents'}},$newmap); # this is permanent |
Line 168 sub get_sequence_assessment_data {
|
Line 187 sub get_sequence_assessment_data {
|
next if (! $curRes->is_problem());# && !$curRes->randomout); |
next if (! $curRes->is_problem());# && !$curRes->randomout); |
# Okay, from here on out we only deal with assessments |
# Okay, from here on out we only deal with assessments |
$title = $curRes->title(); |
$title = $curRes->title(); |
|
$title =~ s/\:/\&\#058;/g; |
$symb = $curRes->symb(); |
$symb = $curRes->symb(); |
$src = $curRes->src(); |
$src = $curRes->src(); |
my $parts = $curRes->parts(); |
my $parts = $curRes->parts(); |
|
my %partdata; |
|
foreach my $part (@$parts) { |
|
my @Responses = $curRes->responseType($part); |
|
my @Ids = $curRes->responseIds($part); |
|
$partdata{$part}->{'ResponseTypes'}= \@Responses; |
|
$partdata{$part}->{'ResponseIds'} = \@Ids; |
|
# Count how many responses of each type there are in this part |
|
foreach (@Responses) { |
|
$partdata{$part}->{$_}++; |
|
} |
|
} |
my $assessment = { title => $title, |
my $assessment = { title => $title, |
src => $src, |
src => $src, |
symb => $symb, |
symb => $symb, |
type => 'assessment', |
type => 'assessment', |
parts => $parts, |
parts => $parts, |
num_parts => scalar(@$parts), |
num_parts => scalar(@$parts), |
|
partdata => \%partdata, |
}; |
}; |
push(@Assessments,$assessment); |
push(@Assessments,$assessment); |
push(@{$currentmap->{'contents'}},$assessment); |
push(@{$currentmap->{'contents'}},$assessment); |
Line 211 sub LoadDiscussion {
|
Line 243 sub LoadDiscussion {
|
return \%Discuss; |
return \%Discuss; |
} |
} |
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
|
=item &GetUserName(username,userdomain) |
|
|
|
Returns a hash with the following entries: |
|
'firstname', 'middlename', 'lastname', 'generation', and 'fullname' |
|
|
|
'fullname' is the result of &Apache::loncoursedata::ProcessFullName. |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub GetUserName { |
|
my ($username,$userdomain) = @_; |
|
$username = $ENV{'user.name'} if (! defined($username)); |
|
$userdomain = $ENV{'user.domain'} if (! defined($username)); |
|
my %userenv = &Apache::lonnet::get('environment', |
|
['firstname','middlename','lastname','generation'], |
|
$userdomain,$username); |
|
$userenv{'fullname'} = &ProcessFullName($userenv{'lastname'}, |
|
$userenv{'generation'}, |
|
$userenv{'firstname'}, |
|
$userenv{'middlename'}); |
|
return %userenv; |
|
} |
|
|
|
################################################ |
|
################################################ |
|
|
=pod |
=pod |
|
|
=item &ProcessFullName() |
=item &ProcessFullName() |
Line 221 is Lastname generation, firstname middle
|
Line 286 is Lastname generation, firstname middle
|
|
|
=cut |
=cut |
|
|
|
################################################ |
|
################################################ |
sub ProcessFullName { |
sub ProcessFullName { |
my ($lastname, $generation, $firstname, $middlename)=@_; |
my ($lastname, $generation, $firstname, $middlename)=@_; |
my $Str = ''; |
my $Str = ''; |
Line 308 interface in lonmysql.pm and I shudder a
|
Line 375 interface in lonmysql.pm and I shudder a
|
|
|
=over 4 |
=over 4 |
|
|
|
=item Tables used to store meta information |
|
|
|
The following tables hold data required to keep track of the current status |
|
of a students data in the tables or to look up the students data in the tables. |
|
|
|
=over 4 |
|
|
=item $symb_table |
=item $symb_table |
|
|
The symb_table has two columns. The first is a 'symb_id' and the second |
The symb_table has two columns. The first is a 'symb_id' and the second |
Line 333 internally to the MySQL database and is
|
Line 407 internally to the MySQL database and is
|
(stored in the students environment). This table has its PRIMARY KEY on the |
(stored in the students environment). This table has its PRIMARY KEY on the |
'student' (100 characters). |
'student' (100 characters). |
|
|
=item $updatetime_table |
=item $studentdata_table |
|
|
|
The studentdata_table has four columns: 'student_id' (the unique id of |
|
the student), 'updatetime' (the time the students data was last updated), |
|
'fullupdatetime' (the time the students full data was last updated), |
|
'section', and 'classification'( the students current classification). |
|
This table has its PRIMARY KEY on 'student_id'. |
|
|
The updatetime_table has two columns. The first is 'student' (100 characters, |
=back |
typically username:domain). The second is 'updatetime', which is an unsigned |
|
integer, NOT a MySQL date. This table has its PRIMARY KEY on 'student' (100 |
=item Tables used to store current status data |
characters). |
|
|
The following tables store data only about the students current status on |
|
a problem, meaning only the data related to the last attempt on a problem. |
|
|
|
=over 4 |
|
|
=item $performance_table |
=item $performance_table |
|
|
Line 362 limited to 255 characters. 'value' is l
|
Line 446 limited to 255 characters. 'value' is l
|
|
|
=back |
=back |
|
|
|
=item Tables used for storing historic data |
|
|
|
The following tables are used to store almost all of the transactions a student |
|
has made on a homework problem. See loncapa/docs/homework/datastorage for |
|
specific information about each of the parameters stored. |
|
|
|
=over 4 |
|
|
|
=item $fulldump_response_table |
|
|
|
The response table holds data (documented in loncapa/docs/homework/datastorage) |
|
associated with a particular response id which is stored when a student |
|
attempts a problem. The following are the columns of the table, in order: |
|
'symb_id','part_id','response_id','student_id','transaction','tries', |
|
'awarddetail', 'response_specific' (data particular to the response |
|
type), 'response_specific_value', and 'submission (the text of the students |
|
submission). The primary key is based on the first five columns listed above. |
|
|
|
=item $fulldump_part_table |
|
|
|
The part table holds data (documented in loncapa/docs/homework/datastorage) |
|
associated with a particular part id which is stored when a student attempts |
|
a problem. The following are the columns of the table, in order: |
|
'symb_id','part_id','student_id','transaction','tries','award','awarded', |
|
and 'previous'. The primary key is based on the first five columns listed |
|
above. |
|
|
|
=item $fulldump_timestamp_table |
|
|
|
The timestamp table holds the timestamps of the transactions which are |
|
stored in $fulldump_response_table and $fulldump_part_table. This data is |
|
about both the response and part data. Columns: 'symb_id','student_id', |
|
'transaction', and 'timestamp'. |
|
The primary key is based on the first 3 columns. |
|
|
|
=back |
|
|
|
=back |
|
|
=head3 Important Subroutines |
=head3 Important Subroutines |
|
|
Here is a brief overview of the subroutines which are likely to be of |
Here is a brief overview of the subroutines which are likely to be of |
Line 390 interest:
|
Line 513 interest:
|
|
|
################################################ |
################################################ |
################################################ |
################################################ |
{ |
{ # Begin scope of table identifiers |
|
|
my $current_course =''; |
my $current_course =''; |
my $symb_table; |
my $symb_table; |
my $part_table; |
my $part_table; |
my $student_table; |
my $student_table; |
my $updatetime_table; |
my $studentdata_table; |
my $performance_table; |
my $performance_table; |
my $parameters_table; |
my $parameters_table; |
|
my $fulldump_response_table; |
|
my $fulldump_part_table; |
|
my $fulldump_timestamp_table; |
|
|
|
my @Tables; |
################################################ |
################################################ |
################################################ |
################################################ |
|
|
Line 422 sub init_dbs {
|
Line 549 sub init_dbs {
|
my $courseid = shift; |
my $courseid = shift; |
&setup_table_names($courseid); |
&setup_table_names($courseid); |
# |
# |
|
# Drop any of the existing tables |
|
foreach my $table (@Tables) { |
|
&Apache::lonmysql::drop_table($table); |
|
} |
|
# |
# Note - changes to this table must be reflected in the code that |
# Note - changes to this table must be reflected in the code that |
# stores the data (calls &Apache::lonmysql::store_row with this table |
# stores the data (calls &Apache::lonmysql::store_row with this table |
# id |
# id |
Line 464 sub init_dbs {
|
Line 596 sub init_dbs {
|
{ name => 'student', |
{ name => 'student', |
type => 'VARCHAR(100)', |
type => 'VARCHAR(100)', |
restrictions => 'NOT NULL'}, |
restrictions => 'NOT NULL'}, |
|
{ name => 'classification', |
|
type => 'varchar(100)', }, |
], |
], |
'PRIMARY KEY' => ['student (100)'], |
'PRIMARY KEY' => ['student (100)'], |
'KEY' => [{ columns => ['student_id']},], |
'KEY' => [{ columns => ['student_id']},], |
}; |
}; |
# |
# |
my $updatetime_table_def = { |
my $studentdata_table_def = { |
id => $updatetime_table, |
id => $studentdata_table, |
permanent => 'no', |
permanent => 'no', |
columns => [{ name => 'student', |
columns => [{ name => 'student_id', |
type => 'VARCHAR(100)', |
type => 'MEDIUMINT UNSIGNED', |
restrictions => 'NOT NULL UNIQUE',}, |
restrictions => 'NOT NULL UNIQUE',}, |
{ name => 'updatetime', |
{ name => 'updatetime', |
type => 'INT UNSIGNED', |
type => 'INT UNSIGNED'}, |
restrictions => 'NOT NULL' }, |
{ name => 'fullupdatetime', |
|
type => 'INT UNSIGNED'}, |
|
{ name => 'section', |
|
type => 'VARCHAR(100)'}, |
|
{ name => 'classification', |
|
type => 'VARCHAR(100)', }, |
], |
], |
'PRIMARY KEY' => ['student (100)'], |
'PRIMARY KEY' => ['student_id'], |
}; |
}; |
# |
# |
my $performance_table_def = { |
my $performance_table_def = { |
Line 494 sub init_dbs {
|
Line 633 sub init_dbs {
|
{ name => 'part_id', |
{ name => 'part_id', |
type => 'MEDIUMINT UNSIGNED', |
type => 'MEDIUMINT UNSIGNED', |
restrictions => 'NOT NULL' }, |
restrictions => 'NOT NULL' }, |
|
{ name => 'part', |
|
type => 'VARCHAR(100)', |
|
restrictions => 'NOT NULL'}, |
{ name => 'solved', |
{ name => 'solved', |
type => 'TINYTEXT' }, |
type => 'TINYTEXT' }, |
{ name => 'tries', |
{ name => 'tries', |
Line 506 sub init_dbs {
|
Line 648 sub init_dbs {
|
type => 'TINYTEXT' }, |
type => 'TINYTEXT' }, |
{ name => 'timestamp', |
{ name => 'timestamp', |
type => 'INT UNSIGNED'}, |
type => 'INT UNSIGNED'}, |
{ name => 'weight', |
|
type => 'INT UNSIGNED'}, |
|
], |
], |
'PRIMARY KEY' => ['symb_id','student_id','part_id'], |
'PRIMARY KEY' => ['symb_id','student_id','part_id'], |
'KEY' => [{ columns=>['student_id'] }, |
'KEY' => [{ columns=>['student_id'] }, |
{ columns=>['symb_id'] },], |
{ columns=>['symb_id'] },], |
}; |
}; |
# |
# |
|
my $fulldump_part_table_def = { |
|
id => $fulldump_part_table, |
|
permanent => 'no', |
|
columns => [ |
|
{ name => 'symb_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'part_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'student_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'transaction', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'tries', |
|
type => 'SMALLINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'award', |
|
type => 'TINYTEXT' }, |
|
{ name => 'awarded', |
|
type => 'TINYTEXT' }, |
|
{ name => 'previous', |
|
type => 'SMALLINT UNSIGNED' }, |
|
# { name => 'regrader', |
|
# type => 'TINYTEXT' }, |
|
# { name => 'afterduedate', |
|
# type => 'TINYTEXT' }, |
|
], |
|
'PRIMARY KEY' => ['symb_id','part_id','student_id','transaction'], |
|
'KEY' => [ |
|
{ columns=>['symb_id'] }, |
|
{ columns=>['part_id'] }, |
|
{ columns=>['student_id'] }, |
|
], |
|
}; |
|
# |
|
my $fulldump_response_table_def = { |
|
id => $fulldump_response_table, |
|
permanent => 'no', |
|
columns => [ |
|
{ name => 'symb_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'part_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'response_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'student_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'transaction', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'awarddetail', |
|
type => 'TINYTEXT' }, |
|
# { name => 'message', |
|
# type => 'CHAR' }, |
|
{ name => 'response_specific', |
|
type => 'TINYTEXT' }, |
|
{ name => 'response_specific_value', |
|
type => 'TINYTEXT' }, |
|
{ name => 'submission', |
|
type => 'TEXT'}, |
|
], |
|
'PRIMARY KEY' => ['symb_id','part_id','response_id','student_id', |
|
'transaction'], |
|
'KEY' => [ |
|
{ columns=>['symb_id'] }, |
|
{ columns=>['part_id','response_id'] }, |
|
{ columns=>['student_id'] }, |
|
], |
|
}; |
|
my $fulldump_timestamp_table_def = { |
|
id => $fulldump_timestamp_table, |
|
permanent => 'no', |
|
columns => [ |
|
{ name => 'symb_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'student_id', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'transaction', |
|
type => 'MEDIUMINT UNSIGNED', |
|
restrictions => 'NOT NULL' }, |
|
{ name => 'timestamp', |
|
type => 'INT UNSIGNED'}, |
|
], |
|
'PRIMARY KEY' => ['symb_id','student_id','transaction'], |
|
'KEY' => [ |
|
{ columns=>['symb_id'] }, |
|
{ columns=>['student_id'] }, |
|
{ columns=>['transaction'] }, |
|
], |
|
}; |
|
|
|
# |
my $parameters_table_def = { |
my $parameters_table_def = { |
id => $parameters_table, |
id => $parameters_table, |
permanent => 'no', |
permanent => 'no', |
Line 555 sub init_dbs {
|
Line 796 sub init_dbs {
|
return 3; |
return 3; |
} |
} |
# |
# |
$tableid = &Apache::lonmysql::create_table($updatetime_table_def); |
$tableid = &Apache::lonmysql::create_table($studentdata_table_def); |
if (! defined($tableid)) { |
if (! defined($tableid)) { |
&Apache::lonnet::logthis("error creating updatetime_table: ". |
&Apache::lonnet::logthis("error creating studentdata_table: ". |
&Apache::lonmysql::get_error()); |
&Apache::lonmysql::get_error()); |
return 4; |
return 4; |
} |
} |
Line 575 sub init_dbs {
|
Line 816 sub init_dbs {
|
&Apache::lonmysql::get_error()); |
&Apache::lonmysql::get_error()); |
return 6; |
return 6; |
} |
} |
|
# |
|
$tableid = &Apache::lonmysql::create_table($fulldump_part_table_def); |
|
if (! defined($tableid)) { |
|
&Apache::lonnet::logthis("error creating fulldump_part_table: ". |
|
&Apache::lonmysql::get_error()); |
|
return 7; |
|
} |
|
# |
|
$tableid = &Apache::lonmysql::create_table($fulldump_response_table_def); |
|
if (! defined($tableid)) { |
|
&Apache::lonnet::logthis("error creating fulldump_response_table: ". |
|
&Apache::lonmysql::get_error()); |
|
return 8; |
|
} |
|
$tableid = &Apache::lonmysql::create_table($fulldump_timestamp_table_def); |
|
if (! defined($tableid)) { |
|
&Apache::lonnet::logthis("error creating fulldump_timestamp_table: ". |
|
&Apache::lonmysql::get_error()); |
|
return 9; |
|
} |
return 0; |
return 0; |
} |
} |
|
|
Line 583 sub init_dbs {
|
Line 844 sub init_dbs {
|
|
|
=pod |
=pod |
|
|
|
=item &delete_caches() |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub delete_caches { |
|
my $courseid = shift; |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
# |
|
&setup_table_names($courseid); |
|
# |
|
my $dbh = &Apache::lonmysql::get_dbh(); |
|
foreach my $table (@Tables) { |
|
my $command = 'DROP TABLE '.$table.';'; |
|
$dbh->do($command); |
|
if ($dbh->err) { |
|
&Apache::lonnet::logthis($command.' resulted in error: '.$dbh->errstr); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
=item &get_part_id() |
=item &get_part_id() |
|
|
Get the MySQL id of a problem part string. |
Get the MySQL id of a problem part string. |
Line 750 sub get_student_id {
|
Line 1039 sub get_student_id {
|
$have_read_student_table = 1; |
$have_read_student_table = 1; |
} |
} |
if (! exists($ids_by_student{$student})) { |
if (! exists($ids_by_student{$student})) { |
&Apache::lonmysql::store_row($student_table,[undef,$student]); |
&Apache::lonmysql::store_row($student_table, |
|
[undef,$student,undef]); |
undef(%ids_by_student); |
undef(%ids_by_student); |
my @Result = &Apache::lonmysql::get_rows($student_table); |
my @Result = &Apache::lonmysql::get_rows($student_table); |
foreach (@Result) { |
foreach (@Result) { |
Line 780 sub get_student {
|
Line 1070 sub get_student {
|
|
|
=pod |
=pod |
|
|
|
=item &clear_internal_caches() |
|
|
|
Causes the internal caches used in get_student_id, get_student, |
|
get_symb_id, get_symb, get_part_id, and get_part to be undef'd. |
|
|
|
Needs to be called before the first operation with the MySQL database |
|
for a given Apache request. |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub clear_internal_caches { |
|
$have_read_part_table = 0; |
|
undef(%ids_by_part); |
|
undef(%parts_by_id); |
|
$have_read_symb_table = 0; |
|
undef(%ids_by_symb); |
|
undef(%symbs_by_id); |
|
$have_read_student_table = 0; |
|
undef(%ids_by_student); |
|
undef(%students_by_id); |
|
} |
|
|
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
|
=item &update_full_student_data($sname,$sdom,$courseid) |
|
|
|
Does a lonnet::dump on a student to populate the courses tables. |
|
|
|
Input: $sname, $sdom, $courseid |
|
|
|
Output: $returnstatus |
|
|
|
$returnstatus is a string describing any errors that occured. 'okay' is the |
|
default. |
|
|
|
This subroutine loads a students data using lonnet::dump and inserts |
|
it into the MySQL database. The inserts are done on three tables, |
|
$fulldump_response_table, $fulldump_part_table, and $fulldump_timestamp_table. |
|
The INSERT calls are made directly by this subroutine, not through lonmysql |
|
because we do a 'bulk'insert which takes advantage of MySQLs non-SQL |
|
compliant INSERT command to insert multiple rows at a time. |
|
If anything has gone wrong during this process, $returnstatus is updated with |
|
a description of the error. |
|
|
|
Once the "fulldump" tables are updated, the tables used for chart and |
|
spreadsheet (which hold only the current state of the student on their |
|
homework, not historical data) are updated. If all updates have occured |
|
successfully, the studentdata table is updated to reflect the time of the |
|
update. |
|
|
|
Notice we do not insert the data and immediately query it. This means it |
|
is possible for there to be data returned this first time that is not |
|
available the second time. CYA. |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub update_full_student_data { |
|
my ($sname,$sdom,$courseid) = @_; |
|
# |
|
# Set up database names |
|
&setup_table_names($courseid); |
|
# |
|
my $student_id = &get_student_id($sname,$sdom); |
|
my $student = $sname.':'.$sdom; |
|
# |
|
my $returnstatus = 'okay'; |
|
# |
|
# Download students data |
|
my $time_of_retrieval = time; |
|
my @tmp = &Apache::lonnet::dump($courseid,$sdom,$sname); |
|
if (@tmp && $tmp[0] =~ /^error/) { |
|
$returnstatus = 'error retrieving full student data'; |
|
return $returnstatus; |
|
} elsif (! @tmp) { |
|
$returnstatus = 'okay: no student data'; |
|
return $returnstatus; |
|
} |
|
my %studentdata = @tmp; |
|
# |
|
# Get database handle and clean out the tables |
|
my $dbh = &Apache::lonmysql::get_dbh(); |
|
$dbh->do('DELETE FROM '.$fulldump_response_table.' WHERE student_id='. |
|
$student_id); |
|
$dbh->do('DELETE FROM '.$fulldump_part_table.' WHERE student_id='. |
|
$student_id); |
|
$dbh->do('DELETE FROM '.$fulldump_timestamp_table.' WHERE student_id='. |
|
$student_id); |
|
# |
|
# Parse and store the data into a form we can handle |
|
my $partdata; |
|
my $respdata; |
|
while (my ($key,$value) = each(%studentdata)) { |
|
next if ($key =~ /^(\d+):(resource$|subnum$|keys:)/); |
|
my ($transaction,$symb,$parameter) = split(':',$key); |
|
my $symb_id = &get_symb_id($symb); |
|
if ($parameter eq 'timestamp') { |
|
# We can deal with 'timestamp' right away |
|
my @timestamp_storage = ($symb_id,$student_id, |
|
$transaction,$value); |
|
my $store_command = 'INSERT IGNORE INTO '.$fulldump_timestamp_table. |
|
" VALUES ('".join("','",@timestamp_storage)."');"; |
|
$dbh->do($store_command); |
|
if ($dbh->err()) { |
|
&Apache::lonnet::logthis('unable to execute '.$store_command); |
|
&Apache::lonnet::logthis($dbh->errstr()); |
|
} |
|
next; |
|
} elsif ($parameter eq 'version') { |
|
next; |
|
} elsif ($parameter =~ /^resource\.(.*)\.(tries| |
|
award| |
|
awarded| |
|
previous| |
|
solved| |
|
awarddetail| |
|
submission| |
|
submissiongrading| |
|
molecule)\s*$/x){ |
|
# we do not have enough information to store an |
|
# entire row, so we save it up until later. |
|
my ($part_and_resp_id,$field) = ($1,$2); |
|
my ($part,$part_id,$resp,$resp_id); |
|
if ($part_and_resp_id =~ /\./) { |
|
($part,$resp) = split(/\./,$part_and_resp_id); |
|
$part_id = &get_part_id($part); |
|
$resp_id = &get_part_id($resp); |
|
} else { |
|
$part_id = &get_part_id($part_and_resp_id); |
|
} |
|
# Deal with part specific data |
|
if ($field =~ /^(tries|award|awarded|previous)$/) { |
|
$partdata->{$symb_id}->{$part_id}->{$transaction}->{$field}=$value; |
|
} |
|
# deal with response specific data |
|
if (defined($resp_id) && |
|
$field =~ /^(awarddetail| |
|
submission| |
|
submissiongrading| |
|
molecule)$/x) { |
|
if ($field eq 'submission') { |
|
# We have to be careful with user supplied input. |
|
# most of the time we are okay because it is escaped. |
|
# However, there is one wrinkle: submissions which end in |
|
# and odd number of '\' cause insert errors to occur. |
|
# Best trap this somehow... |
|
$value =~ s/\'/\\\'/g; |
|
my ($offensive_string) = ($value =~ /(\\+)$/); |
|
if (length($offensive_string) % 2) { |
|
$value =~ s/\\$/\\\\/; |
|
} |
|
} |
|
if ($field eq 'submissiongrading' || |
|
$field eq 'molecule') { |
|
$respdata->{$symb_id}->{$part_id}->{$resp_id}->{$transaction}->{'response_specific'}=$field; |
|
$respdata->{$symb_id}->{$part_id}->{$resp_id}->{$transaction}->{'response_specific_value'}=$value; |
|
} else { |
|
$respdata->{$symb_id}->{$part_id}->{$resp_id}->{$transaction}->{$field}=$value; |
|
} |
|
} |
|
} |
|
} |
|
## |
|
## Store the part data |
|
my $store_command = 'INSERT IGNORE INTO '.$fulldump_part_table. |
|
' VALUES '."\n"; |
|
my $store_rows = 0; |
|
while (my ($symb_id,$hash1) = each (%$partdata)) { |
|
while (my ($part_id,$hash2) = each (%$hash1)) { |
|
while (my ($transaction,$data) = each (%$hash2)) { |
|
$store_command .= "('".join("','",$symb_id,$part_id, |
|
$student_id, |
|
$transaction, |
|
$data->{'tries'}, |
|
$data->{'award'}, |
|
$data->{'awarded'}, |
|
$data->{'previous'})."'),"; |
|
$store_rows++; |
|
} |
|
} |
|
} |
|
if ($store_rows) { |
|
chop($store_command); |
|
$dbh->do($store_command); |
|
if ($dbh->err) { |
|
$returnstatus = 'error storing part data'; |
|
&Apache::lonnet::logthis('insert error '.$dbh->errstr()); |
|
&Apache::lonnet::logthis("While attempting\n".$store_command); |
|
} |
|
} |
|
## |
|
## Store the response data |
|
$store_command = 'INSERT IGNORE INTO '.$fulldump_response_table. |
|
' VALUES '."\n"; |
|
$store_rows = 0; |
|
while (my ($symb_id,$hash1) = each (%$respdata)) { |
|
while (my ($part_id,$hash2) = each (%$hash1)) { |
|
while (my ($resp_id,$hash3) = each (%$hash2)) { |
|
while (my ($transaction,$data) = each (%$hash3)) { |
|
$store_command .= "('".join("','",$symb_id,$part_id, |
|
$resp_id,$student_id, |
|
$transaction, |
|
$data->{'awarddetail'}, |
|
$data->{'response_specific'}, |
|
$data->{'response_specific_value'}, |
|
$data->{'submission'})."'),"; |
|
$store_rows++; |
|
} |
|
} |
|
} |
|
} |
|
if ($store_rows) { |
|
chop($store_command); |
|
$dbh->do($store_command); |
|
if ($dbh->err) { |
|
$returnstatus = 'error storing response data'; |
|
&Apache::lonnet::logthis('insert error '.$dbh->errstr()); |
|
&Apache::lonnet::logthis("While attempting\n".$store_command); |
|
} |
|
} |
|
## |
|
## Update the students "current" data in the performance |
|
## and parameters tables. |
|
my ($status,undef) = &store_student_data |
|
($sname,$sdom,$courseid, |
|
&Apache::lonnet::convert_dump_to_currentdump(\%studentdata)); |
|
if ($returnstatus eq 'okay' && $status ne 'okay') { |
|
$returnstatus = 'error storing current data:'.$status; |
|
} elsif ($status ne 'okay') { |
|
$returnstatus .= ' error storing current data:'.$status; |
|
} |
|
## |
|
## Update the students time...... |
|
if ($returnstatus eq 'okay') { |
|
&Apache::lonmysql::replace_row |
|
($studentdata_table, |
|
[$student_id,$time_of_retrieval,$time_of_retrieval,undef,undef]); |
|
} |
|
return $returnstatus; |
|
} |
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
=item &update_student_data() |
=item &update_student_data() |
|
|
Input: $sname, $sdom, $courseid |
Input: $sname, $sdom, $courseid |
Line 828 sub update_student_data {
|
Line 1371 sub update_student_data {
|
$sname.':'.$sdom.' in course '.$courseid. |
$sname.':'.$sdom.' in course '.$courseid. |
':'.$tmp[0]); |
':'.$tmp[0]); |
$returnstatus = 'error getting data'; |
$returnstatus = 'error getting data'; |
return $returnstatus; |
return ($returnstatus,undef); |
} |
} |
if (scalar(@tmp) < 1) { |
if (scalar(@tmp) < 1) { |
return ('no data',undef); |
return ('no data',undef); |
} |
} |
my %student_data = @tmp; |
my %student_data = @tmp; |
|
my @Results = &store_student_data($sname,$sdom,$courseid,\%student_data); |
|
# |
|
# Set the students update time |
|
if ($Results[0] eq 'okay') { |
|
&Apache::lonmysql::replace_row($studentdata_table, |
|
[$student_id,$time_of_retrieval,undef,undef,undef]); |
|
} |
|
# |
|
return @Results; |
|
} |
|
|
|
sub store_student_data { |
|
my ($sname,$sdom,$courseid,$student_data) = @_; |
|
# |
|
my $student_id = &get_student_id($sname,$sdom); |
|
my $student = $sname.':'.$sdom; |
|
# |
|
my $returnstatus = 'okay'; |
# |
# |
# Remove all of the students data from the table |
# Remove all of the students data from the table |
my $dbh = &Apache::lonmysql::get_dbh(); |
my $dbh = &Apache::lonmysql::get_dbh(); |
Line 847 sub update_student_data {
|
Line 1408 sub update_student_data {
|
my $starttime = Time::HiRes::time; |
my $starttime = Time::HiRes::time; |
my $elapsed = 0; |
my $elapsed = 0; |
my $rows_stored; |
my $rows_stored; |
my $store_parameters_command = 'INSERT INTO '.$parameters_table. |
my $store_parameters_command = 'INSERT IGNORE INTO '.$parameters_table. |
' VALUES '."\n"; |
' VALUES '."\n"; |
my $num_parameters = 0; |
my $num_parameters = 0; |
my $store_performance_command = 'INSERT INTO '.$performance_table. |
my $store_performance_command = 'INSERT IGNORE INTO '.$performance_table. |
' VALUES '."\n"; |
' VALUES '."\n"; |
return 'error' if (! defined($dbh)); |
return ('error',undef) if (! defined($dbh)); |
while (my ($current_symb,$param_hash) = each(%student_data)) { |
while (my ($current_symb,$param_hash) = each(%{$student_data})) { |
# |
# |
# make sure the symb is set up properly |
# make sure the symb is set up properly |
my $symb_id = &get_symb_id($current_symb); |
my $symb_id = &get_symb_id($current_symb); |
# |
# |
# Load data into the tables |
# Load data into the tables |
foreach my $parameter (keys(%$param_hash)) { |
while (my ($parameter,$value) = each(%$param_hash)) { |
my $value = $param_hash->{$parameter}; |
|
my $newstring; |
my $newstring; |
if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous|weight))/) { |
if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) { |
$newstring = "('".join("','", |
$newstring = "('".join("','", |
$symb_id,$student_id, |
$symb_id,$student_id, |
$parameter,$value)."'),\n"; |
$parameter)."',". |
|
$dbh->quote($value)."),\n"; |
$num_parameters ++; |
$num_parameters ++; |
if ($newstring !~ /''/) { |
if ($newstring !~ /''/) { |
$store_parameters_command .= $newstring; |
$store_parameters_command .= $newstring; |
Line 883 sub update_student_data {
|
Line 1444 sub update_student_data {
|
my $award = $param_hash->{'resource.'.$part.'.award'}; |
my $award = $param_hash->{'resource.'.$part.'.award'}; |
my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'}; |
my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'}; |
my $timestamp = $param_hash->{'timestamp'}; |
my $timestamp = $param_hash->{'timestamp'}; |
# use EXT to get the weight |
|
my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight', |
|
$current_symb,$sdom,$sname); |
|
# Give the weight back to the user |
|
$param_hash->{'resource.'.$part.'.weight'}=$weight; |
|
# |
# |
$solved = '' if (! defined($awarded)); |
$solved = '' if (! defined($solved)); |
$tries = '' if (! defined($tries)); |
$tries = '' if (! defined($tries)); |
$awarded = '' if (! defined($awarded)); |
$awarded = '' if (! defined($awarded)); |
$award = '' if (! defined($award)); |
$award = '' if (! defined($award)); |
$awarddetail = '' if (! defined($awarddetail)); |
$awarddetail = '' if (! defined($awarddetail)); |
$newstring = "('".join("','",$symb_id,$student_id,$part_id, |
$newstring = "('".join("','",$symb_id,$student_id,$part_id,$part, |
$solved,$tries,$awarded,$award, |
$solved,$tries,$awarded,$award, |
$awarddetail,$timestamp,$weight)."'),\n"; |
$awarddetail,$timestamp)."'),\n"; |
$store_performance_command .= $newstring; |
$store_performance_command .= $newstring; |
$rows_stored++; |
$rows_stored++; |
} |
} |
Line 906 sub update_student_data {
|
Line 1462 sub update_student_data {
|
chop $store_performance_command; |
chop $store_performance_command; |
chop $store_performance_command; |
chop $store_performance_command; |
my $start = Time::HiRes::time; |
my $start = Time::HiRes::time; |
$dbh->do($store_parameters_command) if ($num_parameters>0); |
|
if ($dbh->err()) { |
|
&Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); |
|
&Apache::lonnet::logthis('command = '.$store_parameters_command); |
|
$returnstatus = 'error: unable to insert parameters into database'; |
|
return $returnstatus,\%student_data; |
|
} |
|
$dbh->do($store_performance_command); |
$dbh->do($store_performance_command); |
if ($dbh->err()) { |
if ($dbh->err()) { |
&Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); |
&Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); |
&Apache::lonnet::logthis('command = '.$store_performance_command); |
&Apache::lonnet::logthis('command = '.$store_performance_command); |
$returnstatus = 'error: unable to insert performance into database'; |
$returnstatus = 'error: unable to insert performance into database'; |
return $returnstatus,\%student_data; |
return ($returnstatus,$student_data); |
|
} |
|
$dbh->do($store_parameters_command) if ($num_parameters>0); |
|
if ($dbh->err()) { |
|
&Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); |
|
&Apache::lonnet::logthis('command = '.$store_parameters_command); |
|
&Apache::lonnet::logthis('rows_stored = '.$rows_stored); |
|
&Apache::lonnet::logthis('student_id = '.$student_id); |
|
$returnstatus = 'error: unable to insert parameters into database'; |
|
return ($returnstatus,$student_data); |
} |
} |
$elapsed += Time::HiRes::time - $start; |
$elapsed += Time::HiRes::time - $start; |
# |
return ($returnstatus,$student_data); |
# Set the students update time |
|
&Apache::lonmysql::replace_row($updatetime_table, |
|
[$student,$time_of_retrieval]); |
|
return ($returnstatus,\%student_data); |
|
} |
} |
|
|
################################################ |
###################################### |
################################################ |
###################################### |
|
|
=pod |
=pod |
|
|
=item &ensure_current_data() |
=item &ensure_tables_are_set_up($courseid) |
|
|
Input: $sname, $sdom, $courseid |
Checks to be sure the MySQL tables for the given class are set up. |
|
If $courseid is omitted it will be obtained from the environment. |
Output: $status, $data |
|
|
|
This routine ensures the data for a given student is up to date. It calls |
Returns nothing on success and 'error' on failure |
&init_dbs() if the tables do not exist. The $updatetime_table is queried |
|
to determine the time of the last update. If the students data is out of |
|
date, &update_student_data() is called. The return values from the call |
|
to &update_student_data() are returned. |
|
|
|
=cut |
=cut |
|
|
################################################ |
###################################### |
################################################ |
###################################### |
sub ensure_current_data { |
sub ensure_tables_are_set_up { |
my ($sname,$sdom,$courseid) = @_; |
my ($courseid) = @_; |
my $status = 'okay'; # return value |
|
# |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
# |
# |
# Clean out package variables |
# Clean out package variables |
Line 960 sub ensure_current_data {
|
Line 1507 sub ensure_current_data {
|
# |
# |
# if the tables do not exist, make them |
# if the tables do not exist, make them |
my @CurrentTable = &Apache::lonmysql::tables_in_db(); |
my @CurrentTable = &Apache::lonmysql::tables_in_db(); |
my ($found_symb,$found_student,$found_part,$found_update, |
my ($found_symb,$found_student,$found_part,$found_studentdata, |
$found_performance,$found_parameters); |
$found_performance,$found_parameters,$found_fulldump_part, |
|
$found_fulldump_response,$found_fulldump_timestamp); |
foreach (@CurrentTable) { |
foreach (@CurrentTable) { |
$found_symb = 1 if ($_ eq $symb_table); |
$found_symb = 1 if ($_ eq $symb_table); |
$found_student = 1 if ($_ eq $student_table); |
$found_student = 1 if ($_ eq $student_table); |
$found_part = 1 if ($_ eq $part_table); |
$found_part = 1 if ($_ eq $part_table); |
$found_update = 1 if ($_ eq $updatetime_table); |
$found_studentdata = 1 if ($_ eq $studentdata_table); |
$found_performance = 1 if ($_ eq $performance_table); |
$found_performance = 1 if ($_ eq $performance_table); |
$found_parameters = 1 if ($_ eq $parameters_table); |
$found_parameters = 1 if ($_ eq $parameters_table); |
|
$found_fulldump_part = 1 if ($_ eq $fulldump_part_table); |
|
$found_fulldump_response = 1 if ($_ eq $fulldump_response_table); |
|
$found_fulldump_timestamp = 1 if ($_ eq $fulldump_timestamp_table); |
} |
} |
if (!$found_symb || !$found_update || |
if (!$found_symb || !$found_studentdata || |
!$found_student || !$found_part || |
!$found_student || !$found_part || |
!$found_performance || !$found_parameters) { |
!$found_performance || !$found_parameters || |
|
!$found_fulldump_part || !$found_fulldump_response || |
|
!$found_fulldump_timestamp ) { |
if (&init_dbs($courseid)) { |
if (&init_dbs($courseid)) { |
return 'error'; |
return 'error'; |
} |
} |
} |
} |
|
} |
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
|
=item &ensure_current_data() |
|
|
|
Input: $sname, $sdom, $courseid |
|
|
|
Output: $status, $data |
|
|
|
This routine ensures the data for a given student is up to date. |
|
The $studentdata_table is queried to determine the time of the last update. |
|
If the students data is out of date, &update_student_data() is called. |
|
The return values from the call to &update_student_data() are returned. |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub ensure_current_data { |
|
my ($sname,$sdom,$courseid) = @_; |
|
my $status = 'okay'; # return value |
|
# |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
&ensure_tables_are_set_up($courseid); |
# |
# |
# Get the update time for the user |
# Get the update time for the user |
my $updatetime = 0; |
my $updatetime = 0; |
Line 984 sub ensure_current_data {
|
Line 1565 sub ensure_current_data {
|
($sdom,$sname,$courseid.'.db', |
($sdom,$sname,$courseid.'.db', |
$Apache::lonnet::perlvar{'lonUsersDir'}); |
$Apache::lonnet::perlvar{'lonUsersDir'}); |
# |
# |
my $student = $sname.':'.$sdom; |
my $student_id = &get_student_id($sname,$sdom); |
my @Result = &Apache::lonmysql::get_rows($updatetime_table, |
my @Result = &Apache::lonmysql::get_rows($studentdata_table, |
"student ='$student'"); |
"student_id ='$student_id'"); |
my $data = undef; |
my $data = undef; |
if (@Result) { |
if (@Result) { |
$updatetime = $Result[0]->[1]; |
$updatetime = $Result[0]->[1]; |
Line 1002 sub ensure_current_data {
|
Line 1583 sub ensure_current_data {
|
|
|
=pod |
=pod |
|
|
|
=item &ensure_current_full_data($sname,$sdom,$courseid) |
|
|
|
Input: $sname, $sdom, $courseid |
|
|
|
Output: $status |
|
|
|
This routine ensures the fulldata (the data from a lonnet::dump, not a |
|
lonnet::currentdump) for a given student is up to date. |
|
The $studentdata_table is queried to determine the time of the last update. |
|
If the students fulldata is out of date, &update_full_student_data() is |
|
called. |
|
|
|
The return value from the call to &update_full_student_data() is returned. |
|
|
|
=cut |
|
|
|
################################################ |
|
################################################ |
|
sub ensure_current_full_data { |
|
my ($sname,$sdom,$courseid) = @_; |
|
my $status = 'okay'; # return value |
|
# |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
&ensure_tables_are_set_up($courseid); |
|
# |
|
# Get the update time for the user |
|
my $modifiedtime = &Apache::lonnet::GetFileTimestamp |
|
($sdom,$sname,$courseid.'.db', |
|
$Apache::lonnet::perlvar{'lonUsersDir'}); |
|
# |
|
my $student_id = &get_student_id($sname,$sdom); |
|
my @Result = &Apache::lonmysql::get_rows($studentdata_table, |
|
"student_id ='$student_id'"); |
|
my $updatetime; |
|
if (@Result && ref($Result[0]) eq 'ARRAY') { |
|
$updatetime = $Result[0]->[2]; |
|
} |
|
if (! defined($updatetime) || $modifiedtime > $updatetime) { |
|
$status = &update_full_student_data($sname,$sdom,$courseid); |
|
} |
|
return $status; |
|
} |
|
|
|
################################################ |
|
################################################ |
|
|
|
=pod |
|
|
=item &get_student_data_from_performance_cache() |
=item &get_student_data_from_performance_cache() |
|
|
Input: $sname, $sdom, $symb, $courseid |
Input: $sname, $sdom, $symb, $courseid |
Line 1038 sub get_student_data_from_performance_ca
|
Line 1667 sub get_student_data_from_performance_ca
|
# |
# |
my $dbh = &Apache::lonmysql::get_dbh(); |
my $dbh = &Apache::lonmysql::get_dbh(); |
my $request = "SELECT ". |
my $request = "SELECT ". |
"d.symb,c.part,a.solved,a.tries,a.awarded,a.award,a.awarddetail,". |
"d.symb,a.part,a.solved,a.tries,a.awarded,a.award,a.awarddetail,". |
"a.timestamp,a.weight "; |
"a.timestamp "; |
if (defined($student)) { |
if (defined($student)) { |
$request .= "FROM $student_table AS b ". |
$request .= "FROM $student_table AS b ". |
"LEFT JOIN $performance_table AS a ON b.student_id=a.student_id ". |
"LEFT JOIN $performance_table AS a ON b.student_id=a.student_id ". |
"LEFT JOIN $part_table AS c ON c.part_id = a.part_id ". |
# "LEFT JOIN $part_table AS c ON c.part_id = a.part_id ". |
"LEFT JOIN $symb_table AS d ON d.symb_id = a.symb_id ". |
"LEFT JOIN $symb_table AS d ON d.symb_id = a.symb_id ". |
"WHERE student='$student'"; |
"WHERE student='$student'"; |
if (defined($symb) && $symb ne '') { |
if (defined($symb) && $symb ne '') { |
$request .= " AND d.symb='".$dbh->quote($symb)."'"; |
$request .= " AND d.symb=".$dbh->quote($symb); |
} |
} |
} elsif (defined($symb) && $symb ne '') { |
} elsif (defined($symb) && $symb ne '') { |
$request .= "FROM $symb_table as d ". |
$request .= "FROM $symb_table as d ". |
"LEFT JOIN $performance_table AS a ON d.symb_id=a.symb_id ". |
"LEFT JOIN $performance_table AS a ON d.symb_id=a.symb_id ". |
"LEFT JOIN $part_table AS c ON c.part_id = a.part_id ". |
# "LEFT JOIN $part_table AS c ON c.part_id = a.part_id ". |
"LEFT JOIN $student_table AS b ON b.student_id = a.student_id ". |
"LEFT JOIN $student_table AS b ON b.student_id = a.student_id ". |
"WHERE symb='".$dbh->quote($symb)."'"; |
"WHERE symb='".$dbh->quote($symb)."'"; |
} |
} |
Line 1068 sub get_student_data_from_performance_ca
|
Line 1697 sub get_student_data_from_performance_ca
|
} |
} |
foreach my $row (@{$sth->fetchall_arrayref}) { |
foreach my $row (@{$sth->fetchall_arrayref}) { |
$rows_retrieved++; |
$rows_retrieved++; |
my ($symb,$part,$solved,$tries,$awarded,$award,$awarddetail,$time,$weight) = |
my ($symb,$part,$solved,$tries,$awarded,$award,$awarddetail,$time) = |
(@$row); |
(@$row); |
my $base = 'resource.'.$part; |
my $base = 'resource.'.$part; |
$studentdata->{$symb}->{$base.'.solved'} = $solved; |
$studentdata->{$symb}->{$base.'.solved'} = $solved; |
Line 1077 sub get_student_data_from_performance_ca
|
Line 1706 sub get_student_data_from_performance_ca
|
$studentdata->{$symb}->{$base.'.award'} = $award; |
$studentdata->{$symb}->{$base.'.award'} = $award; |
$studentdata->{$symb}->{$base.'.awarddetail'} = $awarddetail; |
$studentdata->{$symb}->{$base.'.awarddetail'} = $awarddetail; |
$studentdata->{$symb}->{'timestamp'} = $time if (defined($time) && $time ne ''); |
$studentdata->{$symb}->{'timestamp'} = $time if (defined($time) && $time ne ''); |
$studentdata->{$symb}->{'resource.'.$part.'.weight'}=$weight; |
} |
|
## Get misc parameters |
|
$request = 'SELECT c.symb,a.parameter,a.value '. |
|
"FROM $student_table AS b ". |
|
"LEFT JOIN $parameters_table AS a ON b.student_id=a.student_id ". |
|
"LEFT JOIN $symb_table AS c ON c.symb_id = a.symb_id ". |
|
"WHERE student='$student'"; |
|
if (defined($symb) && $symb ne '') { |
|
$request .= " AND c.symb=".$dbh->quote($symb); |
|
} |
|
$sth = $dbh->prepare($request); |
|
$sth->execute(); |
|
if ($sth->err()) { |
|
&Apache::lonnet::logthis("Unable to execute MySQL request:"); |
|
&Apache::lonnet::logthis("\n".$request."\n"); |
|
&Apache::lonnet::logthis("error is:".$sth->errstr()); |
|
if (defined($symb) && $symb ne '') { |
|
$studentdata = $studentdata->{$symb}; |
|
} |
|
return $studentdata; |
|
} |
|
# |
|
foreach my $row (@{$sth->fetchall_arrayref}) { |
|
$rows_retrieved++; |
|
my ($symb,$parameter,$value) = (@$row); |
|
$studentdata->{$symb}->{$parameter} = $value; |
|
} |
|
# |
|
if (defined($symb) && $symb ne '') { |
|
$studentdata = $studentdata->{$symb}; |
} |
} |
return $studentdata; |
return $studentdata; |
} |
} |
Line 1128 sub get_current_state {
|
Line 1786 sub get_current_state {
|
return () if (! defined($sname) || ! defined($sdom)); |
return () if (! defined($sname) || ! defined($sdom)); |
# |
# |
my ($status,$data) = &ensure_current_data($sname,$sdom,$courseid); |
my ($status,$data) = &ensure_current_data($sname,$sdom,$courseid); |
# |
# &Apache::lonnet::logthis |
if (defined($data)) { |
# ('sname = '.$sname. |
|
# ' domain = '.$sdom. |
|
# ' status = '.$status. |
|
# ' data is '.(defined($data)?'defined':'undefined')); |
|
# while (my ($symb,$hash) = each(%$data)) { |
|
# &Apache::lonnet::logthis($symb."\n----------------------------------"); |
|
# while (my ($key,$value) = each (%$hash)) { |
|
# &Apache::lonnet::logthis(" ".$key." = ".$value); |
|
# } |
|
# } |
|
# |
|
if (defined($data) && defined($symb) && ref($data->{$symb})) { |
|
return %{$data->{$symb}}; |
|
} elsif (defined($data) && ! defined($symb) && ref($data)) { |
return %$data; |
return %$data; |
} elsif ($status eq 'no data') { |
} |
|
if ($status eq 'no data') { |
return (); |
return (); |
} else { |
} else { |
if ($status ne 'okay' && $status ne '') { |
if ($status ne 'okay' && $status ne '') { |
Line 1159 the students you are concerned with prio
|
Line 1831 the students you are concerned with prio
|
|
|
Inputs: $students, $symb, $part, $courseid |
Inputs: $students, $symb, $part, $courseid |
|
|
|
=over 4 |
|
|
|
=item $students is an array of hash references. |
|
Each hash must contain at least the 'username' and 'domain' of a student. |
|
|
|
=item $symb is the symb for the problem. |
|
|
|
=item $part is the part id you need statistics for |
|
|
|
=item $courseid is the course id, of course! |
|
|
|
=back |
|
|
|
Outputs: See the code for up to date information. A hash reference is |
|
returned. The hash has the following keys defined: |
|
|
|
=over 4 |
|
|
|
=item num_students The number of students attempting the problem |
|
|
|
=item tries The total number of tries for the students |
|
|
|
=item max_tries The maximum number of tries taken |
|
|
|
=item mean_tries The average number of tries |
|
|
|
=item num_solved The number of students able to solve the problem |
|
|
|
=item num_override The number of students whose answer is 'correct_by_override' |
|
|
|
=item deg_of_diff The degree of difficulty of the problem |
|
|
|
=item std_tries The standard deviation of the number of tries |
|
|
|
=item skew_tries The skew of the number of tries |
|
|
|
=item per_wrong The number of students attempting the problem who were not |
|
able to answer it correctly. |
|
|
|
=back |
|
|
=cut |
=cut |
|
|
################################################ |
################################################ |
Line 1168 sub get_problem_statistics {
|
Line 1881 sub get_problem_statistics {
|
return if (! defined($symb) || ! defined($part)); |
return if (! defined($symb) || ! defined($part)); |
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
# |
# |
|
&setup_table_names($courseid); |
my $symb_id = &get_symb_id($symb); |
my $symb_id = &get_symb_id($symb); |
my $part_id = &get_part_id($part); |
my $part_id = &get_part_id($part); |
my $stats_table = $courseid.'_problem_stats'; |
my $stats_table = $courseid.'_problem_stats'; |
# |
# |
&Apache::lonnet::logthis('symb id = '.$symb_id); |
|
&Apache::lonnet::logthis('part id = '.$part_id); |
|
|
|
my $dbh = &Apache::lonmysql::get_dbh(); |
my $dbh = &Apache::lonmysql::get_dbh(); |
return undef if (! defined($dbh)); |
return undef if (! defined($dbh)); |
&Apache::lonnet::logthis('dbh is defined'); |
|
# |
# |
# A) Number of Students attempting problem |
# A) Number of Students attempting problem |
# B) Total number of tries of students attempting problem |
# B) Total number of tries of students attempting problem |
Line 1195 sub get_problem_statistics {
|
Line 1905 sub get_problem_statistics {
|
'CREATE TEMPORARY TABLE '.$stats_table. |
'CREATE TEMPORARY TABLE '.$stats_table. |
' SELECT student_id,solved,award,tries FROM '.$performance_table. |
' SELECT student_id,solved,award,tries FROM '.$performance_table. |
' WHERE symb_id='.$symb_id.' AND part_id='.$part_id; |
' WHERE symb_id='.$symb_id.' AND part_id='.$part_id; |
|
if (defined($students)) { |
|
$request .= ' AND ('. |
|
join(' OR ', map {'student_id='. |
|
&get_student_id($_->{'username'}, |
|
$_->{'domain'}) |
|
} @$students |
|
).')'; |
|
} |
# &Apache::lonnet::logthis($request); |
# &Apache::lonnet::logthis($request); |
$dbh->do($request); |
$dbh->do($request); |
my ($num,$tries,$mod,$mean,$STD) = &execute_SQL_request |
my ($num,$tries,$mod,$mean,$STD) = &execute_SQL_request |
Line 1203 sub get_problem_statistics {
|
Line 1921 sub get_problem_statistics {
|
$stats_table); |
$stats_table); |
my ($Solved) = &execute_SQL_request($dbh,'SELECT COUNT(tries) FROM '. |
my ($Solved) = &execute_SQL_request($dbh,'SELECT COUNT(tries) FROM '. |
$stats_table. |
$stats_table. |
" WHERE solved='correct_by_student'"); |
" WHERE solved='correct_by_student' OR solved='correct_by_scantron'"); |
my ($solved) = &execute_SQL_request($dbh,'SELECT COUNT(tries) FROM '. |
my ($solved) = &execute_SQL_request($dbh,'SELECT COUNT(tries) FROM '. |
$stats_table. |
$stats_table. |
" WHERE solved='correct_by_override'"); |
" WHERE solved='correct_by_override'"); |
Line 1215 sub get_problem_statistics {
|
Line 1933 sub get_problem_statistics {
|
$solved = 0 if (! defined($solved)); |
$solved = 0 if (! defined($solved)); |
# |
# |
my $DegOfDiff = 'nan'; |
my $DegOfDiff = 'nan'; |
$DegOfDiff = 1-($Solved + $solved)/$tries if ($tries>0); |
$DegOfDiff = 1-($Solved)/$tries if ($tries>0); |
|
|
my $SKEW = 'nan'; |
my $SKEW = 'nan'; |
|
my $wrongpercent = 0; |
if ($num > 0) { |
if ($num > 0) { |
($SKEW) = &execute_SQL_request($dbh,'SELECT SQRT(SUM('. |
($SKEW) = &execute_SQL_request($dbh,'SELECT SQRT(SUM('. |
'POWER(tries - '.$STD.',3)'. |
'POWER(tries - '.$STD.',3)'. |
'))/'.$num.' FROM '.$stats_table); |
'))/'.$num.' FROM '.$stats_table); |
|
$wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10; |
} |
} |
# |
# |
$dbh->do('DROP TABLE '.$stats_table); # May return an error |
$dbh->do('DROP TABLE '.$stats_table); # May return an error |
return ($num,$tries,$mod,$mean,$Solved,$solved,$DegOfDiff,$STD,$SKEW); |
# |
|
# Store in metadata |
|
# |
|
if ($num) { |
|
my %storestats=(); |
|
|
|
my $urlres=(&Apache::lonnet::decode_symb($symb))[2]; |
|
|
|
$storestats{$courseid.'___'.$urlres.'___timestamp'}=time; |
|
$storestats{$courseid.'___'.$urlres.'___stdno'}=$num; |
|
$storestats{$courseid.'___'.$urlres.'___avetries'}=$mean; |
|
$storestats{$courseid.'___'.$urlres.'___difficulty'}=$DegOfDiff; |
|
|
|
$urlres=~/^(\w+)\/(\w+)/; |
|
&Apache::lonnet::put('nohist_resevaldata',\%storestats,$1,$2); |
|
} |
|
# |
|
# Return result |
|
# |
|
return { num_students => $num, |
|
tries => $tries, |
|
max_tries => $mod, |
|
mean_tries => $mean, |
|
std_tries => $STD, |
|
skew_tries => $SKEW, |
|
num_solved => $Solved, |
|
num_override => $solved, |
|
per_wrong => $wrongpercent, |
|
deg_of_diff => $DegOfDiff }; |
} |
} |
|
|
sub execute_SQL_request { |
sub execute_SQL_request { |
Line 1240 sub execute_SQL_request {
|
Line 1988 sub execute_SQL_request {
|
return (); |
return (); |
} |
} |
|
|
|
sub get_student_data { |
|
my ($students,$courseid) = @_; |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
&setup_table_names($courseid); |
|
my $dbh = &Apache::lonmysql::get_dbh(); |
|
return undef if (! defined($dbh)); |
|
my $request = 'SELECT '. |
|
'student_id, student '. |
|
'FROM '.$student_table; |
|
if (defined($students)) { |
|
$request .= ' WHERE ('. |
|
join(' OR ', map {'student_id='. |
|
&get_student_id($_->{'username'}, |
|
$_->{'domain'}) |
|
} @$students |
|
).')'; |
|
} |
|
$request.= ' ORDER BY student_id'; |
|
my $sth = $dbh->prepare($request); |
|
$sth->execute(); |
|
if ($dbh->err) { |
|
&Apache::lonnet::logthis('error = '.$dbh->errstr()); |
|
return undef; |
|
} |
|
my $dataset = $sth->fetchall_arrayref(); |
|
if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) { |
|
return $dataset; |
|
} |
|
} |
|
|
|
sub get_optionresponse_data { |
|
my ($students,$symb,$response,$courseid) = @_; |
|
return undef if (! defined($symb) || |
|
! defined($response)); |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
# |
|
&setup_table_names($courseid); |
|
my $symb_id = &get_symb_id($symb); |
|
my $response_id = &get_part_id($response); |
|
# |
|
my $dbh = &Apache::lonmysql::get_dbh(); |
|
return undef if (! defined($dbh)); |
|
my $request = 'SELECT '. |
|
'a.student_id, a.awarddetail, a.response_specific_value, '. |
|
'a.submission, b.timestamp, c.tries '. |
|
'FROM '.$fulldump_response_table.' AS a '. |
|
'LEFT JOIN '.$fulldump_timestamp_table.' AS b '. |
|
'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '. |
|
'a.transaction = b.transaction '. |
|
'LEFT JOIN '.$fulldump_part_table.' AS c '. |
|
'ON a.symb_id=c.symb_id AND a.student_id=c.student_id AND '. |
|
'a.part_id=c.part_id AND a.transaction = c.transaction '. |
|
'WHERE '. |
|
'a.symb_id='.$symb_id.' AND a.response_id='.$response_id; |
|
if (defined($students)) { |
|
$request .= ' AND ('. |
|
join(' OR ', map {'a.student_id='. |
|
&get_student_id($_->{'username'}, |
|
$_->{'domain'}) |
|
} @$students |
|
).')'; |
|
} |
|
$request .= ' ORDER BY b.timestamp'; |
|
# &Apache::lonnet::logthis("request =\n".$request); |
|
my $sth = $dbh->prepare($request); |
|
$sth->execute(); |
|
if ($dbh->err) { |
|
&Apache::lonnet::logthis('error = '.$dbh->errstr()); |
|
return undef; |
|
} |
|
my $dataset = $sth->fetchall_arrayref(); |
|
if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) { |
|
return $dataset; |
|
} |
|
} |
|
|
|
sub get_response_time_data { |
|
my ($students,$symb,$part,$courseid) = @_; |
|
return undef if (! defined($symb) || |
|
! defined($part)); |
|
$courseid = $ENV{'request.course.id'} if (! defined($courseid)); |
|
# |
|
&setup_table_names($courseid); |
|
my $symb_id = &get_symb_id($symb); |
|
my $part_id = &get_part_id($part); |
|
# |
|
my $dbh = &Apache::lonmysql::get_dbh(); |
|
return undef if (! defined($dbh)); |
|
my $request = 'SELECT '. |
|
'a.student_id, a.awarded, a.tries, b.timestamp '. |
|
'FROM '.$fulldump_part_table.' AS a '. |
|
'NATURAL LEFT JOIN '.$fulldump_timestamp_table.' AS b '. |
|
# 'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '. |
|
# 'a.transaction = b.transaction '. |
|
'WHERE '. |
|
'a.symb_id='.$symb_id.' AND a.part_id='.$part_id; |
|
if (defined($students)) { |
|
$request .= ' AND ('. |
|
join(' OR ', map {'a.student_id='. |
|
&get_student_id($_->{'username'}, |
|
$_->{'domain'}) |
|
} @$students |
|
).')'; |
|
} |
|
$request .= ' ORDER BY b.timestamp'; |
|
# &Apache::lonnet::logthis("request =\n".$request); |
|
my $sth = $dbh->prepare($request); |
|
$sth->execute(); |
|
if ($dbh->err) { |
|
&Apache::lonnet::logthis('error = '.$dbh->errstr()); |
|
return undef; |
|
} |
|
my $dataset = $sth->fetchall_arrayref(); |
|
if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) { |
|
return $dataset; |
|
} |
|
|
|
} |
|
|
################################################ |
################################################ |
################################################ |
################################################ |
Line 1284 sub setup_table_names {
|
Line 2150 sub setup_table_names {
|
$symb_table = $base_id.'_'.'symb'; |
$symb_table = $base_id.'_'.'symb'; |
$part_table = $base_id.'_'.'part'; |
$part_table = $base_id.'_'.'part'; |
$student_table = $base_id.'_'.'student'; |
$student_table = $base_id.'_'.'student'; |
$updatetime_table = $base_id.'_'.'updatetime'; |
$studentdata_table = $base_id.'_'.'studentdata'; |
$performance_table = $base_id.'_'.'performance'; |
$performance_table = $base_id.'_'.'performance'; |
$parameters_table = $base_id.'_'.'parameters'; |
$parameters_table = $base_id.'_'.'parameters'; |
|
$fulldump_part_table = $base_id.'_'.'partdata'; |
|
$fulldump_response_table = $base_id.'_'.'responsedata'; |
|
$fulldump_timestamp_table = $base_id.'_'.'timestampdata'; |
|
# |
|
@Tables = ( |
|
$symb_table, |
|
$part_table, |
|
$student_table, |
|
$studentdata_table, |
|
$performance_table, |
|
$parameters_table, |
|
$fulldump_part_table, |
|
$fulldump_response_table, |
|
$fulldump_timestamp_table, |
|
); |
return; |
return; |
} |
} |
|
|
Line 1304 sub setup_table_names {
|
Line 2185 sub setup_table_names {
|
################################################ |
################################################ |
################################################ |
################################################ |
|
|
|
} # End scope of table identifiers |
|
|
} |
|
################################################ |
################################################ |
################################################ |
################################################ |
|
|