--- loncom/interface/loncreateuser.pm 2007/12/21 17:27:57 1.219 +++ loncom/interface/loncreateuser.pm 2007/12/21 20:34:26 1.221 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Create a user # -# $Id: loncreateuser.pm,v 1.219 2007/12/21 17:27:57 raeburn Exp $ +# $Id: loncreateuser.pm,v 1.221 2007/12/21 20:34:26 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1509,7 +1509,6 @@ sub update_user_data { text=>"Result", faq=>282,bug=>'Instructor Interface',}); $r->print(&Apache::lonhtmlcommon::breadcrumbs('User Management')); - my %disallowed; $r->print(&update_result_form($uhome)); # Check Inputs if (! $env{'form.ccuname'} ) { @@ -1681,22 +1680,12 @@ sub update_user_data { my @statuses = ('active','future'); my %roles = &Apache::lonnet::get_my_roles($env{'form.ccuname'},$env{'form.ccdomain'},'userroles',\@statuses,undef,$env{'request.role.domain'}); my ($auname,$audom); - if ($context eq 'course') { - $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - if ($cnum eq '' || $cdom eq '') { - my $cid = $env{'request.course.id'}; - my %coursehash = - &Apache::lonnet::coursedescription($cid,{'one_time' => 1}); - $cdom = $coursehash{'domain'}; - $cnum = $coursehash{'num'}; - } - } elsif ($context eq 'author') { + if ($context eq 'author') { $auname = $env{'user.name'}; $audom = $env{'user.domain'}; } foreach my $item (keys(%roles)) { - my ($rolenum,$roledom,$role) = split(/:/,$item); + my ($rolenum,$roledom,$role) = split(/:/,$item,-1); if ($context eq 'course') { if ($cnum ne '' && $cdom ne '') { if ($rolenum eq $cnum && $roledom eq $cdom) { @@ -1713,27 +1702,33 @@ sub update_user_data { } } } - # Check for course or co-author roles being activated or re-enabled - if ($context eq 'author' || $context eq 'course') { - foreach my $key (keys(%env)) { - if ($context eq 'author') { - if ($key=~/^form\.act_\Q$audom\E_\Q$auname\E_([^_]+)/) { - if (!grep(/^\Q$1\E$/,@userroles)) { - push(@userroles,$1); - } - } elsif ($key =~/^form\.ren\:\Q$audom\E\/\Q$auname\E_([^_]+)/) { - if (!grep(/^\Q$1\E$/,@userroles)) { - push(@userroles,$1); - } - } - } elsif ($context eq 'course') { - if ($key=~/^form\.act_\Q$cdom\E_\Q$cnum\E_([^_]+)/) { - if (!grep(/^\Q$1\E$/,@userroles)) { - push(@userroles,$1); + if ($env{'form.action'} eq 'singlestudent') { + if (!grep(/^st$/,@userroles)) { + push(@userroles,'st'); + } + } else { + # Check for course or co-author roles being activated or re-enabled + if ($context eq 'author' || $context eq 'course') { + foreach my $key (keys(%env)) { + if ($context eq 'author') { + if ($key=~/^form\.act_\Q$audom\E_\Q$auname\E_([^_]+)/) { + if (!grep(/^\Q$1\E$/,@userroles)) { + push(@userroles,$1); + } + } elsif ($key =~/^form\.ren\:\Q$audom\E\/\Q$auname\E_([^_]+)/) { + if (!grep(/^\Q$1\E$/,@userroles)) { + push(@userroles,$1); + } } - } elsif ($key =~/^form\.ren\:\Q$cdom\E\/\Q$cnum\E(\/?\w*)_([^_]+)/) { - if (!grep(/^\Q$1\E$/,@userroles)) { - push(@userroles,$1); + } elsif ($context eq 'course') { + if ($key=~/^form\.act_\Q$cdom\E_\Q$cnum\E_([^_]+)/) { + if (!grep(/^\Q$1\E$/,@userroles)) { + push(@userroles,$1); + } + } elsif ($key =~/^form\.ren\:\Q$cdom\E\/\Q$cnum\E(\/?\w*)_([^_]+)/) { + if (!grep(/^\Q$1\E$/,@userroles)) { + push(@userroles,$1); + } } } } @@ -1765,7 +1760,6 @@ sub update_user_data { # Check to see if we can change the ID/student number my $forceid = $env{'form.forceid'}; my $recurseid = $env{'form.recurseid'}; - my $newuser = 0; my (%alerts,%rulematch,%idinst_results,%curr_rules,%got_rules); my %uidhash = &Apache::lonnet::idrget($env{'form.ccdomain'}, $env{'form.ccuname'}); @@ -1797,6 +1791,10 @@ sub update_user_data { $newdefquotatext); my ($defquota,$settingstatus) = &Apache::loncommon::default_quota($env{'form.ccdomain'},$inststatus); + my $showquota; + if (&Apache::lonnet::allowed('mpq',$env{'form.ccdomain'})) { + $showquota = 1; + } my %changeHash; $changeHash{'portfolioquota'} = $userenv{'portfolioquota'}; if ($userenv{'portfolioquota'} ne '') { @@ -1867,6 +1865,13 @@ sub update_user_data { $changeHash{'firstname'},$changeHash{'middlename'}, $changeHash{'lastname'},$changeHash{'generation'}, $changeHash{'id'},undef,$changeHash{'permanentemail'}); + %userupdate = ( + lastname => $env{'form.clastname'}, + middlename => $env{'form.cmiddlename'}, + firstname => $env{'form.cfirstname'}, + generation => $env{'form.cgeneration'}, + id => $env{'form.cid'}, + ); } if (($namechanged && $namechgresult eq 'ok') || ($quotachanged && $quotachgresult eq 'ok')) { @@ -1894,8 +1899,11 @@ sub update_user_data { $lt{'gen'} $lt{'id'} $lt{'mail'} - $lt{'disk'} END + if ($showquota) { + $r->print(" + $lt{'disk'}\n"); + } $r->print(&Apache::loncommon::end_data_table_header_row(). &Apache::loncommon::start_data_table_row()); $r->print(<<"END"); @@ -1906,8 +1914,11 @@ END $userenv{'generation'} $userenv{'id'} $userenv{'permanentemail'} - $oldportfolioquota Mb $olddefquotatext END + if ($showquota) { + $r->print(" + $oldportfolioquota Mb $olddefquotatext \n"); + } $r->print(&Apache::loncommon::end_data_table_row(). &Apache::loncommon::start_data_table_row()); $r->print(<<"END"); @@ -1918,8 +1929,11 @@ END $env{'form.cgeneration'} $env{'form.cid'} $env{'form.cpermanentemail'} - $newportfolioquota Mb $newdefquotatext END + if ($showquota) { + $r->print(" + $newportfolioquota Mb $newdefquotatext \n"); + } $r->print(&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table().'
'); if ($env{'form.cid'} ne $userenv{'id'}) { @@ -1927,13 +1941,6 @@ END ($env{'form.ccuname'} => $env{'form.cid'})); if (($recurseid) && (&Apache::lonnet::allowed('mau',$env{'form.ccdomain'}))) { - %userupdate = ( - lastname => $env{'form.clasaname'}, - middlename => $env{'form.cmiddlename'}, - firstname => $env{'form.cfirstname'}, - generation => $env{'fora.cgeneration'}, - id => $env{'form.cid'}, - ); my $idresult = &Apache::lonuserutils::propagate_id_change( $env{'form.ccuname'},$env{'form.ccdomain'}, @@ -1969,8 +1976,11 @@ END $r->print('
['.$lt{'mail'}.': '. $userenv{'permanentemail'}.']'); } - $r->print('
['.$lt{'disk'}.': '.$oldportfolioquota.' Mb '. - $olddefquotatext.']'); + if ($showquota) { + $r->print('
['.$lt{'disk'}.': '.$oldportfolioquota.' Mb '. + $olddefquotatext.']'); + } + $r->print(''); } if (@mod_disallowed) { my ($rolestr,$contextname); @@ -2001,9 +2011,31 @@ END $r->print($no_forceid_alert. &Apache::lonuserutils::print_namespacing_alerts($env{'form.ccdomain'},\%alerts, \%curr_rules)); } - ## + if ($env{'form.action'} eq 'singlestudent') { + &enroll_single_student($r,$uhome,$amode,$genpwd,$now,$newuser); + } else { + my $rolechanges = &update_roles($r); + if (!$rolechanges && $namechanged) { + if ($context eq 'course') { + if (@userroles > 0) { + if (grep(/^st$/,@userroles)) { + my $classlistupdated = + &Apache::lonuserutils::update_classlist($cdom, + $cnum,$env{'form.ccdomain'}, + $env{'form.ccuname'},\%userupdate); + } + } + } + } + } + $r->print(&Apache::loncommon::end_page()); +} + +sub update_roles { + my ($r) = @_; my $now=time; my $rolechanges = 0; + my %disallowed; $r->print('

