--- loncom/interface/selfenroll.pm 2008/07/30 16:25:35 1.14 +++ loncom/interface/selfenroll.pm 2009/02/05 12:27:21 1.15 @@ -1,7 +1,7 @@ # The LearningOnline Network # Allow users to self-enroll in a course # -# $Id: selfenroll.pm,v 1.14 2008/07/30 16:25:35 raeburn Exp $ +# $Id: selfenroll.pm,v 1.15 2009/02/05 12:27:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -78,20 +78,45 @@ sub handler { } my ($canenroll,$selfenroll_types,$selfenroll_registered,@cancreate, $knownuser,$selfenroll_access_start,$selfenroll_access_end, - $selfenroll_section,$selfenroll_future,%curr_role,$cdomdesc); + $selfenroll_section,$selfenroll_future,%curr_role,$cdomdesc, + $selfenroll_approval,$selfenroll_limit,$selfenroll_cap, + $selfenroll_notifylist,$owner); $selfenroll_types = $coursehash{'internal.selfenroll_types'}; $selfenroll_registered = $coursehash{'internal.selfenroll_registered'}; $selfenroll_section = $coursehash{'internal.selfenroll_section'}; $selfenroll_access_start = $coursehash{'internal.selfenroll_start_access'}; $selfenroll_access_end = $coursehash{'internal.selfenroll_end_access'}; + $selfenroll_limit = $coursehash{'internal.selfenroll_limit'}; + $selfenroll_cap = $coursehash{'internal.selfenroll_cap'}; + $selfenroll_approval = $coursehash{'internal.selfenroll_approval'}; + $selfenroll_notifylist = $coursehash{'internal.selfenroll_notifylist'}; + $owner = $coursehash{'internal.courseowner'}; + my $nospace; if ($selfenroll_types ne '') { my $start = $coursehash{'internal.selfenroll_start_date'}; my $end = $coursehash{'internal.selfenroll_end_date'}; if (($start > 0 && $start < $now) && (($end == 0) || ($end > 0 && $end > $now))) { - $canenroll = 1; + if (($selfenroll_limit eq 'allstudents') || + ($selfenroll_limit eq 'selfenroll')) { + $nospace = + &enrollment_limit_check($selfenroll_limit,$selfenroll_cap, + $cdom,$cnum); + if (!$nospace) { + $canenroll = 1; + } + } else { + $canenroll = 1; + } } elsif (($end == 0) || ($end > 0 && $end > $now)) { if ($start > $now) { - $selfenroll_future = &Apache::lonlocal::locallocaltime($start); + if (($selfenroll_limit eq 'allstudents') || + ($selfenroll_limit eq 'selfenroll')) { + $nospace = + &enrollment_limit_check($selfenroll_limit,$cdom,$cnum); + } + if (!$nospace) { + $selfenroll_future = &Apache::lonlocal::locallocaltime($start); + } } } } @@ -100,6 +125,14 @@ sub handler { $r->print('

'.&mt('Self-enrollment unavailable').'

'. &mt('Self-enrollment is not currently available for this course.'). '

'); + if ($nospace) { + if ($selfenroll_limit eq 'allstudents') { + $r->print(&mt('The enrollment limit of [quant,_1,student] has been reached.',$selfenroll_cap)); + } else { + $r->print(&mt('The enrollment limit of [quant,_1,self-enrolled student] has been reached.',$selfenroll_cap)); + + } + } if ($selfenroll_types ne '') { if ($selfenroll_future ne '') { if ($selfenroll_types eq '*') { @@ -190,7 +223,8 @@ sub handler { } &process_self_enroll($r,$cdom,$cnum,$selfenroll_types,$selfenroll_registered, $selfenroll_access_start,$selfenroll_access_end, - $selfenroll_section,$now); + $selfenroll_section,$now,$selfenroll_approval, + $selfenroll_notifylist,$owner); } elsif ($env{'form.phase'} eq 'login') { my $submit_text = &mt('Log in'); $r->print('

'.&mt('Log-in to LON-CAPA').'

