--- loncom/interface/lonparmset.pm 2018/09/03 20:23:37 1.522.2.24
+++ loncom/interface/lonparmset.pm 2024/07/06 16:19:42 1.522.2.32
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set parameters for assessments
#
-# $Id: lonparmset.pm,v 1.522.2.24 2018/09/03 20:23:37 raeburn Exp $
+# $Id: lonparmset.pm,v 1.522.2.32 2024/07/06 16:19:42 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -36,7 +36,8 @@ lonparmset - Handler to set parameters f
=head1 SYNOPSIS
-lonparmset provides an interface to setting course parameters.
+lonparmset provides an interface to setting content parameters in a
+course.
=head1 DESCRIPTION
@@ -129,7 +130,7 @@ javascript function 'pjump'.
=item print_td()
-=item print_usergroups()
+=item check_other_groups()
=item parm_control_group()
@@ -320,6 +321,7 @@ use Apache::lonnavmaps;
use Apache::longroup;
use Apache::lonrss;
use HTML::Entities;
+use Text::Wrap();
use LONCAPA qw(:DEFAULT :match);
@@ -1024,7 +1026,7 @@ sub print_row {
if (@{$usersgroups} > 1) {
my ($coursereply,$grp_parm,$controlgrp);
($coursereply,$othergrp,$grp_parm,$controlgrp) =
- &print_usergroups($r,$$part{$which}.'.'.$$name{$which},
+ &check_other_groups($$part{$which}.'.'.$$name{$which},
$rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt);
if ($coursereply && $result > 3) {
if (defined($controlgrp)) {
@@ -1098,9 +1100,7 @@ sub print_td {
$nolink = 1;
}
} elsif ($mprefix =~ /availablestudent\&$/) {
- if ($which > 3) {
- $nolink = 1;
- }
+ $nolink = 1;
} elsif ($mprefix =~ /examcode\&$/) {
unless ($which == 2) {
$nolink = 1;
@@ -1117,8 +1117,8 @@ sub print_td {
$r->print(''."\n");
}
-sub print_usergroups {
- my ($r,$what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_;
+sub check_other_groups {
+ my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_;
my $courseid = $env{'request.course.id'};
my $output;
my $symb = &symbcache($rid);
@@ -1133,7 +1133,6 @@ sub print_usergroups {
if (($coursereply) && ($cgroup ne $resultgroup)) {
if ($result > 3) {
$bgcolor = '#AAFFAA';
- $grp_parm = &valout($coursereply,$resulttype);
}
$grp_parm = &valout($coursereply,$resulttype);
$output = '
';
@@ -1285,8 +1284,7 @@ sub isdateparm {
# from which you can select all desired parameters.
#
sub parmmenu {
- my ($r,$allparms,$pscat,$keyorder)=@_;
- my $tempkey;
+ my ($r)=@_;
$r->print(<
// print('');
- &shortCuts($r,$allparms,$pscat,$keyorder);
+ &shortCuts($r);
$r->print('');
}
# return a hash
@@ -1430,7 +1428,7 @@ sub lookUpTableParameter {
'retrypartial' => 'tries',
'discussvote' => 'misc',
'examcode' => 'high_level_randomization',
- );
+ );
}
sub whatIsMyCategory {
@@ -1502,6 +1500,8 @@ sub parmboxes {
&whatIsMyCategory($tempparameter, \%categoryList);
}
#part to print the parm-list
+ $Text::Wrap::columns=60;
+ $Text::Wrap::separator=' ';
$r->print('
'."\n");
#Print parameters
@@ -1512,14 +1512,16 @@ sub parmboxes {
.&mt($categories{$key})
.''."\n");
foreach $tempkey (&keysindisplayorderCategory($categoryList{$key},$keyorder)) {
+ next if ($tempkey eq '');
$r->print(''
.' '."\n");
}
$r->print("
\n");
@@ -1531,7 +1533,7 @@ sub parmboxes {
# This function offers some links on the parameter section to get with one click a group a parameters
#
sub shortCuts {
- my ($r,$allparms,$pscat,$keyorder)=@_;
+ my ($r)=@_;
# Parameter Selection
$r->print(
@@ -1592,9 +1594,37 @@ sub partmenu {
sub usermenu {
my ($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,$usersgroups,$pssymb)=@_;
my $chooseopt=&Apache::loncommon::select_dom_form($udom,'udom').' '.
- &Apache::loncommon::selectstudent_link('parmform','uname','udom');
- my $selscript=&Apache::loncommon::studentbrowser_javascript();
+ &Apache::loncommon::selectstudent_link('parmform','uname','udom','condition').
+ &Apache::lonhtmlcommon::scripttag(<'.
+ $stuonly.' '.
+ '';
my $sections='';
my %sectionhash = &Apache::loncommon::get_sections();
@@ -1701,12 +1731,12 @@ function group_or_section(caller) {
# This function shows on table Mode the available Parameters for the selected Resources
#
sub displaymenu {
- my ($r,$allparms,$pscat,$psprt,$keyorder,$divid)=@_;
+ my ($r,$allparms,$pscat,$keyorder,$divid)=@_;
$r->print(&Apache::lonhtmlcommon::start_pick_box());
$r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameters to View')));
- &parmmenu($r,$allparms,$pscat,$keyorder);
+ &parmmenu($r);
$r->print(&Apache::loncommon::start_scrollbox('480px','440px','200px',$divid));
&parmboxes($r,$allparms,$pscat,$keyorder);
$r->print(&Apache::loncommon::end_scrollbox());
@@ -1717,7 +1747,7 @@ sub displaymenu {
}
sub mapmenu {
- my ($r,$allmaps,$pschp,$maptitles,$symbp)=@_;
+ my ($r,$allmaps,$pschp,$maptitles,$symbp,$parmlev)=@_;
my %allmaps_inverted = reverse %$allmaps;
my $navmap = Apache::lonnavmaps::navmap->new();
my $tree=[];
@@ -1765,7 +1795,11 @@ sub mapmenu {
}
}
# Show it ...
- $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Enclosing Map or Folder'),'','',' id="mapmenu"'));
+ my $rowattr = ' id="mapmenu"';
+ if ($parmlev eq 'general') {
+ $rowattr .= ' style="display:none"';
+ }
+ $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Enclosing Map or Folder'),'','',$rowattr));
if ((ref($tree) eq 'ARRAY') && (ref($treeinfo) eq 'HASH')) {
my $icon = '';
my $whitespace =
@@ -1906,7 +1940,7 @@ sub sectionmenu {
}
$output .= '>'."$s\n";
}
- $output .= "\n");
+ $output .= "\n";
return $output;
}
@@ -2136,25 +2170,124 @@ sub assessparms {
$csec=&Apache::lonnet::getsection($udom,$uname,
$env{'request.course.id'});
if ($csec eq '-1') {
- $message=''.
- &mt("User")." '$uname' ".&mt("at domain")." '$udom' ".
- &mt("not in this course")."";
- $uname='';
- $csec=$env{'form.csec'};
+ my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
+ if ($env{'form.userroles'} eq 'any') {
+ if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
+ $csec = $env{'request.course.sec'};
+ $message = '';
+ if ($crstype eq 'Community') {
+ $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
+ $uname,$udom);
+ } else {
+ $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
+ $uname,$udom);
+ }
+ $message .= '';
+ } else {
+ my @possroles = ('in','ep','ta','cr');
+ if ($crstype eq 'Community') {
+ unshift(@possroles,'co');
+ } else {
+ unshift(@possroles,'cc');
+ }
+ my %not_student_roles =
+ &Apache::lonnet::get_my_roles($uname,$udom,'userroles',['active'],
+ \@possroles,[$udom],1,1);
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my %sections_by_role;
+ foreach my $role (keys(%not_student_roles)) {
+ if ($role =~ /^\Q$cnum:$cdom:\E([^:]+):(|[^:]+)$/) {
+ my ($rolename,$sec) = ($1,$2);
+ if ($rolename =~ m{^cr/}) {
+ $rolename = 'cr';
+ }
+ push(@{$sections_by_role{$rolename}},$sec);
+ }
+ }
+ my $numroles = scalar(keys(%sections_by_role));
+ if ($numroles) {
+ foreach my $role (@possroles) {
+ if (ref($sections_by_role{$role}) eq 'ARRAY') {
+ my @secs = sort { $a <=> $b } @{$sections_by_role{$role}};
+ $csec = $secs[0];
+ last;
+ }
+ }
+ }
+ if ($csec eq '-1') {
+ $message = '';
+ if ($crstype eq 'Community') {
+ $message .= &mt('User [_1] at domain [_2] does not have a role in this community',
+ $uname,$udom);
+ } else {
+ $message .= &mt('User [_1] at domain [_2] does not have a role in this course',
+ $uname,$udom);
+ }
+ $message .= '';
+ $uname='';
+ if ($env{'request.course.sec'} ne '') {
+ $csec=$env{'request.course.sec'};
+ } else {
+ $csec=$env{'form.csec'};
+ }
+ $cgroup=$env{'form.cgroup'};
+ } else {
+ $message = '';
+ if ($crstype eq 'Community') {
+ $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
+ $uname,$udom);
+ } else {
+ $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
+ $uname,$udom);
+ }
+ $message .= '';
+ }
+ }
+ } else {
+ $message = '';
+ if ($crstype eq 'Community') {
+ $message .= &mt('User [_1] at domain [_2] does not have a member role in this community',
+ $uname,$udom);
+ } else {
+ $message .= &mt('User [_1] at domain [_2] does not have a student role in this course',
+ $uname,$udom);
+ }
+ $message .= '';
+ $uname='';
+ if ($env{'request.course.sec'} ne '') {
+ $csec=$env{'request.course.sec'};
+ } else {
+ $csec=$env{'form.csec'};
+ }
+ $cgroup=$env{'form.cgroup'};
+ }
+ } elsif ($env{'request.course.sec'} ne '') {
+ if ($csec ne $env{'request.course.sec'}) {
+ $message=''.
+ &mt("User '[_1]' at domain '[_2]' not in section '[_3]'",
+ $uname,$udom,$env{'request.course.sec'}).
+ '';
+ $uname='';
+ $csec=$env{'request.course.sec'};
+ }
$cgroup=$env{'form.cgroup'};
- } else {
+ }
+ if ($uname ne '') {
my %name=&Apache::lonnet::userenvironment($udom,$uname,
('firstname','middlename','lastname','generation','id'));
- $message="\n
';
+ @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 = '';
}
}
}
@@ -2181,6 +2314,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);
@@ -2189,6 +2323,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);
@@ -2266,9 +2405,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.='
'.&mt('No parameter changes saved.').'
';
+ }
+ if ($totalskippeduser) {
+ $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
@@ -2320,7 +2477,7 @@ ENDPARMSELSCRIPT
$r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
&levelmenu($r,\%alllevs,$parmlev);
$r->print(&Apache::lonhtmlcommon::row_closure());
- &mapmenu($r,\%allmaps,$pschp,\%maptitles, \%symbp);
+ &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
$r->print(&Apache::lonhtmlcommon::row_closure());
$r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
&partmenu($r,\%allparts,\@psprt);
@@ -2329,7 +2486,7 @@ ENDPARMSELSCRIPT
# Step 2
$r->print(&Apache::lonhtmlcommon::topic_bar(2,&mt('Parameter Specification'),'parmstep2'));
- &displaymenu($r,\%allparms,\@pscat,\@psprt,\%keyorder,'parmmenuscroll');
+ &displaymenu($r,\%allparms,\@pscat,\%keyorder,'parmmenuscroll');
# Step 3
$r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('User Specification (optional)'),'parmstep3'));
@@ -2615,7 +2772,7 @@ ENDTABLEHEADFOUR
#-------------------------------------------- for each map, gather information
my $mapid;
- foreach $mapid (sort {$maplist{$a} cmp $maplist{$b}} keys %maplist) {
+ foreach $mapid (sort { $a <=> $b } keys(%maplist)) {
my $maptitle = $maplist{$mapid};
#----------------------- loop through ids and get all parameter types for map
@@ -3053,7 +3210,7 @@ sub parse_listdata_key {
}
sub listdata {
- my ($r,$resourcedata,$listdata,$sortorder,$caller,$classlist,$readonly)=@_;
+ my ($r,$resourcedata,$listdata,$sortorder,$caller,$classlist,$readonly,$parmlev)=@_;
# Start list output
my $oldsection='';
@@ -3063,6 +3220,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')) {
@@ -3123,6 +3281,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)/) {
@@ -3135,6 +3296,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})) {
@@ -3160,6 +3322,7 @@ sub listdata {
$realm=''.&mt('Folder/Map').': '.&Apache::lonnet::gettitle($1).' ('.$1.')';
} elsif ($middle) {
my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
+ next if (($url =~ /\.(page|sequence)$/) && ($parmlev eq 'full') && ($caller eq 'newoverview'));
$realm=''.&mt('Resource').': '.&Apache::lonnet::gettitle($middle).' ('.$url.' in '.$map.' id: '.$id.')';
}
if ($sortorder eq 'realmstudent') {
@@ -3199,8 +3362,13 @@ sub listdata {
'
');
@@ -3609,7 +3806,7 @@ ENDOVER
# List data
- &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly);
+ &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly,$parmlev);
}
$r->print(&tableend());
unless ($readonly) {
@@ -3764,10 +3961,8 @@ ENDOVER
$r->print(&mt('All users'));
} elsif ($data{'scope_type'} eq 'user') {
$r->print(&mt('User: [_1]',join(':',@{$data{'scope'}})));
- } elsif ($data{'scope_type'} eq 'section') {
- $r->print(&mt('Section: [_1]',$data{'scope'}));
- } elsif ($data{'scope_type'} eq 'group') {
- $r->print(&mt('Group: [_1]',$data{'scope'}));
+ } elsif ($data{'scope_type'} eq 'secgroup') {
+ $r->print(&mt('Group/Section: [_1]',$data{'scope'}));
}
$r->print(' ');
if ($data{'realm_type'} eq 'all') {
@@ -3796,9 +3991,21 @@ sub date_shift_one {
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 $submit_text = &mt('Shift all dates accordingly');
+ if ($sec ne '') {
+ my @groups;
+ if ($env{'request.course.groups'} ne '') {
+ @groups = split(/:/,$env{'request.course.groups'});
+ }
+ if (@groups) {
+ $submit_text = &mt("Shift dates set just for your section/group(s), accordingly");
+ } else {
+ $submit_text = &mt("Shift dates set just for your section, accordingly");
+ }
+ }
my $start_page=&Apache::loncommon::start_page('Shift Dates');
my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
$r->print($start_page.$breadcrumbs);
@@ -3813,7 +4020,7 @@ sub date_shift_one {
'
'.
''.
''.
- '');
+ '');
$r->print(&Apache::loncommon::end_page());
}
@@ -3821,20 +4028,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').'']));
@@ -3853,8 +4094,7 @@ sub parse_key {
$data{'scope_type'} = 'user';
$data{'scope'} = [$1,$2];
} else {
- #FIXME check for group scope
- $data{'scope_type'} = 'section';
+ $data{'scope_type'} = 'secgroup';
}
$middle=~s/^\[(.*)\]//;
}
@@ -4168,7 +4408,7 @@ sub continue {
my $output;
$output .= '');
}
- $r->print('Or you may enter a new metadata field name.');
}
@@ -4238,6 +4489,11 @@ sub setrestrictmeta {
my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
my $key_base = $env{'course.'.$env{'request.course.id'}.'.'};
my $save_field = '';
+ my %lt = &Apache::lonlocal::texthash(
+ addm => 'Add Metadata Field',
+ ordm => 'Order Metadata Fields',
+ save => 'Save',
+ );
if ($env{'form.restrictmeta'}) {
foreach my $field (sort(keys(%env))) {
if ($field=~m/^form.(.+)_(.+)$/) {
@@ -4276,28 +4532,25 @@ sub setrestrictmeta {
my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio');
# Now get possible added metadata fields
my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'});
- my $row_alt = 1;
$output .= &Apache::loncommon::start_data_table();
foreach my $field (sort(keys(%metadata_fields))) {
if ($field ne 'courserestricted') {
- $row_alt = $row_alt ? 0 : 1;
$output.= &output_row($r, $field, $metadata_fields{$field});
}
}
my $buttons = (<
+