\n".&mt("Full Name").": ".
- $name{'firstname'}.' '.$name{'middlename'}.' '
- .$name{'lastname'}.' '.$name{'generation'}.
- "
\n".&mt('Student/Employee ID').": ".$name{'id'}.'
';
- }
- @usersgroups = &Apache::lonnet::get_users_groups(
- $udom,$uname,$env{'request.course.id'});
- if (@usersgroups > 0) {
- unless (grep(/^\Q$cgroup\E$/,@usersgroups)) {
- $cgroup = $usersgroups[0];
+ $message .= "\n
\n".&mt('Full Name').': '
+ .$name{'firstname'}.' '.$name{'middlename'}.' '
+ .$name{'lastname'}.' '.$name{'generation'}
+ ."
\n".&mt('Student/Employee ID').': '.$name{'id'}.'
';
+ @usersgroups = &Apache::lonnet::get_users_groups(
+ $udom,$uname,$env{'request.course.id'});
+ if (@usersgroups > 0) {
+ unless (grep(/^\Q$cgroup\E$/,@usersgroups)) {
+ $cgroup = $usersgroups[0];
+ }
+ } else {
+ $cgroup = '';
}
}
}
@@ -2303,6 +2686,7 @@ sub assessparms {
my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
my ($got_chostname,$chostname,$cmajor,$cminor);
my $totalstored = 0;
+ my $totalskippeduser = 0;
my $now = time;
for (my $i=0;$i<=$#markers;$i++) {
my ($needsrelease,$needsnewer,$name);
@@ -2311,6 +2695,11 @@ sub assessparms {
}
if ($markers[$i] =~ /\&(6|5|4)$/) {
next if ($noeditgrp);
+ } elsif ($markers[$i] =~ /\&(3|2|1)$/) {
+ if ($uname eq '') {
+ $totalskippeduser ++;
+ next;
+ }
}
if ($markers[$i] =~ /^[\d.]+\&0_availablestudent\&(1|2|3)$/) {
my (@ok_slots,@fail_slots,@del_slots);
@@ -2388,9 +2777,27 @@ sub assessparms {
# ---------------------------------------------------------------- Done storing
if ($totalstored) {
$message.=''
+ .&mt('Changes for [quant,_1,parameter] saved.',$totalstored)
+ .'
'
.&mt('Changes can take up to 10 minutes before being active for all students.')
.&Apache::loncommon::help_open_topic('Caching')
.'
';
+ } else {
+ $message.='';
+ if ($uhome eq 'no_host') {
+ $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the username or ID was invalid.',
+ $totalskippeduser);
+ } elsif ($env{'form.userroles'} eq 'any') {
+ $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user does not have a course role.',
+ $totalskippeduser);
+ } else {
+ $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user is not a student.',
+ $totalskippeduser);
+ }
+ $message .= '
';
}
}
#----------------------------------------------- if all selected, fill in array
@@ -2413,13 +2820,20 @@ sub assessparms {
# ----- Start Parameter Selection
- # Hide parm selection?
+ # Hide parm selection and possibly table?
+ my ($tablejs,$tabledivsty);
+ if (((($env{'form.uname'} ne '') || ($env{'form.id'} ne '')) && ($uname eq '')) &&
+ ($env{'form.dis'}) && ($pssymb eq '')) {
+ $tablejs = 'document.getElementById('."'parmtable'".').style.display = "";';
+ $tabledivsty = ' style="display:none"';
+ }
$r->print(<
//
@@ -2531,6 +2945,7 @@ ENDPARMSELSCRIPT
if ($parm_permission->{'edit'}) {
undef($readonly);
}
+ $r->print('');
if ($parmlev eq 'full') {
#
@@ -2939,6 +3354,7 @@ ENDMAPONE
.''
);
} # end of $parmlev eq general
+ $r->print('
');
}
$r->print('');
$r->print(&Apache::loncommon::end_page());
@@ -3020,21 +3436,39 @@ sub storedata {
if ($key =~ /^form\.([a-z]+)\_(.+)$/) {
my $cmd=$1;
my $thiskey=$2;
- next if ($cmd eq 'setipallow' || $cmd eq 'setipdeny');
+ next if ($cmd eq 'setipallow' || $cmd eq 'setipdeny' || $cmd eq 'setdeeplink');
my ($tuname,$tudom)=&extractuser($thiskey);
my $tkey=$thiskey;
if ($tuname) {
$tkey=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
}
if ($cmd eq 'set' || $cmd eq 'datepointer' || $cmd eq 'dateinterval') {
- my ($data, $typeof, $text, $name, $valchk);
+ my ($data, $typeof, $text, $name, $valchk, $valmatch, $namematch);
if ($cmd eq 'set') {
$data=$env{$key};
+ $valmatch = '';
$valchk = $data;
$typeof=$env{'form.typeof_'.$thiskey};
$text = &mt('Saved modified parameter for');
if ($typeof eq 'string_questiontype') {
$name = 'type';
+ } elsif ($typeof eq 'string_deeplink') {
+ ($name) = ($typeof =~ /^string_(deeplink)$/);
+ my $stringmatch = &standard_string_matches($typeof);
+ if (ref($stringmatch) eq 'ARRAY') {
+ foreach my $item (@{$stringmatch}) {
+ if (ref($item) eq 'ARRAY') {
+ my ($regexpname,$pattern) = @{$item};
+ if ($pattern ne '') {
+ if ($data =~ /$pattern/) {
+ $valmatch = $regexpname;
+ $valchk = '';
+ last;
+ }
+ }
+ }
+ }
+ }
} elsif ($typeof eq 'string_lenient') {
$name = 'lenient';
} elsif ($typeof eq 'string_discussvote') {
@@ -3189,6 +3623,7 @@ sub listdata {
$tableopen=0;
my $foundkeys=0;
my %keyorder=&standardkeyorder();
+ my $readonlyall = $readonly;
my ($secidx,%grouphash);
if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
@@ -3249,6 +3684,9 @@ sub listdata {
my ($middle,$part,$name)=
($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s]+)\.(\w+)$/);
my $section=&mt('All Students');
+ $readonly = $readonlyall;
+ my $userscope;
+ my $showval = $$resourcedata{$thiskey};
if ($middle=~/^\[(.*)\]/) {
my $issection=$1;
if ($issection=~/^useropt\:($match_username)\:($match_domain)/) {
@@ -3261,6 +3699,7 @@ sub listdata {
}
}
$section=&mt('User').": ".&Apache::loncommon::plainname($1,$2);
+ $userscope = 1;
} else {
if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
if (exists($grouphash{$issection})) {
@@ -3325,8 +3764,13 @@ sub listdata {
''.&mt($parmitem).
' | ');
unless ($readonly) {
+ my $disabled;
+ if (($name eq 'availablestudent') &&
+ (($showval eq '') || ($userscope))) {
+ $disabled = ' disabled="disabled"';
+ }
$r->print(' | ');
+ $thiskey.'"'.$disabled.' />');
}
$r->print('');
$foundkeys++;
@@ -3354,6 +3798,9 @@ sub listdata {
$r->print(&date_interval_selector($thiskey,$name,
$$resourcedata{$thiskey},$readonly));
} elsif ($thistype =~ m/^string/) {
+ if ($name eq 'availablestudent') {
+ $readonly = 1;
+ }
$r->print(&string_selector($thistype,$thiskey,
$$resourcedata{$thiskey},$name,$readonly));
} else {
@@ -3524,6 +3971,221 @@ sub string_ip_selector {
return $output;
}
+sub string_deeplink_selector {
+ my ($thiskey, $showval, $readonly) = @_;
+ my (@components,%values,@current,%titles,%options,%optiontext,%defaults,
+ %selectnull,%domlti,%crslti,@possmenus);
+ @components = ('state','others','listing','scope','protect','menus','target');
+ %titles = &Apache::lonlocal::texthash (
+ state => 'Access status',
+ others => 'Hide other resources',
+ listing => 'In Contents and/or Gradebook',
+ scope => 'Access scope for link',
+ protect => 'Link protection',
+ menus => 'Menu Items Displayed',
+ target => 'Embedded?',
+ );
+ %options = (
+ state => ['only','off','both'],
+ others => ['hide','unhide'],
+ listing => ['full','absent','grades','details','datestatus'],
+ scope => ['res','map','rec'],
+ protect => ['none','key','ltid','ltic'],
+ menus => ['std','colls'],
+ target => ['_self','_top'],
+ );
+ %optiontext = &Apache::lonlocal::texthash (
+ only => 'deep only',
+ off => 'deeplink off',
+ both => 'regular + deep',
+ hide => 'Hidden',
+ unhide => 'Unhidden',
+ full => 'Listed (linked) in both',
+ absent => 'Not listed',
+ grades => 'Listed in grades only',
+ details => 'Listed (unlinked) in both',
+ datestatus => 'Listed (unlinked) inc. status in both',
+ res => 'resource only',
+ map => 'enclosing map/folder',
+ rec => 'recursive map/folder',
+ none => 'not in use',
+ key => 'key access',
+ ltic => 'LTI access (course)',
+ ltid => 'LTI access (domain)' ,
+ std => 'Standard (all menus)',
+ colls => 'Numbered collection',
+ _self => 'Embedded',
+ _top => 'Not embedded',
+ );
+ %selectnull = &Apache::lonlocal::texthash (
+ ltic => 'Select Launcher',
+ ltid => 'Select Launcher',
+ colls => 'Select',
+ );
+ if ($showval =~ /,/) {
+ %values=();
+ @current = split(/,/,$showval);
+ ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/);
+ ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/);
+ ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/);
+ ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/);
+ ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/);
+ ($values{'menus'}) = ($current[5] =~ /^(\d+)$/);
+ ($values{'target'}) = ($current[6] =~ /^(_self|_top)$/);
+ } else {
+ $defaults{'state'} = 'off',
+ $defaults{'others'} = 'unhide',
+ $defaults{'listing'} = 'full';
+ $defaults{'scope'} = 'res';
+ $defaults{'protect'} = 'none';
+ $defaults{'menus'} = '0';
+ $defaults{'target'} = '_top';
+ }
+ my $disabled;
+ if ($readonly) {
+ $disabled=' disabled="disabled"';
+ }
+ my %courselti =
+ &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'});
+ foreach my $item (keys(%courselti)) {
+ if (ref($courselti{$item}) eq 'HASH') {
+ $crslti{$item} = $courselti{$item}{'name'};
+ }
+ }
+ my %lti =
+ &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
+ 'linkprot');
+ foreach my $item (keys(%lti)) {
+ if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
+ $domlti{$item} = $lti{$item}{'name'};
+ }
+ }
+ if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
+ foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
+ my ($num,$value) = split(/\%/,$item);
+ if ($num =~ /^\d+$/) {
+ push(@possmenus,$num);
+ }
+ }
+ }
+
+ my $output = ''."\n";
+ return $output;
+}
+
{
my %strings =
@@ -3556,8 +4218,28 @@ my %strings =
'string_ip'
=> [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'],
['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']],
+ 'string_deeplink'
+ => [['on','Set choices for link protection, resource listing, access scope, shown menu items, and embedding']],
);
+my %stringmatches = (
+ 'string_ip'
+ => [['_allowfrom_','[^\!]+'],
+ ['_denyfrom_','\!']],
+ 'string_deeplink'
+ => [['on','^(only|off|both)\,(hide|unhide)\,(full|absent|grades|details|datestatus)\,(res|map|rec)\,(none|key\:\w+|ltic\:\d+|ltid\:\d+)\,(\d+|)\,_(self|top)$']],
+ );
+
+my %stringtypes = (
+ type => 'string_questiontype',
+ lenient => 'string_lenient',
+ retrypartial => 'string_yesno',
+ discussvote => 'string_discussvote',
+ examcode => 'string_examcode',
+ acc => 'string_ip',
+ deeplink => 'string_deeplink',
+ );
+
sub standard_string_options {
my ($string_type) = @_;
if (ref($strings{$string_type}) eq 'ARRAY') {
@@ -3566,6 +4248,14 @@ sub standard_string_options {
return;
}
+sub standard_string_matches {
+ my ($string_type) = @_;
+ if (ref($stringmatches{$string_type}) eq 'ARRAY') {
+ return $stringmatches{$string_type};
+ }
+ return;
+}
+
sub string_selector {
my ($thistype, $thiskey, $showval, $name, $readonly) = @_;
@@ -3599,6 +4289,8 @@ sub string_selector {
if ($thistype eq 'string_ip') {
return &string_ip_selector($thiskey,$showval,$readonly);
+ } elsif ($thistype eq 'string_deeplink') {
+ return &string_deeplink_selector($thiskey,$showval,$readonly);
}
my ($result,$disabled);
@@ -3708,9 +4400,22 @@ sub oldversion_warning {
#
sub dateshift {
- my ($shift)=@_;
+ my ($shift,$numchanges)=@_;
my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $sec = $env{'request.course.sec'};
+ my $secgrpregex;
+ if ($sec ne '') {
+ my @groups;
+ if ($env{'request.course.groups'} ne '') {
+ @groups = split(/:/,$env{'request.course.groups'});
+ }
+ if (@groups) {
+ $secgrpregex = '(?:'.join('|',($sec,@groups)).')';
+ } else {
+ $secgrpregex = $sec;
+ }
+ }
my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs);
# ugly retro fix for broken version of types
foreach my $key (keys %data) {
@@ -3725,7 +4430,11 @@ sub dateshift {
# go through all parameters and look for dates
foreach my $key (keys %data) {
if ($data{$key.'.type'}=~/^date_(start|end)$/) {
+ if ($sec ne '') {
+ next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./);
+ }
my $newdate=$data{$key}+$shift;
+ $$numchanges ++;
$storecontent{$key}=$newdate;
}
}
@@ -3759,7 +4468,10 @@ sub newoverview {
'.
&Apache::lonhtmlcommon::resize_scrollbox_js('params')."\n".
&showhide_js()."\n".
+ &validateparms_js()."\n".
+ &ipacc_boxes_js()."\n".
&done_proctor_js()."\n".
+ &deeplink_js()."\n".
'// ]]>
';
@@ -3768,7 +4480,7 @@ sub newoverview {
my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
$r->print($start_page.$breadcrumbs);
$r->print(<
+ | '.
''.
''.
- '');
+ '');
$r->print(&Apache::loncommon::end_page());
}
@@ -4116,20 +4843,54 @@ sub date_shift_two {
my ($r) = @_;
my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $sec = $env{'request.course.sec'};
&Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
text=>"Shifting Dates"});
my $start_page=&Apache::loncommon::start_page('Shift Dates');
my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
$r->print($start_page.$breadcrumbs);
my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted');
- $r->print(''.&mt('Shift Dates').'
'.
- ''.&mt('Shifting all dates such that [_1] becomes [_2]',
- &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
- &Apache::lonlocal::locallocaltime($timeshifted)).'
');
+ $r->print(''.&mt('Shift Dates').'
');
+ if ($sec ne '') {
+ my @groups;
+ if ($env{'request.course.groups'} ne '') {
+ @groups = split(/:/,$env{'request.course.groups'});
+ }
+ if (@groups) {
+ $r->print(''.
+ &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]",
+ &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
+ &Apache::lonlocal::locallocaltime($timeshifted)).
+ '
');
+ } else {
+ $r->print(''.
+ &mt("Shift dates set just for your section, such that [_1] becomes [_2]",
+ &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
+ &Apache::lonlocal::locallocaltime($timeshifted)).
+ '
');
+ }
+ } else {
+ $r->print(''.&mt('Shifting all dates such that [_1] becomes [_2]',
+ &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
+ &Apache::lonlocal::locallocaltime($timeshifted)).
+ '
');
+ }
my $delta=$timeshifted-$env{'form.timebase'};
- &dateshift($delta);
+ my $numchanges = 0;
+ my $result = &dateshift($delta,\$numchanges);
+ if ($result eq 'ok') {
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]',
+ $numchanges)));
+ } elsif ($result eq 'con_delayed') {
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]',
+ $numchanges)));
+ } else {
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1));
+ }
$r->print(
- &Apache::lonhtmlcommon::confirm_success(&mt('Done')).
'
'.
&Apache::lonhtmlcommon::actionbox(
[''.&mt('Content and Problem Settings').'']));
@@ -4944,6 +5705,12 @@ sub parm_change_log {
}
if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); }
}
+ my $numgroups = 0;
+ my @groups;
+ if ($env{'request.course.groups'} ne '') {
+ @groups = split(/:/,$env{'request.course.groups'});
+ $numgroups = scalar(@groups);
+ }
foreach my $id (sort
{
if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) {
@@ -4984,7 +5751,8 @@ sub parm_change_log {
my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)=
&components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},undef,undef,$typeflag);
if ($env{'request.course.sec'} ne '') {
- next if (($issection ne '') && ($issection ne $env{'request.course.sec'}));
+ next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) ||
+ ($numgroups && (grep(/^\Q$issection\E$/,@groups))))));
if ($uname ne '') {
my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'});
next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'}));