--- loncom/interface/lonmsgdisplay.pm 2006/11/29 19:31:47 1.45 +++ loncom/interface/lonmsgdisplay.pm 2006/12/08 14:43:38 1.50 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Routines for messaging display # -# $Id: lonmsgdisplay.pm,v 1.45 2006/11/29 19:31:47 raeburn Exp $ +# $Id: lonmsgdisplay.pm,v 1.50 2006/12/08 14:43:38 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -74,8 +74,8 @@ email program, so they have full access interface, or other features they may wish to use in response to the student's query. -=item * B: LON-CAPA can block display of e-mails that are -sent to a student during an online exam. A course coordinator or +=item * B: LON-CAPA can block selected communication +features for students during an online exam. A course coordinator or instructor can set an open and close date/time for scheduled online exams in a course. If a user uses the LON-CAPA internal messaging system to display e-mails during the scheduled blocking event, @@ -138,24 +138,142 @@ my $interdis; sub folderlist { my $folder=shift; - my @allfolders=&Apache::lonnet::getkeys('email_folders'); - if ($allfolders[0]=~/^error:/) { @allfolders=(); } - return '
'. - &mt('Folder').': '. - &Apache::loncommon::select_form($folder,'folder', - ('' => &mt('INBOX'),'trash' => &mt('TRASH'), - 'new' => &mt('New Messages Only'), - 'critical' => &mt('Critical'), - 'sent' => &mt('Sent Messages'), - map { $_ => $_ } @allfolders)). - ' '.&mt('Show'). - ''. - '
'. + my %lt = &Apache::lonlocal::texthash( + actn => 'Action', + fold => 'Folder', + show => 'Show', + go => 'Go', + nnff => 'New Name for Folder', + newn => 'New Name', + thfm => 'The folder may not be renamed', + fmnb => 'folder may not be renamed as it is a folder provided by the system.', + asth => 'as this name is already in use for a system-provided or user-defined folder.', + the => 'The', + tnfm => 'The new folder may not be named', + + ); + + my %actions = &Apache::lonlocal::texthash( + view => 'View Folder', + rename => 'Rename Folder', + delete => 'Delete Folder', + ); + $actions{'select_form_order'} = ['view','rename','delete']; + + my %permfolders = &get_permanent_folders(); + my $permlist = join("','",sort(keys(%permfolders))); + my ($permlistkeys,$permlistvals); + foreach my $key (sort(keys(%permfolders))) { + $permlistvals .= $permfolders{$key}."','"; + $permlistkeys .= $key."','"; + } + $permlistvals =~ s/','$//; + $permlistkeys =~ s/','$//; + my %gotfolders = &Apache::lonmsg::get_user_folders(); + my %userfolders; + + foreach my $key (keys(%gotfolders)) { + $userfolders{$key} = $key; + } + my @userorder = sort(keys(%userfolders)); + my %formhash = (%permfolders,%userfolders); + my $folderlist = join("','",@userorder); + $folderlist .= "','".$permlistvals; + + $formhash{'select_form_order'} = ['','critical','new',@userorder,'sent','trash']; + my $output = qq||; + $output .= ' + + + + + + +
+ + + + + + +
'.$lt{'fold'}.'
'."\n". + &Apache::loncommon::select_form($folder,'folder',%formhash).' +
'.$lt{'show'}.'
+ +
'.$lt{'actn'}.'
'. + &Apache::loncommon::select_form('view','folderaction',%actions).' +

'. + ' +
+
     + '. + '

