--- loncom/interface/loncommon.pm 2007/12/21 05:19:04 1.627 +++ loncom/interface/loncommon.pm 2008/03/28 21:05:28 1.651 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.627 2007/12/21 05:19:04 raeburn Exp $ +# $Id: loncommon.pm,v 1.651 2008/03/28 21:05:28 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -78,6 +78,76 @@ my $readit; ## Global Variables ## + +# ----------------------------------------------- SSI with retries: +# + +=pod + +=head1 Server Side include with retries: + +=over 4 + +=item * &ssi_with_retries(resource,retries form) + +Performs an ssi with some number of retries. Retries continue either +until the result is ok or until the retry count supplied by the +caller is exhausted. + +Inputs: + +=over 4 + +resource - Identifies the resource to insert. + +retries - Count of the number of retries allowed. + +form - Hash that identifies the rendering options. + +=back + +Returns: + +=over 4 + +content - The content of the response. If retries were exhausted this is empty. + +response - The response from the last attempt (which may or may not have been successful. + +=back + +=back + +=cut + +sub ssi_with_retries { + my ($resource, $retries, %form) = @_; + + + my $ok = 0; # True if we got a good response. + my $content; + my $response; + + # Try to get the ssi done. within the retries count: + + do { + ($content, $response) = &Apache::lonnet::ssi($resource, %form); + $ok = $response->is_success; + if (!$ok) { + &Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message); + } + $retries--; + } while (!$ok && ($retries > 0)); + + if (!$ok) { + $content = ''; # On error return an empty content. + } + return ($content, $response); + +} + + + # ----------------------------------------------- Filetypes/Languages/Copyright my %language; my %supported_language; @@ -214,14 +284,14 @@ BEGIN { =over 4 -=item * browser_and_searcher_javascript () +=item * &browser_and_searcher_javascript() XXReturns a string containing javascript with two functions, C and C. Returned string does not contain EscriptE tags. -=item * openbrowser(formname,elementname,only,omit) [javascript] +=item * &openbrowser(formname,elementname,only,omit) [javascript] inputs: formname, elementname, only, omit @@ -234,7 +304,7 @@ with the given extension. Can be a comm Specifying 'omit' will restrict the browser to NOT displaying files with the given extension. Can be a comma separated list. -=item * opensearcher(formname, elementname) [javascript] +=item * &opensearcher(formname,elementname) [javascript] Inputs: formname, elementname @@ -319,7 +389,7 @@ sub storeresurl { unless ($resurl=~/^\/res/) { return 0; } $resurl=~s/\/$//; &Apache::lonnet::put('environment',{'lastresurl' => $resurl}); - &Apache::lonnet::appenv('environment.lastresurl' => $resurl); + &Apache::lonnet::appenv({'environment.lastresurl' => $resurl}); return 1; } @@ -472,7 +542,10 @@ sub setsec_javascript { my ($sec_element,$formname) = @_; my $setsections = qq| function setSect(sectionlist) { - var sectionsArray = sectionlist.split(","); + var sectionsArray = new Array(); + if ((sectionlist != '') && (typeof sectionlist != "undefined")) { + sectionsArray = sectionlist.split(","); + } var numSections = sectionsArray.length; document.$formname.$sec_element.length = 0; if (numSections == 0) { @@ -539,7 +612,7 @@ ENDSCRT =pod -=item * linked_select_forms(...) +=item * &linked_select_forms(...) linked_select_forms returns a string containing a block and html for two element int multiple mode @@ -1476,7 +1548,7 @@ sub multiple_select_form { =pod -=item * select_form($defdom,$name,%hash) +=item * &select_form($defdom,$name,%hash) Returns a string containing a form to allow a user to select the domain to preform an operation in. @@ -1603,7 +1675,7 @@ sub select_dom_form { =pod -=item * home_server_form_item($domain,$name,$defaultflag) +=item * &home_server_form_item($domain,$name,$defaultflag) input: 4 arguments (two required, two optional) - $domain - domain of new user @@ -1763,14 +1835,12 @@ sub decode_user_agent { =over 4 -=item * authform_xxxxxx +=item * &authform_xxxxxx() The authform_xxxxxx subroutines provide javascript and html forms which handle some of the conveniences required for authentication forms. This is not an optimal method, but it works. -See loncreateuser.pm for invocation and use examples. - =over 4 =item * authform_header @@ -1787,7 +1857,7 @@ See loncreateuser.pm for invocation and =back -=back +See loncreateuser.pm for invocation and use examples. =cut @@ -2239,42 +2309,6 @@ sub get_assignable_auth { } ############################################################### -## Get Authentication Defaults for Domain ## -############################################################### - -=pod - -=head1 Domains and Authentication - -Returns default authentication type and an associated argument as -listed in file 'domain.tab'. - -=over 4 - -=item * get_auth_defaults - -get_auth_defaults($target_domain) returns the default authentication -type and an associated argument (initial password or a kerberos domain). -These values are stored in lonTabs/domain.tab - -($def_auth, $def_arg) = &get_auth_defaults($target_domain); - -If target_domain is not found in domain.tab, returns nothing (''). - -=cut - -#------------------------------------------- -sub get_auth_defaults { - my $domain=shift; - return (&Apache::lonnet::domain($domain,'auth_def'), - &Apache::lonnet::domain($domain,'auth_arg_def')); - -} -############################################################### -## End Get Authentication Defaults for Domain ## -############################################################### - -############################################################### ## Get Kerberos Defaults for Domain ## ############################################################### ## @@ -2286,22 +2320,31 @@ sub get_auth_defaults { =pod -=item * get_kerberos_defaults +=item * &get_kerberos_defaults() get_kerberos_defaults($target_domain) returns the default kerberos -version and domain. If not found in domain.tabs, it defaults to -version 4 and the domain of the server. +version and domain. If not found, it defaults to version 4 and the +domain of the server. + +=over 4 ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain); +=back + +=back + =cut #------------------------------------------- sub get_kerberos_defaults { my $domain=shift; - my ($krbdef,$krbdefdom) = - &Apache::loncommon::get_auth_defaults($domain); - unless ($krbdef =~/^krb/ && $krbdefdom) { + my ($krbdef,$krbdefdom); + my %domdefaults = &Apache::lonnet::get_domain_defaults($domain); + if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) { + $krbdef = $domdefaults{'auth_def'}; + $krbdefdom = $domdefaults{'auth_arg_def'}; + } else { $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/; my $krbdefdom=$1; $krbdefdom=~tr/a-z/A-Z/; @@ -2310,11 +2353,6 @@ sub get_kerberos_defaults { return ($krbdef,$krbdefdom); } -=pod - -=back - -=cut ############################################################### ## Thesaurus Functions ## @@ -2326,7 +2364,7 @@ sub get_kerberos_defaults { =over 4 -=item * initialize_keywords +=item * &initialize_keywords() Initializes the package variable %Keywords if it is empty. Uses the package variable $thesaurus_db_file. @@ -2371,7 +2409,7 @@ sub initialize_keywords { =pod -=item * keyword($word) +=item * &keyword($word) Returns true if $word is a keyword. A keyword is a word that appears more than the average number of times in the thesaurus database. Calls @@ -2392,7 +2430,7 @@ sub keyword { =pod -=item * get_related_words +=item * &get_related_words() Look up a word in the thesaurus. Takes a scalar argument and returns an array of words. If the keyword is not in the thesaurus, an empty array @@ -2450,7 +2488,7 @@ sub get_related_words { =over 4 -=item * plainname($uname,$udom,$first) +=item * &plainname($uname,$udom,$first) Takes a users logon name and returns it as a string in "first middle last generation" form @@ -2479,7 +2517,7 @@ sub plainname { # -------------------------------------------------------------------- Nickname =pod -=item * nickname($uname,$udom) +=item * &nickname($uname,$udom) Gets a users name and returns it as a string as @@ -2529,18 +2567,21 @@ sub getnames { } # -------------------------------------------------------------------- getemails + =pod -=item * getemails($uname,$udom) +=item * &getemails($uname,$udom) Gets a user's email information and returns it as a hash with keys: notification, critnotification, permanentemail For notification and critnotification, values are comma-separated lists -of e-mail address(es); for permanentemail, value is a single e-mail address. +of e-mail addresses; for permanentemail, value is a single e-mail address. + =cut + sub getemails { my ($uname,$udom)=@_; if ($udom eq 'public' && $uname eq 'public') { @@ -2575,7 +2616,7 @@ sub flush_email_cache { =pod -=item * screenname($uname,$udom) +=item * &screenname($uname,$udom) Gets a users screenname and returns it as a string @@ -2671,7 +2712,7 @@ sub student_image_tag { =over 4 -=item * languageids() +=item * &languageids() returns list of all language ids @@ -2683,7 +2724,7 @@ sub languageids { =pod -=item * languagedescription() +=item * &languagedescription() returns description of a specified language id @@ -2708,7 +2749,7 @@ sub supportedlanguagecode { =pod -=item * copyrightids() +=item * ©rightids() returns list of all copyrights @@ -2720,7 +2761,7 @@ sub copyrightids { =pod -=item * copyrightdescription() +=item * ©rightdescription() returns description of a specified copyright id @@ -2732,7 +2773,7 @@ sub copyrightdescription { =pod -=item * source_copyrightids() +=item * &source_copyrightids() returns list of all source copyrights @@ -2744,7 +2785,7 @@ sub source_copyrightids { =pod -=item * source_copyrightdescription() +=item * &source_copyrightdescription() returns description of a specified source copyright id @@ -2756,7 +2797,7 @@ sub source_copyrightdescription { =pod -=item * filecategories() +=item * &filecategories() returns list of all file categories @@ -2768,7 +2809,7 @@ sub filecategories { =pod -=item * filecategorytypes() +=item * &filecategorytypes() returns list of file types belonging to a given file category @@ -2782,7 +2823,7 @@ sub filecategorytypes { =pod -=item * fileembstyle() +=item * &fileembstyle() returns embedding style for a specified file type @@ -2806,7 +2847,7 @@ sub filecategoryselect { =pod -=item * filedescription() +=item * &filedescription() returns description for a specified file type @@ -2820,7 +2861,7 @@ sub filedescription { =pod -=item * filedescriptionex() +=item * &filedescriptionex() returns description for a specified file type with extra formatting @@ -2880,21 +2921,15 @@ sub preferred_languages { map { (split(/\s*;\s*/,$_))[0] } (split(/\s*,\s*/,$browser)); push(@languages,@browser); } - if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) { - @languages=(@languages, - &Apache::lonnet::domain($env{'user.domain'}, - 'lang_def')); - } - if (&Apache::lonnet::domain($env{'request.role.domain'},'lang_def')) { - @languages=(@languages, - &Apache::lonnet::domain($env{'request.role.domain'}, - 'lang_def')); - } - if (&Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'}, - 'lang_def')) { - @languages=(@languages, - &Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'}, - 'lang_def')); + + foreach my $domtype ($env{'user.domain'},$env{'request.role.domain'}, + $Apache::lonnet::perlvar{'lonDefDomain'}) { + if ($domtype ne '') { + my %domdefs = &Apache::lonnet::get_domain_defaults($domtype); + if ($domdefs{'lang_def'} ne '') { + push(@languages,$domdefs{'lang_def'}); + } + } } # turn "en-ca" into "en-ca,en" my @genlanguages; @@ -2944,7 +2979,7 @@ sub languages { =over 4 -=item * get_previous_attempt($symb, $username, $domain, $course, +=item * &get_previous_attempt($symb, $username, $domain, $course, $getattempt, $regexp, $gradesub) Return string with previous attempt on problem. Arguments: @@ -3088,7 +3123,7 @@ sub relative_to_absolute { =pod -=item * get_student_view +=item * &get_student_view() show a snapshot of what student was looking at @@ -3107,7 +3142,7 @@ sub get_student_view { } if (defined($target)) { $form{'grade_target'} = $target; } $feedurl=&Apache::lonnet::clutter($feedurl); - my $userview=&Apache::lonnet::ssi_body($feedurl,%form); + my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form); $userview=~s/\]*\>//gi; $userview=~s/\<\/body\>//gi; $userview=~s/\//gi; @@ -3116,12 +3151,44 @@ sub get_student_view { $userview=~s/\<\/head\>//gi; $userview=~s/action\s*\=/would_be_action\=/gi; $userview=&relative_to_absolute($feedurl,$userview); - return $userview; + if (wantarray) { + return ($userview,$response); + } else { + return $userview; + } +} + +sub get_student_view_with_retries { + my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_; + + my $ok = 0; # True if we got a good response. + my $content; + my $response; + + # Try to get the student_view done. within the retries count: + + do { + ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv); + $ok = $response->is_success; + if (!$ok) { + &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message); + } + $retries--; + } while (!$ok && ($retries > 0)); + + if (!$ok) { + $content = ''; # On error return an empty content. + } + if (wantarray) { + return ($content, $response); + } else { + return $content; + } } =pod -=item * get_student_answers() +=item * &get_student_answers() show a snapshot of how student was answering problem @@ -3667,45 +3734,78 @@ sub get_domainconf { my %domconfig = &Apache::lonnet::get_dom('configuration', ['login','rolecolors'],$udom); - my %designhash; + my (%designhash,%legacy); if (keys(%domconfig) > 0) { if (ref($domconfig{'login'}) eq 'HASH') { - foreach my $key (keys(%{$domconfig{'login'}})) { - $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key}; + if (keys(%{$domconfig{'login'}})) { + foreach my $key (keys(%{$domconfig{'login'}})) { + $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key}; + } + } else { + $legacy{'login'} = 1; } + } else { + $legacy{'login'} = 1; } if (ref($domconfig{'rolecolors'}) eq 'HASH') { - foreach my $role (keys(%{$domconfig{'rolecolors'}})) { - if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') { - foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) { - $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item}; + if (keys(%{$domconfig{'rolecolors'}})) { + foreach my $role (keys(%{$domconfig{'rolecolors'}})) { + if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') { + foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) { + $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item}; + } } } + } else { + $legacy{'rolecolors'} = 1; } + } else { + $legacy{'rolecolors'} = 1; } - } else { - my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; - my $designfile = $designdir.'/'.$udom.'.tab'; - if (-e $designfile) { - if ( open (my $fh,"<$designfile") ) { - while (my $line = <$fh>) { - next if ($line =~ /^\#/); - chomp($line); - my ($key,$val)=(split(/\=/,$line)); - if ($val) { $designhash{$udom.'.'.$key}=$val; } + if (keys(%legacy) > 0) { + my %legacyhash = &get_legacy_domconf($udom); + foreach my $item (keys(%legacyhash)) { + if ($item =~ /^\Q$udom\E\.login/) { + if ($legacy{'login'}) { + $designhash{$item} = $legacyhash{$item}; + } + } else { + if ($legacy{'rolecolors'}) { + $designhash{$item} = $legacyhash{$item}; + } } - close($fh); } } - if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') { - $designhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif"; - } + } else { + %designhash = &get_legacy_domconf($udom); } &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash, $cachetime); return %designhash; } +sub get_legacy_domconf { + my ($udom) = @_; + my %legacyhash; + my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; + my $designfile = $designdir.'/'.$udom.'.tab'; + if (-e $designfile) { + if ( open (my $fh,"<$designfile") ) { + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($key,$val)=(split(/\=/,$line)); + if ($val) { $legacyhash{$udom.'.'.$key}=$val; } + } + close($fh); + } + } + if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') { + $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif"; + } + return %legacyhash; +} + =pod =item * &domainlogo() @@ -3755,10 +3855,10 @@ Returns: value of designparamter $which sub designparm { my ($which,$domain)=@_; if ($env{'browser.blackwhite'} eq 'on') { - if ($which=~/\.(font|alink|vlink|link)$/) { + if ($which=~/\.(font|alink|vlink|link|textcol)$/) { return '#000000'; } - if ($which=~/\.(pgbg|sidebg)$/) { + if ($which=~/\.(pgbg|sidebg|bgcol)$/) { return '#FFFFFF'; } if ($which=~/\.tabbg$/) { @@ -3777,7 +3877,7 @@ sub designparm { $output = $defaultdesign{$which}; } if (($which =~ /^(student|coordinator|author|admin)\.img$/) || - ($which =~ /login\.(img|logo|domlogo)/)) { + ($which =~ /login\.(img|logo|domlogo|login)/)) { if ($output =~ m{^/(adm|res)/}) { if ($output =~ m{^/res/}) { my $local_name = &Apache::lonnet::filelocation('',$output); @@ -3945,7 +4045,7 @@ ENDROLE $dc_info = '('.$dc_info.')'; } - if ($env{'environment.remote'} eq 'off') { + if (($env{'environment.remote'} eq 'off') || ($args->{'suppress_header_logos'})) { # No Remote if ($env{'request.state'} eq 'construct') { $forcereg=1; @@ -3968,9 +4068,9 @@ ENDROLE $lastitem = $thisdisfn; } $titleinfo = - &Apache::loncommon::help_open_menu('','',3,'Authoring'). - 'Construction Space: '. - '
' .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."$lastitem
" .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()') @@ -4094,18 +4194,25 @@ sub make_attr_string { Returns a uniform footer for LON-CAPA web pages. -Inputs: none +Inputs: 1 - optional reference to an args hash +If in the hash, key for noredirectlink has a value which evaluates to true, +a 'Continue' link is not displayed if the page contains an +internal redirect in the section, +i.e., $env{'internal.head.redirect'} exists =cut sub endbodytag { + my ($args) = @_; my $endbodytag=''; $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag; if ( exists( $env{'internal.head.redirect'} ) ) { - $endbodytag= - "
". - &mt('Continue').''. - $endbodytag; + if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) { + $endbodytag= + "
". + &mt('Continue').''. + $endbodytag; + } } return $endbodytag; } @@ -4368,6 +4475,7 @@ td.LC_menubuttons_img { } .LC_new_mail { font-family: $sans; + background: $tabbg; font-weight: bold; } @@ -4454,6 +4562,10 @@ table.LC_aboutme_port tr.LC_even_row td table.LC_data_table tr.LC_data_table_highlight td { background-color: $data_table_darker; } +table.LC_data_table tr td.LC_leftcol_header { + background-color: $data_table_head; + font-weight: bold; +} table.LC_data_table tr.LC_empty_row td, table.LC_nested tr.LC_empty_row td { background-color: #FFFFFF; @@ -4729,6 +4841,14 @@ table.LC_pick_box td.LC_pick_box_title { width: 184px; padding: 8px; } +table.LC_pick_box td.LC_selfenroll_pick_box_title { + background: $tabbg; + font-weight: bold; + text-align: right; + width: 350px; + padding: 8px; +} + table.LC_pick_box td.LC_pick_box_value { text-align: left; padding: 8px; @@ -4943,6 +5063,11 @@ span.LC_cusr_emph { font-style: italic; } +span.LC_cusr_subheading { + font-weight: normal; + font-size: 85%; +} + table.LC_docs_documents { background: #BBBBBB; border-width: 0px; @@ -5268,10 +5393,7 @@ Inputs: none sub font_settings { my $headerstring=''; - if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) { - $headerstring.= - ''; - } elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) { + if (!$env{'browser.mathml'} && $env{'browser.unicode'}) { $headerstring.= ''; } @@ -5330,8 +5452,15 @@ sub endheadtag { 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 +Inputs: + +=over 4 + +$title - optional title for the page + +$head_extra - optional extra HTML to put inside the + +=back =cut @@ -5346,44 +5475,54 @@ sub head { 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 +Inputs: + +=over 4 + +$title - optional title for the page + +$head_extra - optional extra HTML to incude inside the + +$args - additional optional args supported are: + +=over 8 + + 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 + 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 + 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 + 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 + html_encode -> return a string ready for being used in a html attribute - force_register -> if is true will turn on the &bodytag() + force_register -> if is true will turn on the &bodytag() $forcereg arg - body_title -> alternate text to use instead of $title + 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 - frameset -> if true will start with a + frameset -> if true will start with a rather than - no_title -> if true the title bar won't be shown - skip_phases -> hash ref of + no_title -> if true the title bar won't be shown + skip_phases -> hash ref of head -> skip the generation body -> skip all generation - - no_inline_link -> if true and in remote mode, don't show the + no_inline_link -> if true and in remote mode, don't show the 'Switch To Inline Menu' link - - no_auto_mt_title -> prevent &mt()ing the title arg - - inherit_jsmath -> when creating popup window in a page, + no_auto_mt_title -> prevent &mt()ing the title arg + inherit_jsmath -> when creating popup window in a page, should it have jsmath forced on by the current page +=back + +=back + =cut sub start_page { @@ -5470,7 +5609,7 @@ sub end_page { if ($args->{'frameset'}) { $result .= ''; } else { - $result .= &endbodytag(); + $result .= &endbodytag($args); } $result .= "\n"; @@ -5848,6 +5987,8 @@ previous, future, or all. 6. reference to results object (hash of hashes). 7. reference to optional userdata hash 8. reference to optional statushash +9. flag if privileged users (except those set to unhide in + course settings) should be excluded Keys of top level results hash are roles. Keys of inner hashes are username:domain, with values set to access type. @@ -5864,7 +6005,7 @@ of the possibility of multiple values fo ############################################### sub get_course_users { - my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash) = @_; + my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_; my %idx = (); my %seclists; @@ -5940,6 +6081,17 @@ sub get_course_users { active => 'Active', future => 'Future', ); + my %nothide; + if ($hidepriv) { + my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum); + foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) { + if ($user !~ /:/) { + $nothide{join(':',split(/[\@]/,$user))}=1; + } else { + $nothide{$user} = 1; + } + } + } foreach my $person (sort(keys(%coursepersonnel))) { my $match = 0; my $secmatch = 0; @@ -5973,6 +6125,12 @@ sub get_course_users { $usec = 'none'; } if ($uname ne '' && $udom ne '') { + if ($hidepriv) { + if ((&Apache::lonnet::privileged($uname,$udom)) && + (!$nothide{$uname.':'.$udom})) { + next; + } + } if ($end > 0 && $end < $now) { $status = 'previous'; } elsif ($start > $now) { @@ -6620,6 +6778,72 @@ sub personal_data_fieldtitles { return %fieldtitles; } +sub sorted_inst_types { + my ($dom) = @_; + my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom); + my $othertitle = &mt('All users'); + if ($env{'request.course.id'}) { + $othertitle = 'any'; + } + my @types; + if (ref($order) eq 'ARRAY') { + @types = @{$order}; + } + if (@types == 0) { + if (ref($usertypes) eq 'HASH') { + @types = sort(keys(%{$usertypes})); + } + } + if (keys(%{$usertypes}) > 0) { + $othertitle = &mt('Other users'); + if ($env{'request.course.id'}) { + $othertitle = 'other'; + } + } + return ($othertitle,$usertypes,\@types); +} + +sub get_institutional_codes { + my ($settings,$allcourses,$LC_code) = @_; +# Get complete list of course sections to update + my @currsections = (); + my @currxlists = (); + my $coursecode = $$settings{'internal.coursecode'}; + + if ($$settings{'internal.sectionnums'} ne '') { + @currsections = split(/,/,$$settings{'internal.sectionnums'}); + } + + if ($$settings{'internal.crosslistings'} ne '') { + @currxlists = split(/,/,$$settings{'internal.crosslistings'}); + } + + if (@currxlists > 0) { + foreach (@currxlists) { + if (m/^([^:]+):(\w*)$/) { + unless (grep/^$1$/,@{$allcourses}) { + push @{$allcourses},$1; + $$LC_code{$1} = $2; + } + } + } + } + + if (@currsections > 0) { + foreach (@currsections) { + if (m/^(\w+):(\w*)$/) { + my $sec = $coursecode.$1; + my $lc_sec = $2; + unless (grep/^$sec$/,@{$allcourses}) { + push @{$allcourses},$sec; + $$LC_code{$sec} = $lc_sec; + } + } + } + } + return; +} + =pod =back @@ -6628,7 +6852,7 @@ sub personal_data_fieldtitles { =over 4 -=item * get_unprocessed_cgi($query,$possible_names) +=item * &get_unprocessed_cgi($query,$possible_names) Modify the %env hash to contain unprocessed CGI form parameters held in $query. The parameters listed in $possible_names (an array reference), @@ -6657,7 +6881,7 @@ sub get_unprocessed_cgi { =pod -=item * cacheheader() +=item * &cacheheader() returns cache-controlling header code @@ -6674,7 +6898,7 @@ sub cacheheader { =pod -=item * no_cache($r) +=item * &no_cache($r) specifies header code to not have cache @@ -6710,7 +6934,7 @@ sub content_type { =pod -=item * add_to_env($name,$value) +=item * &add_to_env($name,$value) adds $name to the %env hash with value $value, if $name already exists, the entry is converted to an array @@ -6737,7 +6961,7 @@ sub add_to_env { =pod -=item * get_env_multiple($name) +=item * &get_env_multiple($name) gets $name from the %env hash, it seemlessly handles the cases where multiple values may be defined and end up as an array ref. @@ -6769,7 +6993,7 @@ sub get_env_multiple { =over 4 -=item * upfile_store($r) +=item * &upfile_store($r) Store uploaded file, $r should be the HTTP Request object, needs $env{'form.upfile'} @@ -6799,7 +7023,7 @@ sub upfile_store { =pod -=item * load_tmp_file($r) +=item * &load_tmp_file($r) Load uploaded file from tmp, $r should be the HTTP Request object, needs $env{'form.datatoken'}, @@ -6823,7 +7047,7 @@ sub load_tmp_file { =pod -=item * upfile_record_sep() +=item * &upfile_record_sep() Separate uploaded file into records returns array of records, @@ -6845,7 +7069,7 @@ sub upfile_record_sep { =pod -=item * record_sep($record) +=item * &record_sep($record) Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'} @@ -6930,7 +7154,7 @@ sub record_sep { =pod -=item * upfile_select_html() +=item * &upfile_select_html() Return HTML code to select a file from the users machine and specify the file type. @@ -6977,7 +7201,7 @@ sub get_samples { =pod -=item * csv_print_samples($r,$records) +=item * &csv_print_samples($r,$records) Prints a table of sample values from each column uploaded $r is an Apache Request ref, $records is an arrayref from @@ -7013,7 +7237,7 @@ sub csv_print_samples { =pod -=item * csv_print_select_table($r,$records,$d) +=item * &csv_print_select_table($r,$records,$d) Prints a table to create associations between values and table columns. @@ -7059,7 +7283,7 @@ sub csv_print_select_table { =pod -=item * csv_samples_select_table($r,$records,$d) +=item * &csv_samples_select_table($r,$records,$d) Prints a table of sample values from the upload and can make associate samples to internal names. @@ -7109,7 +7333,7 @@ sub csv_samples_select_table { =pod -=item clean_excel_name($name) +=item * &clean_excel_name($name) Returns a replacement for $name which does not contain any illegal characters. @@ -7128,7 +7352,7 @@ sub clean_excel_name { =pod -=item * check_if_partid_hidden($id,$symb,$udom,$uname) +=item * &check_if_partid_hidden($id,$symb,$udom,$uname) Returns either 1 or undef @@ -7169,7 +7393,7 @@ sub check_if_partid_hidden { =over 4 -=item get_cgi_id +=item * &get_cgi_id() Inputs: none @@ -7193,7 +7417,7 @@ sub get_cgi_id { =pod -=item DrawBarGraph +=item * &DrawBarGraph() Facilitates the plotting of data in a (stacked) bar graph. Puts plot definition data into the users environment in order for @@ -7328,7 +7552,7 @@ sub DrawBarGraph { $ValuesHash{$id.'.'.$key} = $value; } # - &Apache::lonnet::appenv(%ValuesHash); + &Apache::lonnet::appenv(\%ValuesHash); return ''; } @@ -7337,7 +7561,7 @@ sub DrawBarGraph { =pod -=item DrawXYGraph +=item * &DrawXYGraph() Facilitates the plotting of data in an XY graph. Puts plot definition data into the users environment in order for @@ -7418,7 +7642,7 @@ sub DrawXYGraph { $ValuesHash{$id.'.'.$key} = $value; } # - &Apache::lonnet::appenv(%ValuesHash); + &Apache::lonnet::appenv(\%ValuesHash); return ''; } @@ -7427,7 +7651,7 @@ sub DrawXYGraph { =pod -=item DrawXYYGraph +=item * &DrawXYYGraph() Facilitates the plotting of data in an XY graph with two Y axes. Puts plot definition data into the users environment in order for @@ -7520,7 +7744,7 @@ sub DrawXYYGraph { $ValuesHash{$id.'.'.$key} = $value; } # - &Apache::lonnet::appenv(%ValuesHash); + &Apache::lonnet::appenv(\%ValuesHash); return ''; } @@ -7537,7 +7761,7 @@ Bad place for them but what the hell. =over 4 -=item &chartlink +=item * &chartlink() Returns a link to the chart for a specific student. @@ -7576,9 +7800,9 @@ sub chartlink { =over 4 -=item &restore_course_settings +=item * &restore_course_settings() -=item &store_course_settings +=item * &store_course_settings() Restores/Store indicated form parameters from the course environment. Will not overwrite existing values of the form parameters. @@ -7598,6 +7822,8 @@ a hash ref describing the data to be sto Returns: both routines return nothing +=back + =cut ####################################################### @@ -7650,7 +7876,7 @@ sub store_settings { 'got error:'.$put_result); } # Make sure these settings stick around in this session, too - &Apache::lonnet::appenv(%AppHash); + &Apache::lonnet::appenv(\%AppHash); return; } @@ -7687,7 +7913,7 @@ sub restore_settings { =over 4 -=item &build_recipient_list +=item * &build_recipient_list() Build recipient lists for three types of e-mail: (a) Error Reports, (b) Package Updates, (c) Help requests, generated by @@ -7753,7 +7979,7 @@ sub build_recipient_list { sub commit_customrole { my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_; - my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.'@'.$three.' in '.$url. + my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url. ($start?', '.&mt('starting').' '.localtime($start):''). ($end?', ending '.localtime($end):'').': '. &Apache::lonnet::assigncustomrole( @@ -7816,16 +8042,36 @@ sub commit_studentrole { my $secchange = 0; my $expire_role_result; my $modify_section_result; - unless ($oldsec eq '-1') { - unless ($sec eq $oldsec) { + if ($oldsec ne '-1') { + if ($oldsec ne $sec) { $secchange = 1; + my $now = time; my $uurl='/'.$cid; $uurl=~s/\_/\//g; if ($oldsec) { $uurl.='/'.$oldsec; } $oldsecurl = $uurl; - $expire_role_result = &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',time); + $expire_role_result = + &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now); + if ($env{'request.course.sec'} ne '') { + if ($expire_role_result eq 'refused') { + my @roles = ('st'); + my @statuses = ('previous'); + my @roledoms = ($one); + my $withsec = 1; + my %roleshash = + &Apache::lonnet::get_my_roles($uname,$udom,'userroles', + \@statuses,\@roles,\@roledoms,$withsec); + if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) { + my ($oldstart,$oldend) = + split(':',$roleshash{$two.':'.$one.':st:'.$oldsec}); + if ($oldend > 0 && $oldend <= $now) { + $expire_role_result = 'ok'; + } + } + } + } $result = $expire_role_result; } } @@ -7833,18 +8079,38 @@ sub commit_studentrole { $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid); if ($modify_section_result =~ /^ok/) { if ($secchange == 1) { - $$logmsg .= &mt('Section for [_1] switched from old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed; + if ($sec eq '') { + $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed; + } else { + $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed; + } } elsif ($oldsec eq '-1') { - $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; + if ($sec eq '') { + $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed; + } else { + $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; + } } else { - $$logmsg .= &mt('Student [_1] assigned to unchanged section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; + if ($sec eq '') { + $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed; + } else { + $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; + } } } else { - $$logmsg .= &mt('Error when attempting section change for [_1] from old section [_2] to new section: [_3] in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed; + if ($secchange) { + $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed; + } else { + $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed; + } } $result = $modify_section_result; } elsif ($secchange == 1) { - $$logmsg .= &mt('Error when attempting to expire role for [_1] in old section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed; + if ($oldsec eq '') { + $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed; + } else { + $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed; + } if ($expire_role_result eq 'refused') { my $newsecurl = '/'.$cid; $newsecurl =~ s/\_/\//g; @@ -7973,19 +8239,26 @@ sub construct_course { $outcome .= $clonemsg.$linefeed; my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); # Copy all files - &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); + &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'}); # Restore URL $cenv{'url'}=$oldcenv{'url'}; # Restore title $cenv{'description'}=$oldcenv{'description'}; -# restore grading mode - if (defined($oldcenv{'grading'})) { - $cenv{'grading'}=$oldcenv{'grading'}; - } # Mark as cloned $cenv{'clonedfrom'}=$cloneid; - delete($cenv{'default_enrollment_start_date'}); - delete($cenv{'default_enrollment_end_date'}); +# Need to clone grading mode + my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum); + $cenv{'grading'}=$newenv{'grading'}; +# Do not clone these environment entries + &Apache::lonnet::del('environment', + ['default_enrollment_start_date', + 'default_enrollment_end_date', + 'question.email', + 'policy.email', + 'comment.email', + 'pch.users.denied', + 'plc.users.denied'], + $$crsudom,$$crsunum); } # @@ -8013,7 +8286,6 @@ sub construct_course { } else { $cenv{'internal.courseowner'} = $args->{'curruser'}; } - my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner. if ($args->{'crssections'}) { $cenv{'internal.sectionnums'} = ''; @@ -8073,7 +8345,7 @@ sub construct_course { } if ($args->{'notify_dc'}) { if ($uname ne '') { - push(@notified,$uname.'@'.$udom); + push(@notified,$uname.':'.$udom); } } if (@notified > 0) {