'); @@ -282,6 +316,28 @@ END return OK; } +sub enrollment_limit_check { + my ($selfenroll_limit,$selfenroll_cap,$cdom,$cnum) = @_; + my $nospace = 0; + my (%idx,%stucount); + my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cnum); + $idx{'type'} = &Apache::loncoursedata::CL_TYPE(); + $idx{'status'} = &Apache::loncoursedata::CL_STATUS(); + while (my ($student,$data) = each(%$classlist)) { + if (($data->[$idx{'status'}] eq 'Active') || + ($data->[$idx{'status'}] eq 'Future')) { + if ($data->[$idx{'type'}] eq 'selfenroll') { + $stucount{'selfenroll'} ++; + } + $stucount{'allstudents'} ++; + } + } + if ($stucount{$selfenroll_limit} >= $selfenroll_cap) { + $nospace = 1; + } + return $nospace; +} + sub page_header { my ($r,$courseid,$js,$desc) = @_; my $start_page = @@ -357,7 +413,8 @@ sub has_role { sub process_self_enroll { my ($r,$cdom,$cnum,$selfenroll_types,$selfenroll_registered, - $selfenroll_access_start,$selfenroll_access_end,$selfenroll_section,$now) = @_; + $selfenroll_access_start,$selfenroll_access_end,$selfenroll_section, + $now,$selfenroll_approval,$selfenroll_notifylist,$owner) = @_; my $udom = $env{'user.domain'}; my $uname = $env{'user.name'}; my $selfenroll = 0; @@ -397,48 +454,55 @@ sub process_self_enroll { return; } } - my $enrollresult = - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef, - undef,undef,$usec,$selfenroll_access_end,$selfenroll_access_start, - 'manual',undef,$cdom.'_'.$cnum,$selfenroll); - if ($enrollresult eq 'ok') { - my (%userroles,%newrole,%newgroups); - my $role = 'st'; - my $area = '/'.$cdom.'/'.$cnum; - my $spec = $role.'.'.$area; - if ($usec ne '') { - $spec .= '/'.$usec; - $area .= '/'.$usec; - } - &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum, - $area); - &Apache::lonnet::set_userprivs(\%userroles,\%newrole,%newgroups); - $userroles{'user.role.'.$spec} = $selfenroll_access_start.'.'.$selfenroll_access_end; - &Apache::lonnet::appenv(\%userroles,[$role,'cm']); - $r->print('

'.&mt('Enrollment process complete').'

'); - if ($selfenroll_access_end && $selfenroll_access_end <= $now) { - $r->print(&mt('The end date for access to this course for users who self-enroll has passed.').'
'.&mt('Consequently, although a new role was created for you in the course, it is an inactive role which does not provide access to the course.')); - } else { - $r->print(&mt('Self-enrollment in this course was successful.').'
'); - my $showstart = &Apache::lonlocal::locallocaltime($selfenroll_access_start); - my $showend = &Apache::lonlocal::locallocaltime($selfenroll_access_end); - if ($selfenroll_access_start && $selfenroll_access_start >$now) { - $r->print(&mt('The start date for access to this course for users who self-enroll has yet to be reached.').'
'.&mt('Consequently, although a new role was created for you in the course, you will not be able to select this role until [_1].',$showstart)); + if ($selfenroll_approval) { + my $outcome = + &store_selfenroll_request($udom,$uname,$usec,$cdom,$cnum, + $selfenroll_notifylist,$owner); + $r->print($outcome); + } else { + my $enrollresult = + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef, + undef,undef,$usec,$selfenroll_access_end,$selfenroll_access_start, + 'selfenroll',undef,$cdom.'_'.$cnum,$selfenroll); + if ($enrollresult eq 'ok') { + my (%userroles,%newrole,%newgroups); + my $role = 'st'; + my $area = '/'.$cdom.'/'.$cnum; + my $spec = $role.'.'.$area; + if ($usec ne '') { + $spec .= '/'.$usec; + $area .= '/'.$usec; + } + &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum, + $area); + &Apache::lonnet::set_userprivs(\%userroles,\%newrole,%newgroups); + $userroles{'user.role.'.$spec} = $selfenroll_access_start.'.'.$selfenroll_access_end; + &Apache::lonnet::appenv(\%userroles,[$role,'cm']); + $r->print('