+
'.&mt('New Folder').'
'. + ' +
+
'."\n". ''. - ($folder=~/^(new|critical)/?'
':''); + ''. + ($folder=~/^(new|critical)/?'':''); + return $output; +} + +sub get_permanent_folders { + my %permfolders = + &Apache::lonlocal::texthash('' => 'INBOX', + 'trash' => 'TRASH', + 'new' => 'New Messages Only', + 'critical' => 'Critical', + 'sent' => 'Sent Messages', + ); + return %permfolders; } sub scrollbuttons { @@ -195,14 +313,123 @@ sub statuschange { # ============================================================= Make new folder sub makefolder { - my ($newfolder)=@_; - if (($newfolder eq 'sent') - || ($newfolder eq 'critical') - || ($newfolder eq 'trash') - || ($newfolder eq 'new')) { return; } - &Apache::lonnet::put('email_folders',{$newfolder => time}); + my ($newfolder) = @_; + my %permfolders = &get_permanent_folders(); + my %userfolders = &Apache::lonmsg::get_user_folders(); + my ($outcome,$warning); + if (defined($userfolders{$newfolder})) { + return &mt('The folder name: "[_1]" is already in use for an existing folder.',$newfolder); + } + foreach my $perm (keys(%permfolders)) { + if ($permfolders{$perm} eq $newfolder) { + return &mt('The folder name: "[_1]" is already used for one of the folders automatically generated by the system.',$newfolder); + } + } + if (&get_msgfolder_lock() eq 'ok') { + my %counter_hash = &Apache::lonnet::get('email_folders',["\0".'idcount']); + my $lastcount = $counter_hash{"\0".'idcount'}; + my $folder_id = $lastcount + 1; + while (defined($userfolders{$folder_id})) { + $folder_id ++; + } + my %folderinfo = ( id => $folder_id, + created => time, ); + $outcome = + &Apache::lonnet::put('email_folders',{$newfolder => \%folderinfo, + "\0".'idcount' => $folder_id}); + my $releaseresult = &release_msgfolder_lock(); + if ($releaseresult ne 'ok') { + $warning = $releaseresult; + } + } else { + $outcome = + &mt('Error - could not obtain lock on email folders record.'); + } + return ($outcome,$warning); +} + +# ============================================================= Delete folder + +sub deletefolder { + my ($folder)=@_; + my %permfolders = &get_permanent_folders(); + if (defined($permfolders{$folder})) { + return &mt('The folder [_1] may not be deleted',$folder); + } + my %userfolders = &Apache::lonmsg::get_user_folders(); + if (!defined($userfolders{$folder})) { + return &mt('The folder [_1] does not exist so deletion is not required.', + $folder); + } + # check folder is empty; + my $suffix=&Apache::lonmsg::foldersuffix($folder); + my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix); + if (@messages > 0) { + return &mt('The folder [_1] contains messages so it may not be deleted.'). + '
'. + &mt('Delete or move the messages to a different folder first.'); + } + my $delresult = &Apache::lonnet::del('email_folders',[$folder]); + return $delresult; } +sub renamefolder { + my ($folder) = @_; + my $newname = $env{'form.renamed'}; + my %permfolders = &get_permanent_folders(); + if ($env{'form.renamed'} eq '') { + return &mt('The folder "[_1]" may not be renamed to "[_2]" as the new name you requested is an invalid name.',$folder,$newname); + } + if (defined($permfolders{$newname})) { + return &mt('The folder "[_1]" may not be renamed to "[_2]" as the new name you requested is reserved for folders provided automatically by the system.',$folder,$newname); + } + my %userfolders = &Apache::lonmsg::get_user_folders(); + if (defined($userfolders{$newname})) { + return &mt('The folder "[_1]" may not be renamed to "[_2]" because the new name you requested is already being used for an existing folder.',$folder,$newname); + } + if (!defined($userfolders{$folder})) { + return &mt('The folder "[_1]" could not be renamed to "[_2]" because the folder does not exist.',$folder,$newname); + } + my %folderinfo; + if (ref($userfolders{$folder}) eq 'HASH') { + %folderinfo = %{$userfolders{$folder}}; + } else { + %folderinfo = ( id => $folder, + created => $userfolders{$folder},); + } + my $outcome = + &Apache::lonnet::put('email_folders',{$newname => \%folderinfo}); + if ($outcome eq 'ok') { + $outcome = &Apache::lonnet::del('email_folders',[$folder]); + } + return $outcome; +} + +sub get_msgfolder_lock { + # get lock for mail folder counter. + my $lockhash = { "\0".'lock_counter' => time, }; + my $tries = 0; + my $gotlock = &Apache::lonnet::newput('email_folders',$lockhash); + while (($gotlock ne 'ok') && $tries <3) { + $tries ++; + sleep(1); + $gotlock = &Apache::lonnet::newput('email_folders',$lockhash); + } + return $gotlock; +} + +sub release_msgfolder_lock { + # remove lock + my @del_lock = ("\0".'lock_counter'); + my $dellockoutcome=&Apache::lonnet::del('email_folders',\@del_lock); + if ($dellockoutcome ne 'ok') { + return ('
'.&mt('Warning: failed to release lock for counter').'
'); + } else { + return 'ok'; + } +} + + # ======================================================== Move between folders sub movemsg { @@ -350,10 +577,10 @@ sub disgroup { $result.=''. '
'.$lt{$status}. ''. - ''. '  '. - ''. '

