--- loncom/interface/loncommon.pm 2015/04/01 23:22:10 1.1210 +++ loncom/interface/loncommon.pm 2015/05/21 23:40:09 1.1221 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1210 2015/04/01 23:22:10 raeburn Exp $ +# $Id: loncommon.pm,v 1.1221 2015/05/21 23:40:09 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -73,6 +73,7 @@ use Apache::courseclassifier(); use LONCAPA qw(:DEFAULT :match); use DateTime::TimeZone; use DateTime::Locale::Catalog; +use Encode(); use Text::Aspell; use Authen::Captcha; use Captcha::reCAPTCHA; @@ -535,7 +536,7 @@ ENDAUTHORBRW sub coursebrowser_javascript { my ($domainfilter,$sec_element,$formname,$role_element,$crstype, - $credits_element) = @_; + $credits_element,$instcode) = @_; my $wintitle = 'Course_Browser'; if ($crstype eq 'Community') { $wintitle = 'Community_Browser'; @@ -585,7 +586,10 @@ sub coursebrowser_javascript { if (formname == 'ccrs') { var ownername = document.forms[formid].ccuname.value; var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value; - url += '&cloner='+ownername+':'+ownerdom; + url += '&cloner='+ownername+':'+ownerdom+'&crscode='+document.forms[formid].crscode.value; + } + if (formname == 'requestcrs') { + url += '&crsdom=$domainfilter&crscode=$instcode'; } if (multflag !=null && multflag != '') { url += '&multiple='+multflag; @@ -983,6 +987,7 @@ sub select_datelocale { $locale_names{$id} = '('.$en_terr.')'; } } + $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id}); push (@possibles,$id); } } @@ -994,7 +999,7 @@ sub select_datelocale { } $output.=">$item"; if ($locale_names{$item} ne '') { - $output.=" $locale_names{$item}\n"; + $output.=' '.$locale_names{$item}; } $output.="\n"; } @@ -4040,8 +4045,13 @@ sub get_previous_attempt { my %lasthash=(); my $version; for ($version=1;$version<=$returnhash{'version'};$version++) { - foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) { - $lasthash{$key}=$returnhash{$version.':'.$key}; + foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) { + if ($key =~ /\.rawrndseed$/) { + my ($id) = ($key =~ /^(.+)\.rawrndseed$/); + $lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key}; + } else { + $lasthash{$key}=$returnhash{$version.':'.$key}; + } } } $prevattempts=&start_data_table().&start_data_table_header_row(); @@ -4161,9 +4171,15 @@ sub get_previous_attempt { } } else { if ($key =~ /\./) { - my $value = &format_previous_attempt_value($key, - $returnhash{$version.':'.$key}); - $prevattempts.=''.$value.' '; + my $value = $returnhash{$version.':'.$key}; + if ($key =~ /\.rndseed$/) { + my ($id) = ($key =~ /^(.+)\.[^.]+$/); + if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { + $value = $returnhash{$version.':'.$id.'.rawrndseed'}; + } + } + $prevattempts.=''.&format_previous_attempt_value($key,$value). + ' '; } else { $prevattempts.=' '; } @@ -4172,9 +4188,15 @@ sub get_previous_attempt { } else { foreach my $key (sort(keys(%lasthash))) { next if ($key =~ /\.foilorder$/); - my $value = &format_previous_attempt_value($key, - $returnhash{$version.':'.$key}); - $prevattempts.=''.$value.' '; + my $value = $returnhash{$version.':'.$key}; + if ($key =~ /\.rndseed$/) { + my ($id) = ($key =~ /^(.+)\.[^.]+$/); + if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { + $value = $returnhash{$version.':'.$id.'.rawrndseed'}; + } + } + $prevattempts.=''.&format_previous_attempt_value($key,$value). + ' '; } } $prevattempts.=&end_data_table_row(); @@ -4952,13 +4974,15 @@ END_MYBLOCK my $popupUrl = "/adm/blockingstatus/$querystring"; my $text = &mt('Communication Blocked'); + my $class = 'LC_comblock'; if ($activity eq 'docs') { $text = &mt('Content Access Blocked'); + $class = ''; } elsif ($activity eq 'printout') { $text = &mt('Printing Blocked'); } $output .= <<"END_BLOCK"; -
+
$text @@ -4979,17 +5003,39 @@ sub check_ip_acc { if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) { return 1; } - my $allowed=0; + my $allowed; my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip; my $name; - foreach my $pattern (split(',',$acc)) { - $pattern =~ s/^\s*//; - $pattern =~ s/\s*$//; + my %access = ( + allowfrom => 1, + denyfrom => 0, + ); + my @allows; + my @denies; + foreach my $item (split(',',$acc)) { + $item =~ s/^\s*//; + $item =~ s/\s*$//; + my $pattern; + if ($item =~ /^\!(.+)$/) { + push(@denies,$1); + } else { + push(@allows,$item); + } + } + my $numdenies = scalar(@denies); + my $numallows = scalar(@allows); + my $count = 0; + foreach my $pattern (@denies,@allows) { + $count ++; + my $acctype = 'allowfrom'; + if ($count <= $numdenies) { + $acctype = 'denyfrom'; + } if ($pattern =~ /\*$/) { #35.8.* $pattern=~s/\*//; - if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) { #35.8.3.[34-56] my $low=$2; @@ -4997,7 +5043,7 @@ sub check_ip_acc { $pattern=$1; if ($ip =~ /^\Q$pattern\E/) { my $last=(split(/\./,$ip))[3]; - if ($last <=$high && $last >=$low) { $allowed=1; } + if ($last <=$high && $last >=$low) { $allowed=$access{$acctype}; } } } elsif ($pattern =~ /^\*/) { #*.msu.edu @@ -5007,10 +5053,10 @@ sub check_ip_acc { my $netaddr=inet_aton($ip); ($name)=gethostbyaddr($netaddr,AF_INET); } - if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) { #127.0.0.1 - if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } } else { #some.name.com if (!defined($name)) { @@ -5018,9 +5064,16 @@ sub check_ip_acc { my $netaddr=inet_aton($ip); ($name)=gethostbyaddr($netaddr,AF_INET); } - if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } + } + if ($allowed =~ /^(0|1)$/) { last; } + } + if ($allowed eq '') { + if ($numdenies && !$numallows) { + $allowed = 1; + } else { + $allowed = 0; } - if ($allowed) { last; } } return $allowed; } @@ -6795,7 +6848,6 @@ div.LC_edit_problem_footer, div.LC_edit_problem_footer div, div.LC_edit_problem_editxml_header, div.LC_edit_problem_editxml_header div { - margin-top: 5px; z-index: 100; } @@ -6812,19 +6864,17 @@ table.LC_edit_problem_header_title { background: $tabbg; } -div.LC_edit_problem_discards { - float: left; -} - div.LC_edit_actionbar { - margin: -5px 0px 0px 0px !important; background-color: $sidebg; - height: 31px; + margin: 0; + padding: 0; + line-height: 200%; } -div.LC_edit_problem_saves { - float: right; - padding-bottom: 5px; +div.LC_edit_actionbar div{ + padding: 0; + margin: 0; + display: inline-block; } .LC_edit_opt { @@ -6931,6 +6981,10 @@ fieldset { /* overflow: hidden; */ } +article.geogebraweb div { + margin: 0; +} + fieldset > legend { font-weight: bold; padding: 0 5px 0 5px; @@ -7751,20 +7805,22 @@ ADDMETA $result.=< OFFLOAD } @@ -14358,34 +14414,90 @@ sub check_clone { (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) { $can_clone = 1; } else { - my %clonehash = &Apache::lonnet::get('environment',['cloners'], + my %clonehash = &Apache::lonnet::get('environment',['cloners','internal.coursecode'], $args->{'clonedomain'},$args->{'clonecourse'}); - my @cloners = split(/,/,$clonehash{'cloners'}); - if (grep(/^\*$/,@cloners)) { - $can_clone = 1; - } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { - $can_clone = 1; - } else { - my $ccrole = 'cc'; - if ($args->{'crstype'} eq 'Community') { - $ccrole = 'co'; + if ($clonehash{'cloners'} eq '') { + my %domdefs = &Apache::lonnet::get_domain_defaults($args->{'course_domain'}); + if ($domdefs{'canclone'}) { + unless ($domdefs{'canclone'} eq 'none') { + if ($domdefs{'canclone'} eq 'domain') { + if ($args->{'ccdomain'} eq $args->{'clonedomain'}) { + $can_clone = 1; + } + } elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && + ($args->{'clonedomain'} eq $args->{'course_domain'})) { + if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'}, + $clonehash{'internal.coursecode'},$args->{'crscode'})) { + $can_clone = 1; + } + } + } } - my %roleshash = - &Apache::lonnet::get_my_roles($args->{'ccuname'}, - $args->{'ccdomain'}, - 'userroles',['active'],[$ccrole], - [$args->{'clonedomain'}]); - if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { + } else { + my @cloners = split(/,/,$clonehash{'cloners'}); + if (grep(/^\*$/,@cloners)) { $can_clone = 1; - } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},$args->{'ccuname'},$args->{'ccdomain'})) { + } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { $can_clone = 1; - } else { - if ($args->{'crstype'} eq 'Community') { - $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); - } else { - $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } + unless ($can_clone) { + if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && ($args->{'clonedomain'} eq $args->{'course_domain'})) { + my (%gotdomdefaults,%gotcodedefaults); + foreach my $cloner (@cloners) { + if (($cloner ne '*') && ($cloner !~ /^\*\:$match_domain$/) && + ($cloner !~ /^$match_username\:$match_domain$/) && ($cloner ne '')) { + my (%codedefaults,@code_order); + if (ref($gotcodedefaults{$args->{'clonedomain'}}) eq 'HASH') { + if (ref($gotcodedefaults{$args->{'clonedomain'}}{'defaults'}) eq 'HASH') { + %codedefaults = %{$gotcodedefaults{$args->{'clonedomain'}}{'defaults'}}; + } + if (ref($gotcodedefaults{$args->{'clonedomain'}}{'order'}) eq 'ARRAY') { + @code_order = @{$gotcodedefaults{$args->{'clonedomain'}}{'order'}}; + } + } else { + &Apache::lonnet::auto_instcode_defaults($args->{'clonedomain'}, + \%codedefaults, + \@code_order); + $gotcodedefaults{$args->{'clonedomain'}}{'defaults'} = \%codedefaults; + $gotcodedefaults{$args->{'clonedomain'}}{'order'} = \@code_order; + } + if (@code_order > 0) { + if (&Apache::lonnet::check_instcode_cloning(\%codedefaults,\@code_order, + $cloner,$clonehash{'internal.coursecode'}, + $args->{'crscode'})) { + $can_clone = 1; + last; + } + } + } + } } - } + unless ($can_clone) { + my $ccrole = 'cc'; + if ($args->{'crstype'} eq 'Community') { + $ccrole = 'co'; + } + my %roleshash = + &Apache::lonnet::get_my_roles($args->{'ccuname'}, + $args->{'ccdomain'}, + 'userroles',['active'],[$ccrole], + [$args->{'clonedomain'}]); + if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || + (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { + $can_clone = 1; + } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'}, + $args->{'ccuname'},$args->{'ccdomain'})) { + $can_clone = 1; + } + } + } + } + unless ($can_clone) { + if ($args->{'crstype'} eq 'Community') { + $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } else { + $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } } } } @@ -15598,11 +15710,18 @@ cloneruname - optional username of new c clonerudom - optional domain of new course owner -domcloner - Optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, +domcloner - optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, (used when DC is using course creation form) codetitles - reference to array of titles of components in institutional codes (official courses). +cc_clone - escaped comma separated list of courses for which course cloner has active CC role + (and so can clone automatically) + +reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone + +reqinstcode - institutional code of new course, where search_courses is used to identify potential + courses to clone Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type. @@ -15613,7 +15732,8 @@ Side Effects: None sub search_courses { - my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_; + my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles, + $cc_clone,$reqcrsdom,$reqinstcode) = @_; my (%courses,%showcourses,$cloner); if (($filter->{'ownerfilter'} ne '') || ($filter->{'ownerdomfilter'} ne '')) { @@ -15661,10 +15781,10 @@ sub search_courses { $filter->{'combownerfilter'}, $filter->{'coursefilter'}, undef,undef,$type,$regexpok,undef,undef, - undef,undef,$cloner,$env{'form.cc_clone'}, + undef,undef,$cloner,$cc_clone, $filter->{'cloneableonly'}, $createdbefore,$createdafter,undef, - $domcloner); + $domcloner,undef,$reqcrsdom,$reqinstcode); if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) { my $ccrole; if ($type eq 'Community') { @@ -15909,7 +16029,7 @@ sub update_content_constraints { my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'}); my %checkresponsetypes; foreach my $key (keys(%Apache::lonnet::needsrelease)) { - my ($item,$name,$value) = split(/:/,$key); + my ($item,$name,$value,$valmatch) = split(/:/,$key); if ($item eq 'resourcetag') { if ($name eq 'responsetype') { $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key} @@ -16222,7 +16342,7 @@ sub create_recaptcha { my $captcha = Captcha::reCAPTCHA->new; return $captcha->get_options_setter({theme => 'white'})."\n". $captcha->get_html($pubkey,undef,$use_ssl). - &mt('If either word is hard to read, [_1] will replace them.', + &mt('If the text is hard to read, [_1] will replace them.', 'reCAPTCHA refresh'). '

'; }