'.&mt('Enrollment process complete').'

'); + if ($selfenroll_access_end && $selfenroll_access_end <= $now) { + $r->print(&mt('The end date for access to this course for users who self-enroll has passed.').'
'.&mt('Consequently, although a new role was created for you in the course, it is an inactive role which does not provide access to the course.')); } else { - my $newrole = 'st./'.$cdom.'/'.$cnum; - if ($usec ne '') { - $newrole .= '/'.$usec; + $r->print(&mt('Self-enrollment in this course was successful.').'
'); + my $showstart = &Apache::lonlocal::locallocaltime($selfenroll_access_start); + my $showend = &Apache::lonlocal::locallocaltime($selfenroll_access_end); + if ($selfenroll_access_start && $selfenroll_access_start >$now) { + $r->print(&mt('The start date for access to this course for users who self-enroll has yet to be reached.').'
'.&mt('Consequently, although a new role was created for you in the course, you will not be able to select this role until [_1].',$showstart)); + } else { + my $newrole = 'st./'.$cdom.'/'.$cnum; + if ($usec ne '') { + $newrole .= '/'.$usec; + } + my $rolelink = &jump_to_role($newrole); + $r->print(&mt('Your new role is available immediately, and will provide access to the course until [_1].',$showend).'

'."\n". + $rolelink); } - my $rolelink = &jump_to_role($newrole); - $r->print(&mt('Your new role is available immediately, and will provide access to the course until [_1].',$showend).'

'."\n". - $rolelink); } - } - } else { - $r->print('

'.&mt('Enrollment incomplete').'

'. - &mt('Self-enrollment in this course failed.')); - if ($enrollresult ne '') { - $r->print(''.$enrollresult.''); + } else { + $r->print('

'.&mt('Enrollment incomplete').'