'.&mt('Modifying Roles').'

'); foreach my $key (keys (%env)) { next if (! $env{$key}); @@ -2076,7 +2108,7 @@ END if ($role eq 'st') { if ($url =~ m-^/($match_domain)/($match_courseid)/?(\w*)$-) { my $result = &Apache::loncommon::commit_studentrole(\$logmsg,$udom,$uname,$url,$role,$now,0,$1,$2,$3); - if (($result =~ /^error/) || ($result eq 'not_in_class') || ($result eq 'unknown_course')) { + if (($result =~ /^error/) || ($result eq 'not_in_class') || ($result eq 'unknown_course') || ($result eq 'refused')) { $output = "Error: $result\n"; } else { $output = &mt('Assigning').' '.$role.' in '.$url. @@ -2224,7 +2256,50 @@ END if (!$rolechanges) { $r->print(&mt('No roles to modify')); } - $r->print(&Apache::loncommon::end_page()); + return $rolechanges; +} + +sub enroll_single_student { + my ($r,$uhome,$amode,$genpwd,$now,$newuser) = @_; + $r->print('

'.&mt('Enrolling Student').'

'); + + # Remove non alphanumeric values from section + $env{'form.sections'}=~s/\W//g; + + # Clean out any old student roles the user has in this class. + &Apache::lonuserutils::modifystudent($env{'form.ccdomain'}, + $env{'form.ccuname'},$env{'request.course.id'},undef,$uhome); + my ($startdate,$enddate) = &Apache::lonuserutils::get_dates_from_form(); + my $enroll_result = + &Apache::lonnet::modify_student_enrollment($env{'form.ccdomain'}, + $env{'form.ccuname'},$env{'form.cid'},$env{'form.cfirstname'}, + $env{'form.cmiddlename'},$env{'form.clastname'}, + $env{'form.generation'},$env{'form.sections'},$enddate, + $startdate,'manual',undef,$env{'request.course.id'}); + if ($enroll_result =~ /^ok/) { + $r->print(&mt('[_1] enrolled',$env{'form.ccuname'}.':'.$env{'form.ccdomain'})); + if ($env{'form.sections'} ne '') { + $r->print(' '.&mt('in section [_1]',$env{'form.sections'})); + } + my ($showstart,$showend); + if ($startdate <= $now) { + $showstart = &mt('Access starts immediately'); + } else { + $showstart = &mt('Access starts: ').&Apache::lonlocal::locallocaltime($startdate); + } + if ($enddate == 0) { + $showend = &mt('ends: no ending date'); + } else { + $showend = &mt('ends: ').&Apache::lonlocal::locallocaltime($enddate); + } + $r->print('.
'.$showstart.'; '.$showend); + if ($startdate <= $now && !$newuser) { + $r->print("

