--- loncom/interface/loncommon.pm 2005/04/22 20:50:07 1.260 +++ loncom/interface/loncommon.pm 2006/04/07 21:56:00 1.327 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.260 2005/04/22 20:50:07 albertel Exp $ +# $Id: loncommon.pm,v 1.327 2006/04/07 21:56:00 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -58,7 +58,6 @@ use strict; use Apache::lonnet; use GDBM_File; use POSIX qw(strftime mktime); -use Apache::Constants qw(:common :http :methods); use Apache::lonmenu(); use Apache::lonlocal; use HTML::Entities; @@ -152,19 +151,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); @@ -330,7 +330,10 @@ sub storeresurl { sub studentbrowser_javascript { unless ( (($env{'request.course.id'}) && - (&Apache::lonnet::allowed('srm',$env{'request.course.id'}))) + (&Apache::lonnet::allowed('srm',$env{'request.course.id'}) + || &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + '/'.$env{'request.course.sec'}) + )) || ($env{'request.role'}=~/^(au|dc|su)/) ) { return ''; } return (<<'ENDSTDBRW'); @@ -361,7 +364,9 @@ ENDSTDBRW sub selectstudent_link { my ($form,$unameele,$udomele)=@_; if ($env{'request.course.id'}) { - unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) { + if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) + && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}. + '/'.$env{'request.course.sec'})) { return ''; } 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 +407,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,10 +421,35 @@ 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 @@ -673,7 +706,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,9 +716,10 @@ sub help_open_menu { my $template; if ($text ne "") { $template .= - "". - "
$text"; + "". + "'.$roleinfo.'
$text"; } + my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); my $html=&Apache::lonxml::xmlbegin(); my $helpicon=&lonhttpdurl("/adm/lonIcons/helpgateway.gif"); $template .= <<"ENDTEMPLATE"; @@ -698,7 +731,7 @@ function helpMenu(target) { if (target == 'open') { var newWindow = null; try { - newWindow = window.open("/adm/rat/empty.html","helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" ) + newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" ) } catch(error) { writeHelp(caller); @@ -712,9 +745,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() } @@ -1123,27 +1156,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; @@ -1539,10 +1594,11 @@ sub authform_nochange{ kerb_def_dom => 'MSU.EDU', @_, ); - my $result = &mt('[_1] Do not change login data', + my $result = ''; return $result; } @@ -1574,14 +1630,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; } @@ -1606,9 +1663,9 @@ sub authform_internal{ my $jscall = "javascript:changed_radio('int',$args{'formname'});"; my $result.=&mt ('[_1] Internally authenticated (with initial password [_2])', - '', - ''); return $result; } @@ -1633,9 +1690,9 @@ sub authform_local{ my $jscall = "javascript:changed_radio('loc',$in{'formname'});"; my $result.=&mt('[_1] Local Authentication with argument [_2]', - '', - ''); return $result; } @@ -1649,9 +1706,9 @@ sub authform_filesystem{ my $jscall = "javascript:changed_radio('fsys',$in{'formname'});"; my $result.= &mt ('[_1] Filesystem Authenticated (with initial password [_2])', - '', - ''); return $result; } @@ -1867,12 +1924,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'}, @@ -1903,19 +1959,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.'"'; @@ -1928,6 +1972,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 @@ -1984,24 +2042,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 @@ -2484,7 +2541,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 @@ -2679,6 +2736,15 @@ Inputs: =item * $forcereg, if page should register as content page (relevant for text interface only) +=item * $customtitle, alternate text to use instead of $title + in the title box that appears, this text + is not auto translated like the $title is + +=item * $notopbar, if true, keep the 'what is this' info but remove the + navigational links + +=item * $bgcolor, used to override the bg coor on a webpage to a specific value + =back Returns: A uniform header for LON-CAPA web pages. @@ -2689,11 +2755,12 @@ 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,$bgcolor)=@_; $title=&mt($title); $function = &get_users_function() if (!$function); my $img=&designparm($function.'.img',$domain); - my $pgbg=&designparm($function.'.pgbg',$domain); + my $pgbg= $bgcolor || &designparm($function.'.pgbg',$domain); my $tabbg=&designparm($function.'.tabbg',$domain); my $font=&designparm($function.'.font',$domain); my $link=&designparm($function.'.link',$domain); @@ -2725,15 +2792,19 @@ sub bodytag { END - if ($env{'environment.texengine'} eq 'jsMath') { - $bodytag.=''."\n". - ''."\n"; + &Apache::lontexconvert::jsMath_reset(); + if ($env{'environment.texengine'} eq 'jsMath' || + $env{'form.texengine'} eq 'jsMath' ) { + $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; } @@ -2824,6 +2903,8 @@ ENDROLE $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'}; $dc_info = '('.$dc_info.')'; } + # Explicit link to get inline menu + my $menu='
 '.&mt('Switch to Inline Menu Mode').''; # return(<
