--- loncom/interface/loncommon.pm 2005/05/26 20:49:23 1.262 +++ loncom/interface/loncommon.pm 2005/11/22 00:01:41 1.298 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.262 2005/05/26 20:49:23 albertel Exp $ +# $Id: loncommon.pm,v 1.298 2005/11/22 00:01:41 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -152,19 +152,20 @@ BEGIN { my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; opendir(DIR,$designdir); while ($filename=readdir(DIR)) { + if ($filename!~/\.tab$/) { next; } my ($domain)=($filename=~/^(\w+)\./); - { - my $designfile = $designdir.'/'.$filename; - if ( open (my $fh,"<$designfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\=/,$_)); - if ($val) { $designhash{$domain.'.'.$key}=$val; } - } - close($fh); - } - } + { + my $designfile = $designdir.'/'.$filename; + if ( open (my $fh,"<$designfile") ) { + while (<$fh>) { + next if /^\#/; + chomp; + my ($key,$val)=(split(/\=/,$_)); + if ($val) { $designhash{$domain.'.'.$key}=$val; } + } + close($fh); + } + } } closedir(DIR); @@ -379,7 +380,7 @@ sub coursebrowser_javascript { return (< var stdeditbrowser; - function opencrsbrowser(formname,uname,udom,desc,extra_element) { + function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag) { var url = '/adm/pickcourse?'; var filter; if (filter != null) { @@ -402,6 +403,9 @@ sub coursebrowser_javascript { url += '&domainfilter='+extra_element; } } + if (multflag !=null && multflag != '') { + url += '&multiple='+multflag; + } var title = 'Course_Browser'; var options = 'scrollbars=1,resizable=1,menubar=0'; options += ',width=700,height=600'; @@ -413,11 +417,36 @@ ENDSTDBRW } sub selectcourse_link { - my ($form,$unameele,$udomele,$desc,$extra_element)=@_; + my ($form,$unameele,$udomele,$desc,$extra_element,$multflag)=@_; return "".&mt('Select Course').""; + '","'.$udomele.'","'.$desc.'","'.$extra_element.'","'.$multflag.'");'."'>".&mt('Select Course').""; +} + +sub check_uncheck_jscript { + my $jscript = <<"ENDSCRT"; +function checkAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = true ; + } + } else { + field.checked = true + } +} + +function uncheckAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = false ; + } } else { + field.checked = false ; + } +} +ENDSCRT + return $jscript; } + =pod =item * linked_select_forms(...) @@ -673,7 +702,6 @@ sub help_open_menu { foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) { $$_ = &Apache::lonnet::escape($$_); } - if (!$stayOnPage) { $link = "javascript:helpMenu('open')"; } else { @@ -684,8 +712,8 @@ sub help_open_menu { my $template; if ($text ne "") { $template .= - "". - "'); $i++; } @@ -3549,7 +3932,7 @@ the routine &Apache::lonnet::transfer_pr my $uniq=0; sub get_cgi_id { $uniq=($uniq+1)%100000; - return (time.'_'.$uniq); + return (time.'_'.$$.'_'.$uniq); } ############################################################
$text"; + "". + "'.$roleinfo.'
$text"; } my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); my $html=&Apache::lonxml::xmlbegin(); @@ -713,9 +741,9 @@ function helpMenu(target) { return; } function writeHelp(caller) { - caller.document.write('$htmlLON-CAPA Help Menu') - caller.document.write("") - caller.document.write("") + caller.document.writeln('$htmlLON-CAPA Help Menu') + caller.document.writeln("") + caller.document.writeln("") caller.document.close() caller.focus() } @@ -1124,27 +1152,49 @@ sub domain_select { } &get_domains; if ($multiple) { $domains{''}=&mt('Any domain'); - return &multiple_select_form($name,$value,4,%domains); + return &multiple_select_form($name,$value,4,\%domains); } else { return &select_form($name,$value,%domains); } } +#------------------------------------------- + +=pod + +=item * multiple_select_form($name,$value,$size,$hash,$order) + +Returns a string containing a element + $value - sclara or array ref of values that should already be selected + $size - number of rows long the select element is + $hash - the elements should be 'option' => 'shown text' + (shown text should already have been &mt()) + $order - (optional) array ref of the order to show the elments in + +=cut + +#------------------------------------------- sub multiple_select_form { - my ($name,$value,$size,%hash)=@_; + my ($name,$value,$size,$hash,$order)=@_; my %selected = map { $_ => 1 } ref($value)?@{$value}:($value); my $output=''; if (! defined($size)) { $size = 4; - if (scalar(keys(%hash))<4) { - $size = scalar(keys(%hash)); + if (scalar(keys(%$hash))<4) { + $size = scalar(keys(%$hash)); } } $output.="\n\n"; return $output; @@ -1540,10 +1590,11 @@ sub authform_nochange{ kerb_def_dom => 'MSU.EDU', @_, ); - my $result = &mt('[_1] Do not change login data', + my $result = ''; return $result; } @@ -1575,14 +1626,15 @@ sub authform_kerberos{ my $jscall = "javascript:changed_radio('krb',$in{'formname'});"; my $result .= &mt ('[_1] Kerberos authenticated with domain [_2] '. - '[_3] Version 4 [_4] Version 5', - '', - '', - '', - ''); + ''); return $result; } @@ -1607,9 +1659,9 @@ sub authform_internal{ my $jscall = "javascript:changed_radio('int',$args{'formname'});"; my $result.=&mt ('[_1] Internally authenticated (with initial password [_2])', - '', - ''); return $result; } @@ -1634,9 +1686,9 @@ sub authform_local{ my $jscall = "javascript:changed_radio('loc',$in{'formname'});"; my $result.=&mt('[_1] Local Authentication with argument [_2]', - '', - ''); return $result; } @@ -1650,9 +1702,9 @@ sub authform_filesystem{ my $jscall = "javascript:changed_radio('fsys',$in{'formname'});"; my $result.= &mt ('[_1] Filesystem Authenticated (with initial password [_2])', - '', - ''); return $result; } @@ -1868,12 +1920,11 @@ if $first is set to 'lastname' then it r =cut + ############################################################### sub plainname { my ($uname,$udom,$first)=@_; - my %names=&Apache::lonnet::get('environment', - ['firstname','middlename','lastname','generation'], - $udom,$uname); + my %names=&getnames($uname,$udom); my $name=&Apache::lonnet::format_name($names{'firstname'}, $names{'middlename'}, $names{'lastname'}, @@ -1904,19 +1955,7 @@ if the user does not sub nickname { my ($uname,$udom)=@_; - my %names; - if ($uname eq $env{'user.name'} && - $udom eq $env{'user.domain'}) { - %names=('nickname' => $env{'environment.nickname'} , - 'firstname' => $env{'environment.firstname'} , - 'middlename' => $env{'environment.middlename'}, - 'lastname' => $env{'environment.lastname'} , - 'generation' => $env{'environment.generation'}); - } else { - %names=&Apache::lonnet::get('environment', - ['nickname','firstname','middlename', - 'lastname','generation'],$udom,$uname); - } + my %names=&getnames($uname,$udom); my $name=$names{'nickname'}; if ($name) { $name='"'.$name.'"'; @@ -1929,6 +1968,20 @@ sub nickname { return $name; } +sub getnames { + my ($uname,$udom)=@_; + my $id=$uname.':'.$udom; + my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id); + if ($cached) { + return %{$names}; + } else { + my %loadnames=&Apache::lonnet::get('environment', + ['firstname','middlename','lastname','generation','nickname'], + $udom,$uname); + &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames); + return %loadnames; + } +} # ------------------------------------------------------------------ Screenname @@ -1985,24 +2038,23 @@ sub syllabuswrapper { } sub track_student_link { - my ($linktext,$sname,$sdom,$target) = @_; - my $link ="/adm/trackstudent"; + my ($linktext,$sname,$sdom,$target,$start) = @_; + my $link ="/adm/trackstudent?"; my $title = 'View recent activity'; if (defined($sname) && $sname !~ /^\s*$/ && defined($sdom) && $sdom !~ /^\s*$/) { - $link .= "?selected_student=$sname:$sdom"; + $link .= "selected_student=$sname:$sdom"; $title .= ' of this student'; - } + } if (defined($target) && $target !~ /^\s*$/) { $target = qq{target="$target"}; } else { $target = ''; } + if ($start) { $link.='&start='.$start; } return qq{$linktext}; } - - =pod =back @@ -2485,7 +2537,7 @@ sub pgrdlink { Inputs: $text $uname $udom $symb $target Returns: A link to parmset.pm such as to see the PPRM view of a -student andn resource +student and a specific resource =cut @@ -2690,7 +2742,7 @@ other decorations will be returned. =cut sub bodytag { - my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle)=@_; + my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle,$notopbar)=@_; $title=&mt($title); $function = &get_users_function() if (!$function); my $img=&designparm($function.'.img',$domain); @@ -2726,15 +2778,17 @@ sub bodytag { END + &Apache::lontexconvert::jsMath_reset(); if ($env{'environment.texengine'} eq 'jsMath') { - $bodytag.=''."\n". - ''."\n"; + $bodytag.=&Apache::lontexconvert::jsMath_header(); } my $upperleft=''. - '
'. + '
'. $titleinfo.'
'; if ($env{'request.state'} eq 'construct') { - $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable); + if ($notopbar) { + $bodytag .= $titletable; + } else { + $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable); + } } else { - $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg). + if ($notopbar) { + $bodytag .= $titletable; + } else { + $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg). $titletable; + } } return $bodytag; } @@ -2881,10 +2943,7 @@ Returns: A uniform footer for LON-CAPA w sub endbodytag { my $endbodytag=''; - if ($env{'environment.texengine'} eq 'jsMath') { - $endbodytag=''. - "\n".$endbodytag; - } + $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag; return $endbodytag; } @@ -2919,6 +2978,60 @@ sub get_users_function { =pod +=item check_user_status + +Determines current status of supplied role for a +specific user. Roles can be active, previous or future. + +Inputs: +user's domain, user's username, course's domain, +course's number, optional section/group. + +Outputs: +role status: active, previous or future. + +=cut + +sub check_user_status { + my ($udom,$uname,$cdom,$crs,$role,$secgrp) = @_; + my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); + my @uroles = keys %userinfo; + my $srchstr; + my $active_chk = 'none'; + if (@uroles > 0) { + if (($role eq 'cc') || ($secgrp eq '') || (!defined($secgrp))) { + $srchstr = '/'.$cdom.'/'.$crs.'_'.$role; + } else { + $srchstr = '/'.$cdom.'/'.$crs.'/'.$secgrp.'_'.$role; } + if (grep/^$srchstr$/,@uroles) { + my $role_end = 0; + my $role_start = 0; + $active_chk = 'active'; + if ($userinfo{$srchstr} =~ m/^($role)_(\d+)/) { + $role_end = $2; + if ($userinfo{$srchstr} =~ m/^($role)_($role_end)_(\d+)$/) { + $role_start = $3; + } + } + if ($role_start > 0) { + if (time < $role_start) { + $active_chk = 'future'; + } + } + if ($role_end > 0) { + if (time > $role_end) { + $active_chk = 'previous'; + } + } + } + } + return $active_chk; +} + +############################################### + +=pod + =item get_sections Determines all the sections for a course including @@ -2937,11 +3050,10 @@ Returns number of sections. sub get_sections { my ($cdom,$cnum,$sectioncount,$possible_roles) = @_; if (!($cdom && $cnum)) { return 0; } - my $cid = $cdom.'_'.$cnum; my $numsections = 0; if (!defined($possible_roles) || (grep/^st$/,@$possible_roles)) { - my ($classlist) = &Apache::loncoursedata::get_classlist($cid,$cdom,$cnum); + my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum); my $sec_index = &Apache::loncoursedata::CL_SECTION(); my $status_index = &Apache::loncoursedata::CL_STATUS(); while (my ($student,$data) = each %$classlist) { @@ -2971,6 +3083,272 @@ sub get_sections { return $numsections; } +############################################### + +=pod + +=item coursegroups + +Retrieve information about groups in a course, + +Input: +1. Reference to hash to populate with group information. +2. Optional course domain +3. Optional course number +4. Optional group name + +Course domain and number will be taken from user's +environment if not supplied. Optional group name will' +be passed to lonnet::get_coursegroups() as a regexp to +use in the call to the dump function. + +Output +Returns number of groups in the course (subject to the +optional group name filter). + +Side effects: +Populates the referenced curr_groups hash, with key, +value pairs. Keys are group names, corresponding values +are scalars containing group information in XML. This +can be sent to &get_group_settings() to be parsed. + +=cut + +############################################### + +sub coursegroups { + my ($curr_groups,$cdom,$cnum,$group) = @_; + my $numgroups; + if (!defined($cdom) || !defined($cnum)) { + my $cid = $env{'request.course.id'}; + $cdom = $env{'course.'.$cid.'.domain'}; + $cnum = $env{'course.'.$cid.'.num'}; + } + %{$curr_groups} = &Apache::lonnet::get_coursegroups($cdom,$cnum,$group); + my ($tmp) = keys(%{$curr_groups}); + if ($tmp=~/^error:/) { + unless ($tmp eq 'error: 2 tie(GDBM) Failed while attempting dump') { + &logthis('Error retrieving groups: '.$tmp.' in '.$cnum.':'. + $cdom); + } + $numgroups = 0; + } else { + $numgroups = keys(%{$curr_groups}); + } + return $numgroups; +} + +############################################### + +=pod + +=item get_group_settings + +Uses TokeParser to extract group information from the +XML used to describe course groups. + +Input: +Scalar containing XML - as retrieved from &coursegroups(). + +Output: +Hash containing group information as key=values for (a), and +hash of hashes for (b) + +Keys (in two categories): +(a) groupname, creator, creation, modified, startdate,enddate. +Corresponding values are name of the group, creator of the group +(username:domain), UNIX time for date group was created, and +settings were last modified, and default start and end access +times for group members. + +(b) functions returned in hash of hashes. +Outer hash key is functions. +Inner hash keys are chat,discussion,email,files,homepage,roster. +Corresponding values are either on or off, depending on +whther this type of functionality is available for the group. + +=cut + +############################################### + +sub get_group_settings { + my ($groupinfo)=@_; + my $parser=HTML::TokeParser->new(\$groupinfo); + my $token; + my $tool = ''; + my %content=(); + while ($token=$parser->get_token) { + if ($token->[0] eq 'S') { + my $entry=$token->[1]; + if ($entry eq 'functions') { + %{$content{$entry}} = (); + $tool = $entry; + } else { + my $value=$parser->get_text('/'.$entry); + if ($entry eq 'name') { + if ($tool eq 'functions') { + my $function = $token->[2]{id}; + $content{$tool}{$function} = $value; + } + } elsif ($entry eq 'groupname') { + $content{$entry}=&Apache::lonnet::unescape($value); + } else { + $content{$entry}=$value; + } + } + } elsif ($token->[0] eq 'E') { + if ($token->[1] eq 'functions') { + $tool = ''; + } + } + } + return %content; +} + +sub check_group_access { + my ($group) = @_; + my $access = 1; + my $now = time; + my ($start,$end) = split(/\./,$env{'user.role.gr/'.$env{'request.course,id'}.'/'.$group}); + if (($end!=0) && ($end<$now)) { $access = 0; } + if (($start!=0) && ($start>$now)) { $access=0; } + return $access; +} + +############################################### + +=pod + +=item get_course_users + +Retrieves usernames:domains for users in the specified course +with specific role(s), and access status. + +Incoming parameters: +1. course domain +2. course number +3. access status: users must have - either active, +previous, future, or all. +4. reference to array of permissible roles +5. reference to array of section restrictions (optional) +6. reference to results object (hash of hashes). +7. reference to optional userdata hash +Keys of top level hash are roles. +Keys of inner hashes are username:domain, with +values set to access type. +Optional userdata hash returns an array with arguments in the +same order as loncoursedata::get_classlist() for student data. + +Entries for end, start, section and status are blank because +of the possibility of multiple values for non-student roles. + +=cut + +############################################### + +sub get_course_users { + my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_; + my %idx = (); + + $idx{udom} = &Apache::loncoursedata::CL_SDOM(); + $idx{uname} = &Apache::loncoursedata::CL_SNAME(); + $idx{end} = &Apache::loncoursedata::CL_END(); + $idx{start} = &Apache::loncoursedata::CL_START(); + $idx{id} = &Apache::loncoursedata::CL_ID(); + $idx{section} = &Apache::loncoursedata::CL_SECTION(); + $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME(); + $idx{status} = &Apache::loncoursedata::CL_STATUS(); + + if (grep(/^st$/,@{$roles})) { + my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum); + my $now = time; + foreach my $student (keys(%{$classlist})) { + my $match = 0; + if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) { + unless(grep(/^\Q$$classlist{$student}[$idx{section}]\E$/, + @{$sections})) { + next; + } + } + if (defined($$types{'active'})) { + if ($$classlist{$student}[$idx{status}] eq 'Active') { + push(@{$$users{st}{$student}},'active'); + $match = 1; + } + } + if (defined($$types{'previous'})) { + if ($$classlist{$student}[$idx{end}] <= $now) { + push(@{$$users{st}{$student}},'previous'); + $match = 1; + } + } + if (defined($$types{'future'})) { + if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) { + push(@{$$users{st}{$student}},'future'); + $match = 1; + } + } + if ($match && defined($userdata)) { + $$userdata{$student} = $$classlist{$student}; + } + } + } + if ((@{$roles} > 0) && (@{$roles} ne "st")) { + my @coursepersonnel = &Apache::lonnet::getkeys('nohist_userroles',$cdom,$cnum); + foreach my $person (@coursepersonnel) { + my $match = 0; + my ($role,$user) = ($person =~ /^([^:]*):([^:]+:[^:]+)/); + $user =~ s/:$//; + if (($role) && (grep(/^\Q$role\E$/,@{$roles}))) { + my ($uname,$udom,$usec) = split(/:/,$user); + if ($usec ne '' && (ref($sections) eq 'ARRAY') && + @{$sections} > 0) { + unless(grep(/^\Q$usec\E$/,@{$sections})) { + next; + } + } + if ($uname ne '' && $udom ne '') { + my $status = &check_user_status($udom,$uname,$cdom,$cnum,$role); + foreach my $type (keys(%{$types})) { + if ($status eq $type) { + @{$$users{$role}{$user}} = $type; + $match = 1; + } + } + if ($match && defined($userdata) && + !exists($$userdata{$uname.':'.$udom})) { + &get_user_info($udom,$uname,\%idx,$userdata); + } + } + } + } + if (grep(/^ow$/,@{$roles})) { + if ((defined($cdom)) && (defined($cnum))) { + my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum); + if ( defined($csettings{'internal.courseowner'}) ) { + my $owner = $csettings{'internal.courseowner'}; + @{$$users{'ow'}{$owner.':'.$cdom}} = 'any'; + if (defined($userdata) && + !exists($$userdata{$owner.':'.$cdom})) { + &get_user_info($cdom,$owner,\%idx,$userdata); + } + } + } + } + } + return; +} + +sub get_user_info { + my ($udom,$uname,$idx,$userdata) = @_; + $$userdata{$uname.':'.$udom}[$$idx{fullname}] = + &plainname($uname,$udom,'lastname'); + $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname; + $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom; + return; +} + +############################################### sub get_posted_cgi { my $r=shift; @@ -3066,7 +3444,6 @@ sub get_unprocessed_cgi { if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) { $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; - &Apache::lonxml::debug("Seting :$name: to :$value:"); unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) }; } } @@ -3109,6 +3486,7 @@ sub no_cache { sub content_type { my ($r,$type,$charset) = @_; + &no_cache($r); if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; } unless ($charset) { $charset=&Apache::lonlocal::current_encoding; @@ -3264,6 +3642,11 @@ Separate a record into fields $record sh =cut +sub takeleft { + my $index=shift; + return substr('0000'.$index,-4,4); +} + sub record_sep { my $record=shift; my %components=(); @@ -3274,7 +3657,7 @@ sub record_sep { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } elsif ($env{'form.upfiletype'} eq 'tab') { @@ -3283,7 +3666,7 @@ sub record_sep { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } else { @@ -3301,7 +3684,7 @@ sub record_sep { $field=~s/^\s*$delimiter//; $field=~s/$delimiter\s*$//; } - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } @@ -3458,9 +3841,9 @@ sub csv_samples_select_table { $display.''); } $r->print('
'); - if (defined($sone{$_})) { $r->print($sone{$_}."
\n"); } - if (defined($stwo{$_})) { $r->print($stwo{$_}."
\n"); } - if (defined($sthree{$_})) { $r->print($sthree{$_}."
\n"); } + if (defined($sone{$_})) { $r->print($sone{$_}."
\n"); } + if (defined($stwo{$_})) { $r->print($stwo{$_}."
\n"); } + if (defined($sthree{$_})) { $r->print($sthree{$_}."
\n"); } $r->print('