'. + &mt('Self-enrollment in this course failed.')); + if ($enrollresult ne '') { + $r->print(''.$enrollresult.''); + } } } } else { @@ -470,6 +534,143 @@ sub user_can_selfenroll { return $selfenroll; } +sub store_selfenroll_request { + my ($udom,$uname,$usec,$cdom,$cnum,$selfenroll_notifylist,$owner) = @_; + my $namespace = 'selfenrollrequests'; + my $output; + my $now = time; + my %existing = + &Apache::lonnet::get($namespace,[$uname.':'.$udom],$cdom,$cnum); + if ($existing{$uname.':'.$udom}) { + my ($timestamp,$sec) = split(/:/,$existing{$uname.':'.$udom}); + $output = &mt('A self-enrollment request already exists for you for this course.').'
'.&mt('Your earlier request was submitted: [_1] and remains in a queue awaiting action by a Course Coordinator.',&Apache::lonlocal::locallocaltime($timestamp)); + } else { + my %selfenroll = ( + $uname.':'.$udom => $now.':'.$usec, + ); + my $putresult = &Apache::lonnet::put($namespace,\%selfenroll,$cdom,$cnum); + if ($putresult eq 'ok') { + $output = &mt('Your request for self-enrollment has been recorded.').'
'. + &mt('A message will be sent to your LON-CAPA account when the course coordinator takes action on your request').'
'; + my %emails = &Apache::loncommon::getemails($uname,$udom); + if (($emails{'permanentemail'} ne '') || ($emails{'notification'} ne '')) { + my $address = $emails{'permanentemail'}; + if ($address eq '') { + $address = $emails{'notification'}; + } + $output.= &mt('An e-mail will also be sent to: [_1] when this occurs.',$address); + } + if ($selfenroll_notifylist) { + my $fullname = &Apache::loncommon::plainname($uname,$udom); + my %courseinfo = &Apache::lonnet::coursedescription($cdom.'_'.$cnum); + my $coursedesc = $courseinfo{'description'}; + &send_notification($selfenroll_notifylist,$fullname,$cdom. + '_'.$cnum,$coursedesc,$now,'request',$owner); + } + } else { + $output = ''.&mt('An error occurred when recording your request.').''; + + } + } + return $output; +} + +sub send_notification { + my ($notifylist,$textstr,$cid,$coursedesc,$timestamp,$context,$sender, + $approvedlist,$rejectedlist) = @_; +# FIXME locallocaltime needs to be able to take $sender_lh as an argument +# so this can be localized to the recipients date display format/time zone + $timestamp =&Apache::lonlocal::locallocaltime($timestamp); + my $msgcc; + my ($rawsubj,@rawmsg,$subject,$message,$namelink); + $namelink = &Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})); + if ($context eq 'managers') { + $rawsubj = 'Self-enrollment requests processed'; + push(@rawmsg,{ + mt => 'Enrollment requests in the following course: [_1] have been processed.', + args => [$coursedesc], + }); + } elsif ($context eq 'enroller') { + $rawsubj = 'Enrollment request'; + push(@rawmsg,{ + mt => 'Your request for enrollment in the following course: [_1], requested on [_2], has been reviewed by a Course Coordinator.', + args => [$coursedesc,$timestamp], + }); + if (ref($textstr) eq 'ARRAY') { + push(@rawmsg,@{$textstr}); + } + } else { + $rawsubj = 'Self-enrollment request'; + push(@rawmsg,{ + mt => 'Enrollment in the following course: [_1] was requested by [_2] on [_3].', + args => [$coursedesc,$textstr,$timestamp], + }, + { + mt =>'As Course Coordinator, use Main Menu -> Manage Couse Users -> "Enrollment Requests" to display a list of pending enrollment requests which you can either approve or reject.' + }); + } + my @to_notify = split(/,/,$notifylist); + my $numsent = 0; + my @recusers; + my @recudoms; + foreach my $cc (@to_notify) { + my ($ccname,$ccdom) = split(/:/,$cc); + if (!exists($msgcc->{$ccname.':'.$ccdom})) { + push(@recusers,$ccname); + push(@recudoms,$ccdom); + $msgcc->{$ccname.':'.$ccdom}=''; + $numsent ++; + } + } + my %reciphash = ( + cc => $msgcc, + ); + my ($uname,$udom); + if ($sender =~ /:/) { + ($uname,$udom) = split(/:/,$sender); + } else { + $uname = $sender; + my %courseinfo = &Apache::lonnet::coursedescription($cid); + $udom = $courseinfo{'num'}; + } + my %sentmessage; + my $stamp = time; + my $msgcount = &Apache::lonmsg::get_uniq(); + my $sender_lh = &Apache::loncommon::user_lang($uname,$udom,$cid); + $subject = &Apache::lonlocal::mt_user($sender_lh,$rawsubj); + $message = ''; + foreach my $item (@rawmsg) { + if (ref($item) eq 'HASH') { + $message .= &Apache::lonlocal::mt_user($sender_lh,$item->{mt},@{$item->{args}})."\n"; + } + } + &Apache::lonmsg::process_sent_mail($subject,'',$numsent,$stamp,$uname,$udom,$msgcount,$cid,$$,$message,\@recusers,\@recudoms); + my ($recipid,$recipstatus) = + &Apache::lonmsg::store_recipients($subject,$uname,$udom,\%reciphash); + foreach my $recip (sort(keys(%{$msgcc}))) { + my ($ccname,$ccdom) = split(/:/,$recip); + my $recip_lh = &Apache::loncommon::user_lang($ccname,$ccdom,$cid); + my $subject = &Apache::lonlocal::mt_user($sender_lh,$rawsubj); + my $message = ''; + foreach my $item (@rawmsg) { + if (ref($item) eq 'HASH') { + $message .= &Apache::lonlocal::mt_user($sender_lh,$item->{mt}, + @{$item->{args}})."\n"; + } + } + if ($context eq 'managers') { + if ($approvedlist) { + $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Approved enrollments:')."\n".$approvedlist; + } + if ($rejectedlist) { + $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Rejected enrollments:')."\n".$rejectedlist; + } + } + my $status = &Apache::lonmsg::user_normal_msg($ccname,$ccdom,$subject,$message,undef,undef,undef,1,\%sentmessage,undef,undef,undef,1,$recipid); + } +} + sub jump_to_role { my ($role) = @_; my $output = <<"END";