".&mt('If the student is currently logged-in to LON-CAPA, the new role will be available when the student next logs in.')."

"); + } + } else { + $r->print(&mt('unable to enroll').": ".$enroll_result); + } + return; } sub get_defaultquota_text { @@ -2264,7 +2339,7 @@ sub update_result_form { } $outcome .= ''."\n". ''."\n". - ''."\n". + ''."\n". ''; return $outcome; } @@ -2655,10 +2730,11 @@ sub handler { if (! exists($env{'form.state'})) { &Apache::lonuserutils::print_first_users_upload_form($r,$context); } elsif ($env{'form.state'} eq 'got_file') { - &Apache::lonuserutils::print_upload_manager_form($r,$context); + &Apache::lonuserutils::print_upload_manager_form($r,$context, + $permission); } elsif ($env{'form.state'} eq 'enrolling') { if ($env{'form.datatoken'}) { - &Apache::lonuserutils::upfile_drop_add($r,$context); + &Apache::lonuserutils::upfile_drop_add($r,$context,$permission); } } else { &Apache::lonuserutils::print_first_users_upload_form($r,$context); @@ -2680,16 +2756,18 @@ sub handler { my $response; if ($env{'form.srchterm'} !~ /^$match_username$/) { my $response = &mt('You must specify a valid username. Only the following are allowed: letters numbers - . @'); + $env{'form.phase'} = ''; &print_username_entry_form($r,$context,$response,$srch); } else { my $ccuname =&LONCAPA::clean_username($srch->{'srchterm'}); my $ccdomain=&LONCAPA::clean_domain($srch->{'srchdomain'}); &print_user_modification_page($r,$ccuname,$ccdomain, - $srch,$response,$context); + $srch,$response,$context, + $permission); } } elsif ($env{'form.phase'} eq 'get_user_info') { my ($currstate,$response,$forcenewuser,$results) = - &user_search_result($srch); + &user_search_result($context,$srch); if ($env{'form.currstate'} eq 'modify') { $currstate = $env{'form.currstate'}; } @@ -2718,7 +2796,8 @@ sub handler { $response = ''; } &print_user_modification_page($r,$ccuname,$ccdomain, - $srch,$response,$context); + $srch,$response,$context, + $permission); } elsif ($currstate eq 'query') { &print_user_query_page($r,'createuser'); } else { @@ -2729,7 +2808,7 @@ sub handler { my $ccuname = &LONCAPA::clean_username($env{'form.seluname'}); my $ccdomain = &LONCAPA::clean_domain($env{'form.seludom'}); &print_user_modification_page($r,$ccuname,$ccdomain,$srch,'', - $context); + $context,$permission); } } elsif ($env{'form.phase'} eq 'update_user_data') { &update_user_data($r,$context); @@ -2746,15 +2825,22 @@ sub handler { ($permission->{'view'} || $permission->{'cusr'})) { if ($env{'form.phase'} eq 'bulkchange') { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'backPage(document.studentform)', - text=>"List Users"}); + ({href=>'/adm/createuser?action=listusers', + text=>"List Users"}, + {href=>"/adm/createuser", + text=>"Result"}); my $setting = $env{'form.roletype'}; my $choice = $env{'form.bulkaction'}; $r->print(&header()); - $r->print(&Apache::lonhtmlcommon::breadcrumbs("List Users", + $r->print(&Apache::lonhtmlcommon::breadcrumbs("Update Users", 'User_Management_List')); if ($permission->{'cusr'}) { &Apache::lonuserutils::update_user_list($r,$context,$setting,$choice); + $r->print('