-$titleinfo $dc_info +$titleinfo $dc_info $menu $env{'environment.firstname'} @@ -2860,7 +2941,7 @@ ENDBODY =back -=head1 HTTP Helpers +=head1 HTML Helpers =over 4 @@ -2868,29 +2949,268 @@ ENDBODY Returns a uniform footer for LON-CAPA web pages. -Inputs: - -=over 4 +Inputs: none =back -Returns: A uniform footer for LON-CAPA web pages. - =cut sub endbodytag { my $endbodytag=''; - if ($env{'environment.texengine'} eq 'jsMath') { - $endbodytag=''. - "\n".$endbodytag; + $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag; + if ( exists( $env{'internal.head.redirect'} ) ) { + $endbodytag= + "
". + &mt('Continue').''. + $endbodytag; } return $endbodytag; } +=pod + +=over 4 + +=item * &headtag() + +Returns a uniform footer for LON-CAPA web pages. + +Inputs: $title - optional title for the head + $head_extra - optional extra HTML to put inside the + $args - optional arguments + force_register - if is true call registerurl so the remote is + informed + + redirect - array ref of seconds before redirect occurs + url to redirect to + (side effect of setting + $env{'internal.head.redirect'} to the url + redirected too) +=back + +=cut + +sub headtag { + my ($title,$head_extra,$args) = @_; + + my $result = + ''. + &Apache::lonxml::fontsettings(). + &Apache::lonhtmlcommon::htmlareaheaders(); + + if ($args->{'force_register'}) { + $result .= &Apache::lonmenu::registerurl(1); + } + + if (ref($args->{'redirect'})) { + my ($time,$url) = @{$args->{'redirect'}}; + $url = &Apache::lonenc::check_encrypt($url); + $env{'internal.head.redirect'} = $url; + $result.=< + +ADDMETA + } + if (!defined($title)) { + $title = 'The LearningOnline Network with CAPA'; + } + + $result .= ' LON-CAPA '.&mt($title).''.$head_extra; + return $result; +} + +=pod + +=over 4 + +=item * &endheadtag() + +Returns a uniform for LON-CAPA web pages. + +Inputs: none + +=back + +=cut + +sub endheadtag { + return ''; +} + +=pod + +=over 4 + +=item * &head() + +Returns a uniform complete .. section for LON-CAPA web pages. + +Inputs: $title - optional title for the page + $head_extra - optional extra HTML to put inside the +=back + +=cut + +sub head { + my ($title,$head_extra,$args) = @_; + return &headtag($title,$head_extra,$args).&endheadtag(); +} + +=pod + +=over 4 + +=item * &start_page() + +Returns a complete .. section for LON-CAPA web pages. + +Inputs: $title - optional title for the page + $head_extra - optional extra HTML to incude inside the + $args - additional optional args supported are: + only_body -> is true will set &bodytag() onlybodytag + arg on + no_nav_bar -> is true will set &bodytag() notopbar arg on + add_entries -> additional attributes to add to the + domain -> force to color decorate a page for a + specific domain + function -> force usage of a specific rolish color + scheme + redirect -> see &headtag() + bgcolor -> override the default page bg color + js_ready -> return a string ready for being used in + a javascript writeln + html_encode -> return a string ready for being used in + a html attribute + force_register -> if is true will turn on the &bodytag() + $forcereg arg + body_title -> alternate text to use instead of $title + in the title box that appears, this text + is not auto translated like the $title is + +=back + +=cut + +sub start_page { + my ($title,$head_extra,$args) = @_; + #&Apache::lonnet::logthis("start_page ".join(':',caller(0))); + my %head_args; + foreach my $arg ('redirect','force_register') { + if (defined($args->{$arg})) { + $head_args{$arg} = $args->{$arg}; + } + } + + $env{'internal.start_page'}++; + my $result = + &Apache::lonxml::xmlbegin(). + &headtag($title,$head_extra,\%head_args).&endheadtag(). + &bodytag($title, + $args->{'function'}, $args->{'add_entries'}, + $args->{'only_body'}, $args->{'domain'}, + $args->{'force_register'}, $args->{'body_title'}, + $args->{'no_nav_bar'}, $args->{'bgcolor'}); + if ($args->{'js_ready'}) { + $result = &js_ready($result); + } + if ($args->{'html_encode'}) { + $result = &html_encode($result); + } + return $result; +} + +=pod + +=over 4 + +=item * &head() + +Returns a complete section for LON-CAPA web pages. + +Inputs: $args - additional optional args supported are: + js_ready -> return a string ready for being used in + a javascript writeln + html_encode -> return a string ready for being used in + a html attribute +=back + +=cut + +sub end_page { + my ($args) = @_; + #&Apache::lonnet::logthis("end_page ".join(':',caller(0))); + $env{'internal.end_page'}++; + my $result = &endbodytag()."\n"; + if ($args->{'js_ready'}) { + $result = &js_ready($result); + } + if ($args->{'html_encode'}) { + $result = &html_encode($result); + } + return $result; +} + +sub html_encode { + my ($result) = @_; + + $result = &HTML::Entities::encode($result,'<>&"'); + + return $result; +} +sub js_ready { + my ($result) = @_; + + $result =~ s/[\n\r]/ /xmsg; + $result =~ s/\\/\\\\/xmsg; + $result =~ s/'/\\'/xmsg; + $result =~ s{}{}xmsg; + + return $result; +} + +sub validate_page { + if ( exists($env{'internal.start_page'}) + && $env{'internal.start_page'} > 1) { + &Apache::lonnet::logthis('start_page called multiple times '. + $env{'internal.start_page'}.' '. + $ENV{'request.filename'}); + } + if ( exists($env{'internal.end_page'}) + && $env{'internal.end_page'} > 1) { + &Apache::lonnet::logthis('end_page called multiple times '. + $env{'internal.end_page'}.' '. + $env{'request.filename'}); + } + if ( exists($env{'internal.start_page'}) + && ! exists($env{'internal.end_page'})) { + &Apache::lonnet::logthis('start_page called without end_page '. + $env{'request.filename'}); + } + if ( ! exists($env{'internal.start_page'}) + && exists($env{'internal.end_page'})) { + &Apache::lonnet::logthis('end_page called without start_page'. + $env{'request.filename'}); + } +} + +sub simple_error_page { + my ($r,$title,$msg) = @_; + my $page = + &Apache::loncommon::start_page($title). + &mt($msg). + &Apache::loncommon::end_page(); + if (ref($r)) { + $r->print($page); + return; + } + return $page; +} ############################################### =pod +=over 4 + =item get_users_function Used by &bodytag to determine the current users primary role. @@ -2918,6 +3238,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 @@ -2936,11 +3310,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) { @@ -2970,6 +3343,287 @@ 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 +whether 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 $role = ''; + my %content=(); + while ($token=$parser->get_token) { + if ($token->[0] eq 'S') { + my $entry=$token->[1]; + if ($entry eq 'functions' || $entry eq 'autosec') { + %{$content{$entry}} = (); + $tool = $entry; + } elsif ($entry eq 'role') { + if ($tool eq 'autosec') { + $role = $token->[2]{id}; + } + } 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); + } elsif (($entry eq 'roles') || ($entry eq 'types') || + ($entry eq 'sectionpick') || ($entry eq 'defpriv')) { + push(@{$content{$entry}},$value); + } elsif ($entry eq 'section') { + if ($tool eq 'autosec' && $role ne '') { + push(@{$content{$tool}{$role}},$value); + } + } else { + $content{$entry}=$value; + } + } + } elsif ($token->[0] eq 'E') { + if ($token->[1] eq 'functions' || $token->[1] eq 'autosec') { + $tool = ''; + } elsif ($token->[1] eq 'role') { + $role = ''; + } + + } + } + 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; @@ -3065,7 +3719,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) }; } } @@ -3108,6 +3761,10 @@ sub no_cache { sub content_type { my ($r,$type,$charset) = @_; + if ($r) { + # Note that printout.pl calls this with undef for $r. + &no_cache($r); + } if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; } unless ($charset) { $charset=&Apache::lonlocal::current_encoding; @@ -3263,6 +3920,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=(); @@ -3273,7 +3935,7 @@ sub record_sep { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } elsif ($env{'form.upfiletype'} eq 'tab') { @@ -3282,7 +3944,7 @@ sub record_sep { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } else { @@ -3300,7 +3962,7 @@ sub record_sep { $field=~s/^\s*$delimiter//; $field=~s/$delimiter\s*$//; } - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } @@ -3337,6 +3999,22 @@ sub upfile_select_html { return $Str; } +sub get_samples { + my ($records,$toget) = @_; + my @samples=({}); + my $got=0; + foreach my $rec (@$records) { + my %temp = &record_sep($rec); + if (! grep(/\S/, values(%temp))) { next; } + if (%temp) { + $samples[$got]=\%temp; + $got++; + if ($got == $toget) { last; } + } + } + return \@samples; +} + ###################################################### ###################################################### @@ -3354,18 +4032,15 @@ Apache Request ref, $records is an array ###################################################### sub csv_print_samples { my ($r,$records) = @_; - my (%sone,%stwo,%sthree); - %sone=&record_sep($$records[0]); - if (defined($$records[1])) {%stwo=&record_sep($$records[1]);} - if (defined($$records[2])) {%sthree=&record_sep($$records[2]);} - # + my $samples = &get_samples($records,3); + $r->print(&mt('Samples').'
'); - foreach (sort({$a <=> $b} keys(%sone))) { + foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) { $r->print(''); } $r->print(''); - foreach my $hash (\%sone,\%stwo,\%sthree) { + foreach my $hash (@$samples) { $r->print(''); - foreach (sort({$a <=> $b} keys(%sone))) { + foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) { $r->print(''); @@ -3394,8 +4069,8 @@ $d is an array of 2 element arrays (inte ###################################################### sub csv_print_select_table { my ($r,$records,$d) = @_; - my $i=0;my %sone; - %sone=&record_sep($$records[0]); + my $i=0; + my $samples = &get_samples($records,1); $r->print(&mt('Associate columns with student attributes.')."\n". '
'.&mt('Column [_1]',($_+1)).'
'); if (defined($$hash{$_})) { $r->print($$hash{$_}); } $r->print('
'. ''. @@ -3407,7 +4082,7 @@ sub csv_print_select_table { $r->print('
'.&mt('Attribute').''); - %sone=&record_sep($$records[0]); - if (defined($$records[1])) {%stwo=&record_sep($$records[1]);} - if (defined($$records[2])) {%sthree=&record_sep($$records[2]);} - # - foreach (sort keys %sone) { + + foreach my $key (sort(keys(%{ $samples->[0] }))) { $r->print(''); $i++; } @@ -3548,7 +4222,7 @@ the routine &Apache::lonnet::transfer_pr my $uniq=0; sub get_cgi_id { $uniq=($uniq+1)%100000; - return (time.'_'.$uniq); + return (time.'_'.$$.'_'.$uniq); } ############################################################ @@ -3968,13 +4642,14 @@ sub store_course_settings { # save to the environment # appenv the same items, just to be safe my $courseid = $env{'request.course.id'}; - my $coursedom = $env{'course.'.$courseid.'.domain'}; + my $udom = $env{'user.domain'}; + my $uname = $env{'user.name'}; my ($prefix,$Settings) = @_; my %SaveHash; my %AppHash; while (my ($setting,$type) = each(%$Settings)) { - my $basename = 'internal.'.$prefix.'.'.$setting; - my $envname = 'course.'.$courseid.'.'.$basename; + my $basename = join('.','internal',$courseid,$prefix,$setting); + my $envname = 'environment.'.$basename; if (exists($env{'form.'.$setting})) { # Save this value away if ($type eq 'scalar' && @@ -4002,8 +4677,7 @@ sub store_course_settings { } } my $put_result = &Apache::lonnet::put('environment',\%SaveHash, - $coursedom, - $env{'course.'.$courseid.'.num'}); + $udom,$uname); if ($put_result !~ /^(ok|delayed)/) { &Apache::lonnet::logthis('unable to save form parameters, '. 'got error:'.$put_result); @@ -4018,7 +4692,7 @@ sub restore_course_settings { my ($prefix,$Settings) = @_; while (my ($setting,$type) = each(%$Settings)) { next if (exists($env{'form.'.$setting})); - my $envname = 'course.'.$courseid.'.internal.'.$prefix. + my $envname = 'environment.internal.'.$courseid.'.'.$prefix. '.'.$setting; if (exists($env{$envname})) { if ($type eq 'scalar') {
'. &mt('Field').''.&mt('Samples').'
'); - if (defined($sone{$_})) { $r->print($sone{$_}."
\n"); } - if (defined($stwo{$_})) { $r->print($stwo{$_}."
\n"); } - if (defined($sthree{$_})) { $r->print($sthree{$_}."
\n"); } + foreach my $line (0..2) { + if (defined($samples->[$line]{$key})) { + $r->print($samples->[$line]{$key}."
\n"); + } + } $r->print('