'. &Apache::loncommon::start_data_table(). @@ -520,6 +747,7 @@ sub sortedmessages { my ($blocked,$startblock,$endblock,$numblocked,$folder) = @_; my $suffix=&Apache::lonmsg::foldersuffix($folder); my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix); + #unpack the varibles and repack into temp for sorting my @temp; my %descriptions; @@ -623,7 +851,7 @@ sub get_course_desc { if (defined($env{'course.'.$fromcid.'.description'})) { $description = $env{'course.'.$fromcid.'.description'}; } else { - my %courseinfo=&Apache::lonnet::coursedescription($fromcid); $description = $courseinfo{'description'}; + my %courseinfo=&Apache::lonnet::coursedescription($fromcid); $description = $courseinfo{'description'}; } $$descriptions{$fromcid} = $description; @@ -640,7 +868,7 @@ sub disnew { my %lt=&Apache::lonlocal::texthash( 'nm' => 'New Messages', 'su' => 'Subject', - 'co' => 'Course/Group', + 'co' => 'Course', 'da' => 'Date', 'us' => 'Username', 'op' => 'Open', @@ -669,14 +897,14 @@ sub disnew { $blocked{$id} = 'ON'; $numblocked ++; } else { - push @newmsgs, { + push(@newmsgs, { msgid => $msgid, sendtime => $sendtime, shortsub => $shortsubj, from => $fromname, fromdom => $fromdom, - course => $description - } + course => $description, + }); } } } @@ -684,18 +912,18 @@ sub disnew { if ($#newmsgs >= 0) { $r->print(<$lt{'nm'} - +
 