'.&mt('Display User Lists').''); + $r->print(&Apache::loncommon::end_page()); + } else { + $r->print(&mt('You are not authorized to make bulk changes to user roles')); + $r->print(&Apache::loncommon::end_page()); } } else { &Apache::lonhtmlcommon::add_breadcrumb @@ -2807,7 +2893,8 @@ sub handler { } elsif ($env{'form.action'} eq 'dateselect') { if ($permission->{'cusr'}) { $r->print(&header(undef,undef,{'no_nav_bar' => 1}). - &Apache::lonuserutils::date_section_selector($context). + &Apache::lonuserutils::date_section_selector($context, + $permission). &Apache::loncommon::end_page()); } else { $r->print(&header(). @@ -2861,17 +2948,17 @@ sub print_main_menu { my %links = ( domain => { upload => 'Upload a File of Users', - singleuser => 'Add/Manage a Single User', + singleuser => 'Add/Modify a Single User', listusers => 'Manage Multiple Users', }, author => { upload => 'Upload a File of Co-authors', - singleuser => 'Add/Manage a Single Co-author', + singleuser => 'Add/Modify a Single Co-author', listusers => 'Display Co-authors and Manage Multiple Users', }, course => { upload => 'Upload a File of Course Users', - singleuser => 'Add/Manage a Single Course User', + singleuser => 'Add/Modify a Single Course User', listusers => 'Display Class Lists and Manage Multiple Users', }, ); @@ -2965,7 +3052,7 @@ sub restore_prev_selections { #-------------------------------------------------- functions for &phase_two sub user_search_result { - my ($srch) = @_; + my ($context,$srch) = @_; my %allhomes; my %inst_matches; my %srch_results; @@ -3034,14 +3121,14 @@ sub user_search_result { my $uhome=&Apache::lonnet::homeserver($srch->{'srchterm'},$srch->{'srchdomain'}); if ($uhome eq 'no_host') { ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } else { $currstate = 'modify'; } } else { %srch_results = &Apache::lonnet::usersearch($srch); ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } } else { my $courseusers = &get_courseusers(); @@ -3050,7 +3137,7 @@ sub user_search_result { $currstate = 'modify'; } else { ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } } else { foreach my $user (keys(%$courseusers)) { @@ -3077,7 +3164,7 @@ sub user_search_result { } } ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } } } @@ -3087,7 +3174,7 @@ sub user_search_result { ($dirsrchres,%srch_results) = &Apache::lonnet::inst_directory_query($srch); if ($dirsrchres eq 'ok') { ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } else { my $showdom = &display_domain_info($srch->{'srchdomain'}); $response = ''. @@ -3101,7 +3188,7 @@ sub user_search_result { if ($srch->{'srchin'} eq 'dom') { %srch_results = &Apache::lonnet::usersearch($srch); ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } elsif ($srch->{'srchin'} eq 'crs') { my $courseusers = &get_courseusers(); foreach my $user (keys(%$courseusers)) { @@ -3153,14 +3240,14 @@ sub user_search_result { } } ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } elsif ($srch->{'srchin'} eq 'alc') { $currstate = 'query'; } elsif ($srch->{'srchin'} eq 'instd') { ($dirsrchres,%srch_results) = &Apache::lonnet::inst_directory_query($srch); if ($dirsrchres eq 'ok') { ($currstate,$response,$forcenewuser) = - &build_search_response($srch,%srch_results); + &build_search_response($context,$srch,%srch_results); } else { my $showdom = &display_domain_info($srch->{'srchdomain'}); $response = ''. &mt('Institutional directory search is not available in domain: [_1]',$showdom). @@ -3266,7 +3353,7 @@ sub get_courseusers { } sub build_search_response { - my ($srch,%srch_results) = @_; + my ($context,$srch,%srch_results) = @_; my ($currstate,$response,$forcenewuser); my %names = ( 'uname' => 'username', @@ -3325,8 +3412,15 @@ sub build_search_response { } } if (!($srch->{'srchby'} eq 'uname' && $srch->{'srchin'} eq 'dom' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchdomain'} eq $env{'request.role.domain'})) { - my $showdom = &display_domain_info($env{'request.role.domain'}); + my $cancreate = + &Apache::lonuserutils::can_create_user($env{'request.role.domain'},$context); + if ($cancreate) { + my $showdom = &display_domain_info($env{'request.role.domain'}); $response .= '

'.&mt("To add a new user (you can only create new users in your current role's domain - [_1]):",$env{'request.role.domain'}).'


'; + } else { + my $helplink = ' href="javascript:helpMenu('."'display'".')"'; + $response .= '

'.&mt("You are not authorized to create new users in your current role's domain - [_1].",$env{'request.role.domain'}).'
'.&mt('Contact the helpdesk if you need to create a new user.',$helplink).'

'; + } } } } @@ -3428,83 +3522,24 @@ sub course_level_table { } my @roles = &Apache::lonuserutils::roles_by_context('course'); foreach my $role (@roles) { + my $plrole=&Apache::lonnet::plaintext($role); if (&Apache::lonnet::allowed('c'.$role,$thiscourse)) { - my $plrole=&Apache::lonnet::plaintext($role); - $table .= &Apache::loncommon::start_data_table_row(). -' -'.$plrole.' -'.$area.'
Domain: '.$domain.''."\n"; - if ($role ne 'cc') { - if (%sections_count) { - my $currsec = - &Apache::lonuserutils::course_sections(\%sections_count, - $protectedcourse.'_'.$role); - $table .= - ''. - ' - '. - ''. - ''. - '
'.$lt{'exs'}.'
'. - $currsec.'
   '.$lt{'new'}.'
'. - ''. - '
'; - } else { - $table .= ''; - } - } else { - $table .= ' '; + $table .= &course_level_row($protectedcourse,$role,$area,$domain, + $plrole,\%sections_count,\%lt); + } elsif ($env{'request.course.sec'} ne '') { + if (&Apache::lonnet::allowed('c'.$role,$thiscourse.'/'. + $env{'request.course.sec'})) { + $table .= &course_level_row($protectedcourse,$role,$area,$domain, + $plrole,\%sections_count,\%lt); } - $table .= < -$lt{'ssd'} - -$lt{'sed'} -ENDTIMEENTRY - $table.= &Apache::loncommon::end_data_table_row(); } } - foreach my $cust (sort keys %customroles) { - if (&Apache::lonnet::allowed('ccr',$thiscourse)) { - my $plrole=$cust; - my $customrole=$protectedcourse.'_cr_cr_'.$env{'user.domain'}. - '_'.$env{'user.name'}.'_'.$plrole; - $table .= &Apache::loncommon::start_data_table_row(). -' -'.$plrole.' -'.$area.''."\n"; - if (%sections_count) { - my $currsec = - &Apache::lonuserutils::course_sections(\%sections_count, - $customrole); - $table.= - ''. - ''. - ''. - ''. - ''. - '
'. - $lt{'exs'}.'
'.$currsec.'
   '.$lt{'new'}.'
'. - '
'; - } else { - $table .= ''; - } - $table .= < -$lt{'ssd'} - -$lt{'sed'} -ENDENTRY - $table .= &Apache::loncommon::end_data_table_row(); - } + if (&Apache::lonnet::allowed('ccr',$thiscourse)) { + foreach my $cust (sort keys %customroles) { + my $role = 'cr_cr_'.$env{'user.domain'}.'_'.$env{'user.name'}.'_'.$cust; + $table .= &course_level_row($protectedcourse,$role,$area,$domain, + $cust,\%sections_count,\%lt); + } } } return '' if ($table eq ''); # return nothing if there is nothing @@ -3524,6 +3559,52 @@ $table. return $result; } +sub course_level_row { + my ($protectedcourse,$role,$area,$domain,$plrole,$sections_count,$lt) = @_; + my $table = &Apache::loncommon::start_data_table_row(). + ' '."\n". + ' '.$plrole.''."\n". + ''.$area.'
Domain: '.$domain.''."\n"; + if ($role eq 'cc') { + $table .= ' '; + } elsif ($env{'request.course.sec'} ne '') { + $table .= ' '. + $env{'request.course.sec'}.''; + } else { + if (ref($sections_count) eq 'HASH') { + my $currsec = + &Apache::lonuserutils::course_sections($sections_count, + $protectedcourse.'_'.$role); + $table .= ''. + ' + + + '."\n". + '
'.$lt->{'exs'}.'
'. + $currsec.'
   '.$lt->{'new'}.'
'. + ''. + '
'; + } else { + $table .= ''; + } + } + $table .= < +$lt->{'ssd'} + +$lt->{'sed'} +ENDTIMEENTRY + $table.= &Apache::loncommon::end_data_table_row(); +} + sub course_level_dc { my ($dcdom) = @_; my %customroles=&Apache::lonuserutils::my_custom_roles(); @@ -3570,6 +3651,7 @@ sub course_level_dc { '  '. ' '.$lt{'new'}.'
'. ''. + ''. ''. ''; $otheritems .= <