".
- "$text";
+ "".
+ "$text";
}
# Add the graphic
@@ -764,10 +782,10 @@ sub helpLatexCheatsheet {
}
return ''.
$addOther .
- &Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
+ &Apache::loncommon::help_open_topic("Greek_Symbols",&mt('Greek Symbols'),
undef,undef,600)
.' | '.
- &Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
+ &Apache::loncommon::help_open_topic("Other_Symbols",&mt('Other Symbols'),
undef,undef,600)
.' | ';
}
@@ -805,14 +823,10 @@ sub help_open_menu {
my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
= @_;
$stayOnPage = 0 if (not defined $stayOnPage);
- # formerly only used pop-up help (stayOnPage = 0)
+ # only use pop-up help (stayOnPage == 0)
# if environment.remote is on (using remote control UI)
- # if ($env{'browser.interface'} eq 'textual' ||
- # $env{'environment.remote'} eq 'off' ) {
- # $stayOnPage=1;
- #}
- # Now making pop-up help the default even with remote control
- if ($env{'browser.interface'} eq 'textual') {
+ if ($env{'browser.interface'} eq 'textual' ||
+ $env{'environment.remote'} eq 'off' ) {
$stayOnPage=1;
}
my $output;
@@ -834,15 +848,13 @@ sub help_open_menu {
sub top_nav_help {
my ($text) = @_;
-
$text = &mt($text);
-
- my $stayOnPage =
+ my $stay_on_page =
($env{'browser.interface'} eq 'textual' ||
$env{'environment.remote'} eq 'off' );
- my $link= ($stayOnPage) ? "javascript:helpMenu('display')"
+ my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
: "javascript:helpMenu('open')";
- my $banner_link = &update_help_link(undef,undef,undef,undef,$stayOnPage);
+ my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
my $title = &mt('Get help');
@@ -870,7 +882,7 @@ sub help_menu_js {
'js_ready' => 1,
'add_entries' => {
'border' => '0',
- 'rows' => "105,*",},});
+ 'rows' => "110,*",},});
my $end_page =
&Apache::loncommon::end_page({'frameset' => 1,
'js_ready' => 1,});
@@ -1084,6 +1096,138 @@ sub changable_area {
=pod
+=item * viewport_geometry_js {
+
+Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
+
+=cut
+
+
+sub viewport_geometry_js {
+ return <<"GEOMETRY";
+var Geometry = {};
+function init_geometry() {
+ if (Geometry.init) { return };
+ Geometry.init=1;
+ if (window.innerHeight) {
+ Geometry.getViewportHeight = function() { return window.innerHeight; };
+ Geometry.getViewportWidth = function() { return window.innerWidth; };
+ Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
+ Geometry.getVerticalScroll = function() { return window.pageYOffset; };
+ }
+ else if (document.documentElement && document.documentElement.clientHeight) {
+ Geometry.getViewportHeight =
+ function() { return document.documentElement.clientHeight; };
+ Geometry.getViewportWidth =
+ function() { return document.documentElement.clientWidth; };
+
+ Geometry.getHorizontalScroll =
+ function() { return document.documentElement.scrollLeft; };
+ Geometry.getVerticalScroll =
+ function() { return document.documentElement.scrollTop; };
+ }
+ else if (document.body.clientHeight) {
+ Geometry.getViewportHeight =
+ function() { return document.body.clientHeight; };
+ Geometry.getViewportWidth =
+ function() { return document.body.clientWidth; };
+ Geometry.getHorizontalScroll =
+ function() { return document.body.scrollLeft; };
+ Geometry.getVerticalScroll =
+ function() { return document.body.scrollTop; };
+ }
+}
+
+GEOMETRY
+}
+
+=pod
+
+=item * viewport_size_js {
+
+Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window.
+
+=cut
+
+sub viewport_size_js {
+ my $geometry = &viewport_geometry_js();
+ return <<"DIMS";
+
+$geometry
+
+function getViewportDims(width,height) {
+ init_geometry();
+ width.value = Geometry.getViewportWidth();
+ height.value = Geometry.getViewportHeight();
+ return;
+}
+
+DIMS
+}
+
+=pod
+
+=item * resize_textarea_js
+
+emits the needed javascript to resize a textarea to be as big as possible
+
+creates a function resize_textrea that takes two IDs first should be
+the id of the element to resize, second should be the id of a div that
+surrounds everything that comes after the textarea, this routine needs
+to be attached to the for the onload and onresize events.
+
+
+=cut
+
+sub resize_textarea_js {
+ my $geometry = &viewport_geometry_js();
+ return <<"RESIZE";
+
+RESIZE
+
+}
+
+=pod
+
=back
=head1 Excel and CSV file utility routines
@@ -1285,8 +1429,6 @@ sub domain_select {
=over 4
-=cut
-
=item * multiple_select_form($name,$value,$size,$hash,$order)
Returns a string containing a |
END_BLOCK
@@ -5735,7 +6540,157 @@ END_BLOCK
return $output;
}
+sub user_rule_check {
+ my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
+ my $response;
+ if (ref($usershash) eq 'HASH') {
+ foreach my $user (keys(%{$usershash})) {
+ my ($uname,$udom) = split(/:/,$user);
+ next if ($udom eq '' || $uname eq '');
+ my ($id,$newuser);
+ if (ref($usershash->{$user}) eq 'HASH') {
+ $newuser = $usershash->{$user}->{'newuser'};
+ $id = $usershash->{$user}->{'id'};
+ }
+ my $inst_response;
+ if (ref($checks) eq 'HASH') {
+ if (defined($checks->{'username'})) {
+ ($inst_response,%{$inst_results->{$user}}) =
+ &Apache::lonnet::get_instuser($udom,$uname);
+ } elsif (defined($checks->{'id'})) {
+ ($inst_response,%{$inst_results->{$user}}) =
+ &Apache::lonnet::get_instuser($udom,undef,$id);
+ }
+ } else {
+ ($inst_response,%{$inst_results->{$user}}) =
+ &Apache::lonnet::get_instuser($udom,$uname);
+ return;
+ }
+ if (!$got_rules->{$udom}) {
+ my %domconfig = &Apache::lonnet::get_dom('configuration',
+ ['usercreation'],$udom);
+ if (ref($domconfig{'usercreation'}) eq 'HASH') {
+ foreach my $item ('username','id') {
+ if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
+ $$curr_rules{$udom}{$item} =
+ $domconfig{'usercreation'}{$item.'_rule'};
+ }
+ }
+ }
+ $got_rules->{$udom} = 1;
+ }
+ foreach my $item (keys(%{$checks})) {
+ if (ref($$curr_rules{$udom}) eq 'HASH') {
+ if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
+ if (@{$$curr_rules{$udom}{$item}} > 0) {
+ my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
+ foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
+ if ($rule_check{$rule}) {
+ $$rulematch{$user}{$item} = $rule;
+ if ($inst_response eq 'ok') {
+ if (ref($inst_results) eq 'HASH') {
+ if (ref($inst_results->{$user}) eq 'HASH') {
+ if (keys(%{$inst_results->{$user}}) == 0) {
+ $$alerts{$item}{$udom}{$uname} = 1;
+ }
+ }
+ }
+ }
+ last;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+sub user_rule_formats {
+ my ($domain,$domdesc,$curr_rules,$check) = @_;
+ my %text = (
+ 'username' => 'Usernames',
+ 'id' => 'IDs',
+ );
+ my $output;
+ my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
+ if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
+ if (@{$ruleorder} > 0) {
+ $output = ' '.&mt("$text{$check} with the following format(s) may only be used for verified users at [_1]:",$domdesc).' ';
+ foreach my $rule (@{$ruleorder}) {
+ if (ref($curr_rules) eq 'ARRAY') {
+ if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
+ if (ref($rules->{$rule}) eq 'HASH') {
+ $output .= '- '.$rules->{$rule}{'name'}.': '.
+ $rules->{$rule}{'desc'}.'
';
+ }
+ }
+ }
+ }
+ $output .= ' ';
+ }
+ }
+ return $output;
+}
+sub instrule_disallow_msg {
+ my ($checkitem,$domdesc,$count,$mode) = @_;
+ my $response;
+ my %text = (
+ item => 'username',
+ items => 'usernames',
+ match => 'matches',
+ do => 'does',
+ action => 'a username',
+ one => 'one',
+ );
+ if ($count > 1) {
+ $text{'item'} = 'usernames';
+ $text{'match'} ='match';
+ $text{'do'} = 'do';
+ $text{'action'} = 'usernames',
+ $text{'one'} = 'ones';
+ }
+ if ($checkitem eq 'id') {
+ $text{'items'} = 'IDs';
+ $text{'item'} = 'ID';
+ $text{'action'} = 'an ID';
+ if ($count > 1) {
+ $text{'item'} = 'IDs';
+ $text{'action'} = 'IDs';
+ }
+ }
+ $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1], but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).' ';
+ if ($mode eq 'upload') {
+ if ($checkitem eq 'username') {
+ $response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+ } elsif ($checkitem eq 'id') {
+ $response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the ID/Student Number field.");
+ }
+ } else {
+ if ($checkitem eq 'username') {
+ $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+ } elsif ($checkitem eq 'id') {
+ $response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
+ }
+ }
+ return $response;
+}
+
+sub personal_data_fieldtitles {
+ my %fieldtitles = &Apache::lonlocal::texthash (
+ id => 'Student/Employee ID',
+ permanentemail => 'E-mail address',
+ lastname => 'Last Name',
+ firstname => 'First Name',
+ middlename => 'Middle Name',
+ generation => 'Generation',
+ gen => 'Generation',
+ );
+ return %fieldtitles;
+}
=pod
@@ -5994,28 +6949,50 @@ sub record_sep {
$i++;
}
} else {
- my @allfields;
+ my $separator=',';
if ($env{'form.upfiletype'} eq 'semisv') {
- @allfields=split(/;/,$record,-1);
- } else {
- @allfields=split(/\,/,$record,-1);
+ $separator=';';
}
my $i=0;
- my $j;
- for ($j=0;$j<=$#allfields;$j++) {
- my $field=$allfields[$j];
- if ($field=~/^\s*(\"|\')/) {
- my $delimiter=$1;
- while (($field!~/$delimiter$/) && ($j<$#allfields)) {
- $j++;
- $field.=','.$allfields[$j];
- }
- $field=~s/^\s*$delimiter//;
- $field=~s/$delimiter\s*$//;
- }
- $components{&takeleft($i)}=$field;
- $i++;
+# the character we are looking for to indicate the end of a quote or a record
+ my $looking_for=$separator;
+# do not add the characters to the fields
+ my $ignore=0;
+# we just encountered a separator (or the beginning of the record)
+ my $just_found_separator=1;
+# store the field we are working on here
+ my $field='';
+# work our way through all characters in record
+ foreach my $character ($record=~/(.)/g) {
+ if ($character eq $looking_for) {
+ if ($character ne $separator) {
+# Found the end of a quote, again looking for separator
+ $looking_for=$separator;
+ $ignore=1;
+ } else {
+# Found a separator, store away what we got
+ $components{&takeleft($i)}=$field;
+ $i++;
+ $just_found_separator=1;
+ $ignore=0;
+ $field='';
+ }
+ next;
+ }
+# single or double quotation marks after a separator indicate beginning of a quote
+# we are now looking for the end of the quote and need to ignore separators
+ if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
+ $looking_for=$character;
+ next;
+ }
+# ignore would be true after we reached the end of a quote
+ if ($ignore) { next; }
+ if (($just_found_separator) && ($character=~/\s/)) { next; }
+ $field.=$character;
+ $just_found_separator=0;
}
+# catch the very last entry, since we never encountered the separator
+ $components{&takeleft($i)}=$field;
}
return %components;
}
@@ -6086,20 +7063,21 @@ sub csv_print_samples {
my ($r,$records) = @_;
my $samples = &get_samples($records,3);
- $r->print(&mt('Samples').'
');
+ $r->print(&mt('Samples').' '.&start_data_table().
+ &start_data_table_header_row());
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
$r->print(''.&mt('Column [_1]',($sample+1)).' | '); }
- $r->print(' ');
+ $r->print(&end_data_table_header_row());
foreach my $hash (@$samples) {
- $r->print('');
+ $r->print(&start_data_table_row());
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
$r->print('');
if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
$r->print(' | ');
}
- $r->print(' ');
+ $r->print(&end_data_table_row());
}
- $r->print('
'."\n");
+ $r->print(&end_data_table().' '."\n");
}
######################################################
@@ -6124,12 +7102,13 @@ sub csv_print_select_table {
my $i=0;
my $samples = &get_samples($records,1);
$r->print(&mt('Associate columns with student attributes.')."\n".
- ''.
+ &start_data_table().&start_data_table_header_row().
''.&mt('Attribute').' | '.
- ''.&mt('Column').' | '."\n");
+ ''.&mt('Column').' | '.
+ &end_data_table_header_row()."\n");
foreach my $array_ref (@$d) {
my ($value,$display,$defaultcol)=@{ $array_ref };
- $r->print(''.$display.' | ');
+ $r->print(&start_data_table_row().' '.$display.' | ');
$r->print('');
@@ -6139,9 +7118,10 @@ sub csv_print_select_table {
($sample eq $defaultcol ? ' selected="selected" ' : '').
'>Column '.($sample+1).'');
}
- $r->print(' | '."\n");
+ $r->print(''.&end_data_table_row()."\n");
$i++;
}
+ $r->print(&end_data_table());
$i--;
return $i;
}
@@ -6168,11 +7148,13 @@ sub csv_samples_select_table {
my $i=0;
#
my $samples = &get_samples($records,3);
- $r->print(''.
- &mt('Field').' | '.&mt('Samples').' | ');
+ $r->print(&start_data_table().
+ &start_data_table_header_row().''.
+ &mt('Field').' | '.&mt('Samples').' | '.
+ &end_data_table_header_row());
foreach my $key (sort(keys(%{ $samples->[0] }))) {
- $r->print('print(&start_data_table_row().'');
foreach my $option (@$d) {
my ($value,$display,$defaultcol)=@{ $option };
@@ -6186,9 +7168,10 @@ sub csv_samples_select_table {
$r->print($samples->[$line]{$key}." \n");
}
}
- $r->print(' | | ');
+ $r->print(''.&end_data_table_row());
$i++;
}
+ $r->print(&end_data_table());
$i--;
return($i);
}
@@ -6687,6 +7670,8 @@ a hash ref describing the data to be sto
Returns: both routines return nothing
+=back
+
=cut
#######################################################
@@ -6767,12 +7752,82 @@ sub restore_settings {
}
}
+#######################################################
+#######################################################
+
+=pod
+
+=head1 Domain E-mail Routines
+
+=over 4
+
+=item &build_recipient_list
+
+Build recipient lists for three types of e-mail:
+(a) Error Reports, (b) Package Updates, (c) Help requests, generated by
+lonerrorhandler.pm, CHECKRPMS and lonsupportreq.pm respectively.
+
+Inputs:
+defmail (scalar - email address of default recipient),
+mailing type (scalar - errormail, packagesmail, or helpdeskmail),
+defdom (domain for which to retrieve configuration settings),
+origmail (scalar - email address of recipient from loncapa.conf,
+i.e., predates configuration by DC via domainprefs.pm
+
+Returns: comma separated list of addresses to which to send e-mail.
+
+=cut
+
+############################################################
+############################################################
+sub build_recipient_list {
+ my ($defmail,$mailing,$defdom,$origmail) = @_;
+ my @recipients;
+ my $otheremails;
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
+ if (ref($domconfig{'contacts'}) eq 'HASH') {
+ if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
+ my @contacts = ('adminemail','supportemail');
+ foreach my $item (@contacts) {
+ if ($domconfig{'contacts'}{$mailing}{$item}) {
+ my $addr = $domconfig{'contacts'}{$item};
+ if (!grep(/^\Q$addr\E$/,@recipients)) {
+ push(@recipients,$addr);
+ }
+ }
+ $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
+ }
+ }
+ } elsif ($origmail ne '') {
+ push(@recipients,$origmail);
+ }
+ if ($defmail ne '') {
+ push(@recipients,$defmail);
+ }
+ if ($otheremails) {
+ my @others;
+ if ($otheremails =~ /,/) {
+ @others = split(/,/,$otheremails);
+ } else {
+ push(@others,$otheremails);
+ }
+ foreach my $addr (@others) {
+ if (!grep(/^\Q$addr\E$/,@recipients)) {
+ push(@recipients,$addr);
+ }
+ }
+ }
+ my $recipientlist = join(',',@recipients);
+ return $recipientlist;
+}
+
############################################################
############################################################
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(
@@ -6793,8 +7848,8 @@ sub commit_standardrole {
my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
$one,$two,$sec,$context);
if (($result =~ /^error/) || ($result eq 'not_in_class') ||
- ($result eq 'unknown_course')) {
- $output = "Error: $result\n";
+ ($result eq 'unknown_course') || ($result eq 'refused')) {
+ $output = $logmsg.' '.&mt('Error: ').$result."\n";
} else {
$output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
@@ -6823,7 +7878,7 @@ sub commit_standardrole {
sub commit_studentrole {
my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
- my ($result,$linefeed);
+ my ($result,$linefeed,$oldsecurl,$newsecurl);
if ($context eq 'auto') {
$linefeed = "\n";
} else {
@@ -6835,15 +7890,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;
}
- $expire_role_result = &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',time);
+ $oldsecurl = $uurl;
+ $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;
}
}
@@ -6851,21 +7927,55 @@ 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 .= "Section for $uname switched from old section: $oldsec to new section: $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 .= "New student role for $uname in section $sec in course $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 .= "Student $uname assigned to unchanged section $sec in course $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 .= "Error when attempting section change for $uname from old section $oldsec to new section: $sec in course $cid -error: $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 .= "Error when attempting to expire role for $uname in old section $oldsec in course $cid -error: $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;
+ if ($sec ne '') {
+ $newsecurl.='/'.$sec;
+ }
+ if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
+ if ($sec eq '') {
+ $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments unaffiliated with any section.',$sec).$linefeed;
+ } else {
+ $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$sec).$linefeed;
+ }
+ }
+ }
}
} else {
- $$logmsg .= "Incomplete course id defined. Addition of user $uname from domain $udom to course $one\_$two, section $sec not completed.$linefeed";
+ $$logmsg .= &mt('Incomplete course id defined.').$linefeed.&mt('Addition of user [_1] from domain [_2] to course [_3], section [_4] not completed.',$uname,$udom,$one.'_'.$two,$sec).$linefeed;
$result = "error: incomplete course id\n";
}
return $result;
@@ -6874,6 +7984,45 @@ sub commit_studentrole {
############################################################
############################################################
+sub check_clone {
+ my ($args,$linefeed) = @_;
+ my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
+ my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
+ my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
+ my $clonemsg;
+ my $can_clone = 0;
+
+ if ($clonehome eq 'no_host') {
+ $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
+ } else {
+ my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
+ if ($env{'request.role.domain'} eq $args->{'clonedomain'}) {
+ $can_clone = 1;
+ } else {
+ my %clonehash = &Apache::lonnet::get('environment',['cloners'],
+ $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 %roleshash =
+ &Apache::lonnet::get_my_roles($args->{'ccuname'},
+ $args->{'ccdomain'},
+ 'userroles',['active'],['cc'],
+ [$args->{'clonedomain'}]);
+ if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
+ $can_clone = 1;
+ } 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'});
+ }
+ }
+ }
+ }
+ return ($can_clone, $clonemsg, $cloneid, $clonehome);
+}
+
sub construct_course {
my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context) = @_;
my $outcome;
@@ -6881,6 +8030,25 @@ sub construct_course {
if ($context eq 'auto') {
$linefeed = "\n";
}
+
+#
+# Are we cloning?
+#
+ my ($can_clone, $clonemsg, $cloneid, $clonehome);
+ if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
+ ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
+ if ($context ne 'auto') {
+ if ($clonemsg ne '') {
+ $clonemsg = ''.$clonemsg.'';
+ }
+ }
+ $outcome .= $clonemsg.$linefeed;
+
+ if (!$can_clone) {
+ return (0,$outcome);
+ }
+ }
+
#
# Open course
#
@@ -6901,81 +8069,46 @@ sub construct_course {
# if anyone ever decides to not show this, and Utils::Course::new
# will need to be suitably modified.
$outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
-
#
# Check if created correctly
#
($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
$outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
+
#
-# Are we cloning?
-#
- my $cloneid='';
- if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
- my $can_clone = 0;
- $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
- my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
- my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
- my $clonemsg;
- if ($clonehome eq 'no_host') {
- $clonemsg = &mt('Attempting to clone non-existing [_1]',$crstype);
- if ($context eq 'auto') {
- $outcome .= $clonemsg;
- } else {
- $outcome .= ''.$clonemsg.'';
- }
- $outcome .= $linefeed;
- } else {
- my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
- if ($env{'request.role.domain'} eq $args->{'form.clonedomain'}) {
- $can_clone = 1;
- } else {
- my %clonehash = &Apache::lonnet::get('environment',['cloners'],
- $args->{'clonedomain'},$args->{'clonecourse'});
- my @cloners = split(/,/,$clonehash{'cloners'});
- my %roleshash =
- &Apache::lonnet::get_my_roles($args->{'ccuname'},
- $args->{'ccdomain'},'userroles',['active'],['cc'],
- [$args->{'clonedomain'}]);
- if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
- $can_clone = 1;
- } else {
- $clonemsg = &mt('The new course was not cloned from an existing course because the course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
- if ($context eq 'auto') {
- $outcome .= $clonemsg;
- } else {
- $outcome .= ''.$clonemsg.'';
- }
- $outcome .= $linefeed;
- }
- }
- }
- if ($can_clone) {
- $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
- if ($context eq 'auto') {
- $outcome = $clonemsg;
- } else {
- $outcome .= ''.$clonemsg.'';
- }
- $outcome .= $linefeed;
- my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
+# Do the cloning
+#
+ if ($can_clone && $cloneid) {
+ $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
+ if ($context ne 'auto') {
+ $clonemsg = ''.$clonemsg.'';
+ }
+ $outcome .= $clonemsg.$linefeed;
+ my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
# Copy all files
- &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid);
+ &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid);
# Restore URL
- $cenv{'url'}=$oldcenv{'url'};
+ $cenv{'url'}=$oldcenv{'url'};
# Restore title
- $cenv{'description'}=$oldcenv{'description'};
-# restore grading mode
- if (defined($oldcenv{'grading'})) {
- $cenv{'grading'}=$oldcenv{'grading'};
- }
+ $cenv{'description'}=$oldcenv{'description'};
# Mark as cloned
- $cenv{'clonedfrom'}=$cloneid;
- delete($cenv{'default_enrollment_start_date'});
- delete($cenv{'default_enrollment_end_date'});
- }
+ $cenv{'clonedfrom'}=$cloneid;
+# 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);
}
+
#
# Set environment (will override cloned, if existing)
#
@@ -7061,7 +8194,7 @@ sub construct_course {
}
if ($args->{'notify_dc'}) {
if ($uname ne '') {
- push(@notified,$uname.'@'.$udom);
+ push(@notified,$uname.':'.$udom);
}
}
if (@notified > 0) {
@@ -7083,7 +8216,7 @@ sub construct_course {
' ('.$lt{'adby'}.')';
if ($context eq 'auto') {
$outcome .= $badclass_msg.$linefeed;
- $outcome .= ''.$badclass_msg.$linefeed.'
|