TABLEHEAD foreach my $msg (@newmsgs) { $r->print(<<"ENDLINK"); - + ENDLINK foreach my $item ('sendtime','from','fromdom','shortsub','course') { $r->print(""); } - $r->print(""); + $r->print(""); } $r->print('
  $lt{'da'}$lt{'us'}$lt{'do'}$lt{'su'}$lt{'co'}
$lt{'op'}$lt{'op'}$msg->{$item}
'); } elsif ($numblocked == 0) { @@ -773,7 +1001,7 @@ ENDDISHEADER if ($lastdis>$#temp) { $lastdis=$#temp; } $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber)); $r->print('
'. - '
 '); + ''); } else { @@ -799,9 +1027,9 @@ ENDDISHEADER } $r->print('
 '); if ($env{'form.sortedby'} eq "revdate") { $r->print(''.&mt('Date').''); if ($env{'form.sortedby'} eq "revcourse") { - $r->print(''.&mt('Course/Group').''); + $r->print(''.&mt('Course').''); } else { - $r->print(''.&mt('Course/Group').''); + $r->print(''.&mt('Course').''); } $r->print(''); if ($env{'form.sortedby'} eq "revstatus") { @@ -864,12 +1092,14 @@ ENDDISHEADER '

'); } $r->print('

'); - my @allfolders=&Apache::lonnet::getkeys('email_folders'); - if ($allfolders[0]=~/^error:/) { @allfolders=(); } + my %gotfolders = &Apache::lonmsg::get_user_folders(); + my %userfolders; + foreach my $key (keys(%gotfolders)) { + $userfolders{$key} = $key; + } $r->print( &Apache::loncommon::select_form('','movetofolder', - ( map { $_ => $_ } @allfolders)) - ); + %userfolders)); my $postedstartdis=$startdis+1; $r->print(''); if ($numblocked > 0) { @@ -925,13 +1155,17 @@ sub compout { my $dismsg=''; my $disbase=''; my $func=&mt('Send New'); - my %lt=&Apache::lonlocal::texthash('us' => 'Username', - 'do' => 'Domain', - 'ad' => 'Additional Recipients', - 'sb' => 'Subject', - 'ca' => 'Cancel', - 'ma' => 'Mail'); - + my %lt=&Apache::lonlocal::texthash('us' => 'Username', + 'do' => 'Domain', + 'ad' => 'Additional Recipients', + 'sb' => 'Subject', + 'ca' => 'Cancel', + 'ma' => 'Mail', + 'gen' => 'Generate messages from a file', + 'gmt' => 'General message text', + 'tff' => 'The file format for the uploaded portion of the message is', + 'uas' => 'Upload and Send', + ); if (&Apache::lonnet::allowed('srm',$env{'request.course.id'}) || &Apache::lonnet::allowed('srm',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { @@ -1030,7 +1264,7 @@ sub compout { my $latexHelp = Apache::loncommon::helpLatexCheatsheet(); if ($broadcast ne 'upload') { $r->print(<<"ENDCOMP"); -

$lt{'ad'}
username:domain,username:domain, ... +
$lt{'ad'}:
username:domain,username:domain, ...
$lt{'sb'}: @@ -1055,31 +1289,34 @@ ENDCOMP $env{'form.group'}.'" />'); } } else { # $broadcast is 'upload' - $r->print(<print(< -

Generate messages from a file

+

$lt{'gen'}

Subject:

-

General message text
+

$lt{'gmt'}:

-The file format for the uploaded portion of the message is: -

-username1:domain1: text
-username2:domain2: text
-username3:domain1: text
-
+$lt{'tff'}: +ENDBLOCK + $r->print(' +
'."\n".
+&mt('username1:domain1: text')."\n".
+&mt('username2:domain2: text')."\n".
+&mt('username3:domain1: text')."\n".
+'

-The messages will be assembled from all lines with the respective -username:domain, and appended to the general message text.

+'.&mt('The messages will be assembled from all lines with the respective'."\n".'username:domain, and appended to the general message text.')); + $r->print(<

$dispcrit -

+

ENDUPLOAD } if ($broadcast eq 'group') { @@ -1116,8 +1353,8 @@ sub retrieve_instructor_comments { my ($user,$domain)=@_; my $target=$env{'form.grade_target'}; if (! $env{'request.course.id'}) { return; } - if (! &Apache::lonnet::allowed('srm',$env{'request.course.id'}) - && ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + if (! &Apache::lonnet::allowed('dff',$env{'request.course.id'}) + && ! &Apache::lonnet::allowed('dff',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { return; } @@ -1143,10 +1380,10 @@ sub disfacetoface { my ($r,$user,$domain)=@_; my $target=$env{'form.grade_target'}; unless ($env{'request.course.id'}) { return; } - if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) - && ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + if (!&Apache::lonnet::allowed('dff',$env{'request.course.id'}) + && ! &Apache::lonnet::allowed('dff',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { - $r->print('Not allowed'); + $r->print(&mt('Not allowed')); return; } my %records=&Apache::lonnet::dump('nohist_email', @@ -1225,10 +1462,10 @@ sub general_message { sub facetoface { my ($r,$stage)=@_; - if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) - && ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + if (!&Apache::lonnet::allowed('dff',$env{'request.course.id'}) + && ! &Apache::lonnet::allowed('dff',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { - $r->print('Not allowed'); + $r->print(&mt('Not allowed')); return; } my $crstype = &Apache::loncommon::course_type(); @@ -1315,7 +1552,8 @@ sub examblock { 'cbds' => 'Communication blocking during scheduled exams', 'desc' => "You can use communication blocking to prevent $usertype enrolled in this course from displaying LON-CAPA messages sent by other $usertype during an online exam. As blocking of communication could potentially interrupt legitimate communication between $usertype who are also both enrolled in a different LON-CAPA course, please be careful that you select the correct start and end times for your scheduled exam when setting or modifying these parameters.", 'mecb' => 'Modify existing communication blocking periods', - 'ncbc' => 'No communication blocks currently stored' + 'ncbc' => 'No communication blocks currently stored', + 'stor' => 'Store', ); my %ltext = &Apache::lonlocal::texthash( @@ -1354,7 +1592,7 @@ sub examblock { $r->print(<<"END");
- + $end_page END @@ -1365,10 +1603,6 @@ sub blockstore { my $r = shift; my %lt=&Apache::lonlocal::texthash( 'tfcm' => 'The following changes were made', - 'cbps' => 'communication blocking period(s)', - 'werm' => 'was/were removed', - 'wemo' => 'was/were modified', - 'wead' => 'was/were added', 'ncwm' => 'No changes were made.' ); my %adds = (); @@ -1425,13 +1659,13 @@ sub blockstore { if ($chgestotal > 0) { $r->print($lt{'tfcm'}.'
    '); if ($canceltotal > 0) { - $r->print('
  • '.$canceltotal.' '.$lt{'cbps'},' '.$lt{'werm'}.'
  • '); + $r->print('
  • '.&mt('[quant,_1,communication blocking period was,communication blocking periods were] removed.',$canceltotal).'
  • '); } if ($modtotal > 0) { - $r->print('
  • '.$modtotal.' '.$lt{'cbps'},' '.$lt{'wemo'}.'
  • '); + $r->print('
  • '.&mt('[quant,_1,communication blocking period was,communication blocking periods were] modified.',$modtotal).'
  • '); } if ($addtotal > 0) { - $r->print('
  • '.$addtotal.' '.$lt{'cbps'},' '.$lt{'wead'}.'
  • '); + $r->print('
  • '.&mt('[quant,_1,communication blocking period was,communication blocking periods were] added.',$addtotal).'
  • '); } $r->print('
'); } else { @@ -2056,7 +2290,7 @@ sub handler { unless ($dismode) { $dismode=''; } else { - $sqs.='&dismode='.&escape($dismode); + $sqs.='&dismode='.&escape($dismode); } # --------------------------------------------------------------------- Display @@ -2207,11 +2441,43 @@ sub handler { } } elsif ($env{'form.newfolder'}) { &printheader($r,'','New Folder'); - &makefolder($env{'form.newfolder'}); - &Apache::loncommunicate::menu($r); - &disall($r,$env{'form.newfolder'}); + my $showfolder = $env{'form.newfolder'}; + my ($makeresult,$warning) = &makefolder($env{'form.newfolder'}); + if ($makeresult eq 'ok') { + $r->print(&mt('Mail folder "[_1]" created.',$showfolder).'
'); + } else { + $r->print(&mt('Creation failed.').' '.$makeresult.'
'. + $warning); + $showfolder = $folder; + } + &Apache::loncommunicate::menu($r); + &disall($r,$showfolder); } elsif ($env{'form.showcommentbaseurl'}) { &storedcommentlisting($r); + } elsif ($env{'form.folderaction'} eq 'delete') { + &printheader($r,'','Deleted Folder'); + my $showfolder = ''; + my $delresult = &deletefolder($folder); + if ($delresult eq 'ok') { + $r->print(&mt('Mail folder "[_1]" deleted.',$folder).'
'); + } else { + $r->print(&mt('Deletion failed.').' '.$delresult.'
'); + $showfolder = $folder; + } + &Apache::loncommunicate::menu($r); + &disall($r,$showfolder); + } elsif ($env{'form.folderaction'} eq 'rename') { + &printheader($r,'','Renamed Folder'); + my $showfolder = $env{'form.renamed'}; + my $renresult = &renamefolder($folder); + if ($renresult eq 'ok') { + $r->print(&mt('Mail folder "[_1]" renamed "[_2]".',$folder,$showfolder).'
'); + } else { + $r->print(&mt('Renaming failed.').' '.$renresult.'
'); + $showfolder = $folder; + } + &Apache::loncommunicate::menu($r); + &disall($r,$showfolder); } else { &printheader($r,'','Display All Messages'); &Apache::loncommunicate::menu($r);