--- loncom/interface/lonmsgdisplay.pm 2006/12/07 21:21:04 1.49
+++ loncom/interface/lonmsgdisplay.pm 2009/08/28 23:29:45 1.114.2.1
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines for messaging display
#
-# $Id: lonmsgdisplay.pm,v 1.49 2006/12/07 21:21:04 albertel Exp $
+# $Id: lonmsgdisplay.pm,v 1.114.2.1 2009/08/28 23:29:45 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -33,12 +33,13 @@ package Apache::lonmsgdisplay;
=head1 NAME
-Apache::lonmsg: supports internal messaging
+Apache::lonmsgdisplay: supports internal messaging
=head1 SYNOPSIS
-lonmsg provides routines for sending messages, receiving messages, and
-a handler to allow users to read, send, and delete messages.
+lonmsgdisplay provides a handler to allow users to read, send,
+and delete messages, and to create and delete message folders,
+and to move messages between folders.
=head1 OVERVIEW
@@ -74,8 +75,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,
@@ -93,25 +94,6 @@ addresses on their B screen, but g
are much more useful than traditional email can be made to be, even
with HTML support.
-Right now, this document will cover just how to send a message, since
-it is likely you will not need to programmatically read messages,
-since lonmsg already implements that functionality.
-
-The routines used to package messages and unpackage messages are not
-only used by lonmsg when creating/extracting messages for LON-CAPA's
-internal messaging system, but also by lonnotify.pm which is available
-for use by Domain Coordinators to broadcast standard e-mail to specified
-users in their domain. The XML packaging used in the two cases is very
-similar. The differences are the use of $uname and
-$udom in stored internal messages, compared
-with $email in stored
-Domain Coordinator e-mail for the storage of information about
-recipients of the message/e-mail.
-
-=head1 FUNCTIONS
-
-=over 4
-
=cut
use strict;
@@ -119,6 +101,7 @@ use Apache::lonnet;
use HTML::TokeParser();
use Apache::Constants qw(:common);
use Apache::loncommon();
+use Apache::lonhtmlcommon();
use Apache::lontexconvert();
use HTML::Entities();
use Apache::lonlocal;
@@ -132,17 +115,25 @@ use LONCAPA;
# Querystring component with sorting type
my $sqs;
my $startdis;
-my $interdis;
# ============================================================ List all folders
sub folderlist {
- my $folder=shift;
+ my ($folder,$msgstatus) = @_;
my %lt = &Apache::lonlocal::texthash(
actn => 'Action',
fold => 'Folder',
show => 'Show',
+ status => 'Message Status',
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(
@@ -152,6 +143,10 @@ sub folderlist {
);
$actions{'select_form_order'} = ['view','rename','delete'];
+ my %statushash = &get_msgstatus_types();
+
+ $statushash{'select_form_order'} = ['','new','read','replied','forwarded'];
+
my %permfolders = &get_permanent_folders();
my $permlist = join("','",sort(keys(%permfolders)));
my ($permlistkeys,$permlistvals);
@@ -165,6 +160,7 @@ sub folderlist {
my %userfolders;
foreach my $key (keys(%gotfolders)) {
+ $key =~ s/(['"])/\$1/g; #' stupid emacs
$userfolders{$key} = $key;
}
my @userorder = sort(keys(%userfolders));
@@ -172,7 +168,7 @@ sub folderlist {
my $folderlist = join("','",@userorder);
$folderlist .= "','".$permlistvals;
- $formhash{'select_form_order'} = ['','critical','new',@userorder,'sent','trash'];
+ $formhash{'select_form_order'} = ['','critical',@userorder,'sent','trash'];
my $output = qq||;
+ my %show = ('select_form_order' => [10,20,50,100,200],
+ map {$_=>$_} (10,20,50,100,200));
+
+
$output .= '
':'');
+ ($folder=~/^critical/?'':'');
return $output;
}
@@ -261,25 +261,43 @@ sub get_permanent_folders {
my %permfolders =
&Apache::lonlocal::texthash('' => 'INBOX',
'trash' => 'TRASH',
- 'new' => 'New Messages Only',
'critical' => 'Critical',
'sent' => 'Sent Messages',
);
return %permfolders;
}
+sub get_msgstatus_types {
+ my %statushash = &Apache::lonlocal::texthash(
+ '' => 'Any',
+ new => 'Unread',
+ read => 'Read',
+ replied => 'Replied to',
+ forwarded => 'Forwarded',
+ );
+ return %statushash;
+}
+
sub scrollbuttons {
- my ($start,$maxdis,$first,$finish,$total)=@_;
+ my ($start,$maxdis,$first,$finish,$total,$msgstatus)=@_;
unless ($total>0) { return ''; }
$start++; $maxdis++;$first++;$finish++;
+
+ my %statushash = &get_msgstatus_types();
+ my $status;
+ if ($msgstatus eq '') {
+ $status = &mt('All');
+ } else {
+ $status = $statushash{$msgstatus};
+ }
return
- &mt('Page').': '.
+ ''.&mt('Page').': '.
''.
''.
' of '.$maxdis.
''.
' '.
- &mt('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'';
+ &mt('[_1] messages: showing messages [_2] through [_3] of [_4].',$status,$first,$finish,$total).'';
}
# =============================================================== Status Change
@@ -335,7 +353,7 @@ sub makefolder {
}
} else {
$outcome =
- &mt('Error - could not obtain lock on email folders record.');
+ &mt('Error - could not obtain lock on message folders record.');
}
return ($outcome,$warning);
}
@@ -346,18 +364,18 @@ sub deletefolder {
my ($folder)=@_;
my %permfolders = &get_permanent_folders();
if (defined($permfolders{$folder})) {
- return &mt('The folder [_1] may not be deleted',$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.',
+ 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.').
+ return &mt('The folder "[_1]" contains messages so it may not be deleted.',$folder).
' '.
&mt('Delete or move the messages to a different folder first.');
}
@@ -372,6 +390,9 @@ sub renamefolder {
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{$folder})) {
+ return &mt('The folder "[_1]" may not be renamed as it is a folder provided by the system.',$folder);
+ }
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);
}
@@ -481,7 +502,8 @@ sub movemsg {
# ======================================================= Display a course list
sub discourse {
- my $result;
+ my ($statushash) = @_;
+ my ($result,$active,$previous,$future);
my ($course_personnel,
$current_members,
$expired_members,
@@ -490,51 +512,80 @@ sub discourse {
unshift @$current_members, (@$course_personnel);
my %defaultUsers;
- $result .= ''."\n";
+ my $tmptext;
+ if ($tmptext = &Apache::lonselstudent::render_student_list($current_members,
+ "activeusers",
+ "current",
+ \%defaultUsers,
+ 1,"selectedusers",1,'email')
+ ) {
+ $result .= ' ';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'active'} = 1;
+ }
+ }
+ if ($tmptext = &Apache::lonselstudent::render_student_list($expired_members,
+ "previoususers",
+ "expired",
+ \%defaultUsers,
+ 1, "selectedusers",0,'email')
+ ) {
+ $result .= ' ';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'previous'} = 1;
+ }
- $result .= &Apache::lonselstudent::render_student_list($current_members,
- "compemail",
- "current",
- \%defaultUsers,
- 1,"selectedusers",1);
-
- $result .= &Apache::lonselstudent::render_student_list($expired_members,
- "compemail",
- "expired",
- \%defaultUsers,
- 1, "selectedusers",0);
- $result .= &Apache::lonselstudent::render_student_list($future_members,
- "compemail",
- "future",
- \%defaultUsers,
- 1, "selectedusers", 0);
+ }
+ if ($tmptext = &Apache::lonselstudent::render_student_list($future_members,
+ "futureusers",
+ "future",
+ \%defaultUsers,
+ 1, "selectedusers",0,'email')
+ ) {
+ $result .= '';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'future'} = 1;
+ }
+
+ }
return $result;
}
sub disgroup {
- my ($cdom,$cnum,$group,$viewgrps,$editgrps) = @_;
- my $result;
+ my ($r,$cdom,$cnum,$group,$access_status) = @_;
+ my $hasfloat;
# Needs to be in a course
if (!($env{'request.course.fn'})) {
- $result = &mt('Error: you must have a course role selected to be able to send a broadcast message to a group in the course.');
- return $result;
+ $r->print(''.&mt('Error: you must have a course role selected to be able to send a broadcast message to a group in the course.').'');
+ return;
}
if ($cdom eq '' || $cnum eq '') {
- $result = &mt('Error: could not determine domain or number of course');
- return $result;
+ $r->print(''.&mt('Error: could not determine domain or number of course').'');
+ return;
}
my ($memberinfo,$numitems) =
&Apache::longroup::group_memberlist($cdom,$cnum,$group,{},[]);
my @statustypes = ('active');
+ my $viewgrps = &Apache::lonnet::allowed('vcg',$env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
+ my $editgrps = &Apache::lonnet::allowed('mdg',$env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
if ($viewgrps || $editgrps) {
push(@statustypes,('future','previous'));
}
if (keys(%{$memberinfo}) == 0) {
- $result = &mt('As this group has no members, there are no '.
- 'recipients to select.');
- return $result;
+ $r->print(''.
+ &mt('As this group has no members, there are no recipients to select').
+ '');
+ return;
} else {
- $result = &mt('Select message recipients from the group members listed below. ');
+ $hasfloat = 1;
+ unless($env{'environment.wysiwygeditor'} eq 'on') {
+ $r->print('
');
+ }
my %Sortby = (
active => {},
previous => {},
@@ -544,9 +595,9 @@ sub disgroup {
'name' => 'Name',
'usnm' => 'Username',
'doma' => 'Domain',
- 'active' => 'Active Members',
- 'previous' => 'Former Members',
- 'future' => 'Future Members',
+ 'active' => 'Broadcast to Active Members',
+ 'previous' => 'Broadcast (Bcc) to Former Members',
+ 'future' => 'Broadcast (Bcc) to Future Members',
);
foreach my $user (sort(keys(%{$memberinfo}))) {
my $status = $$memberinfo{$user}{status};
@@ -560,71 +611,75 @@ sub disgroup {
push(@{$Sortby{$status}{$$memberinfo{$user}{fullname}}},$user);
}
}
- $result .= &group_check_uncheck();
- $result .= '
'.
- '
';
+ $r->print(&group_check_uncheck());
foreach my $status (@statustypes) {
if (ref($numitems) eq 'HASH') {
if ((defined($$numitems{$status})) && ($$numitems{$status})) {
- $result.='
'.&mt('You have not replied to any messages in this folder.').'
');
+ } else {
+ $r->print('
'.&mt('There are no '.lc($statushash{$msgstatus}).' messages in this folder.').'
');
+ }
+ if ($numblocked > 0) {
+ $r->print(&blocked_in_folder($numblocked,$startblock,$endblock,
+ \%setters));
+ }
return;
}
- unless ($interdis) {
- $interdis=20;
- }
+ my $interdis = $env{'form.interdis'};
my $number=int($totalnumber/$interdis);
+ if ($totalnumber%$interdis == 0) {
+ $number--;
+ }
+
if (($startdis<0) || ($startdis>$number)) { $startdis=$number; }
my $firstdis=$interdis*$startdis;
if ($firstdis>$#temp) { $firstdis=$#temp-$interdis+1; }
my $lastdis=$firstdis+$interdis-1;
if ($lastdis>$#temp) { $lastdis=$#temp; }
- $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber));
+ $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber,$msgstatus));
$r->print('');
+ $r->print('');
if ($numblocked > 0) {
- my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
- my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
- $r->print('
'.
- &mt('[_1,quant,message is, messages are] not viewable because display of LON-CAPA messages sent to you by other students between [_2] and [_3] is currently being blocked because of online exams.',$numblocked,$beginblock,$finishblock));
- $r->print(&Apache::loncommon::build_block_table($startblock,$endblock,
- \%setters));
+ $r->print(&blocked_in_folder($numblocked,$startblock,$endblock,
+ \%setters));
}
}
+sub blocked_in_folder {
+ my ($numblocked,$startblock,$endblock,$setters) = @_;
+ my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
+ my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
+ my $output = '
'.
+ &mt('[quant,_1,message is, messages are] not viewable because display of LON-CAPA messages sent to you by other students between [_2] and [_3] is currently being blocked because of online exams.',$numblocked,$beginblock,$finishblock);
+ $output .= &Apache::loncommon::build_block_table($startblock,$endblock,
+ $setters);
+ return $output;
+}
+
# ============================================================== Compose output
sub compout {
- my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode)=@_;
+ my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode,
+ $multiforward)=@_;
my $suffix=&Apache::lonmsg::foldersuffix($folder);
my ($cdom,$cnum,$group,$refarg);
if (exists($env{'form.group'})) {
@@ -1137,6 +1239,20 @@ sub compout {
} elsif ($replycrit) {
$r->print('
'.&mt('Replying to a Critical Message').'
');
$replying=$replycrit;
+ } elsif ($multiforward) {
+ &Apache::lonhtmlcommon::add_breadcrumb
+ ({href=>"/adm/email?folder=".&escape($folder),
+ text=>"Display All Messages"});
+ &printheader($r,'/adm/email?compose=multiforward',
+ 'Forwarding Multiple Messages');
+ if ($multiforward > 1) {
+ $r->print(&mt('Each of the [quant,_1,message] you checked'
+ .' will be forwarded to the recipient(s) you select below.',$multiforward)
+ .' ');
+ } else {
+ $r->print(&mt('The message you checked will be forwarded to the recipient(s) you select below.').' ');
+ }
+
} else {
&printheader($r,'/adm/email?compose=upload',
'Distribute from Uploaded File');
@@ -1146,37 +1262,124 @@ sub compout {
my $dissub='';
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 $attachrow;
+ my $func1='Send'; # do not translate here!
+ my %func2=( # do not translate here!
+ 'ma' => 'Message',
+ 'msg' => 'Messages',
+ );
+ my %lt=&Apache::lonlocal::texthash('us' => 'Username',
+ 'do' => 'Domain',
+ 'ad' => 'Additional Recipients',
+ 'rt' => 'Reply to',
+ 'ar' => 'Allow replies',
+ 'sb' => 'Subject',
+ 'ca' => 'Cancel',
+ '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',
+ 'atta' => 'Attachment',
+ 'to' => 'To:',
+ );
+ my %attachmax = (
+ text => &mt('(128 KB max size)'),
+ num => 131072,
+ );
+ if (!$forwarding && !$multiforward) {
+ $attachrow = '
'.$lt{'atta'}.' '.$attachmax{'text'}.':
';
+ }
if (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
|| &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
'/'.$env{'request.course.sec'})) {
my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
$dispcrit=
- '
' . $crithelp .
- '
'.
- '' . $crithelp .
- '
'.
-'';
- }
+ ''.$crithelp.' '.&mt('Require return receipt?').' '.
+ ' '.
+' ';
+ }
+ if ($broadcast ne 'group') {
+ if (&Apache::lonnet::allowed('dff',$env{'request.course.id'}) ||
+ &Apache::lonnet::allowed('dff',$env{'request.course.id'}.
+ '/'.$env{'request.course.sec'})) {
+
+ $dispcrit.=' ';
+ }
+ }
+
my %message;
my %content;
+ my ($hasfloat,$broadcast_js,$sendmode,$can_grp_broadcast);
my $defdom=$env{'user.domain'};
+ if ($broadcast eq 'group') {
+ my %access_status = (
+ active => 0,
+ previous => 0,
+ future => 0,
+ );
+
+ if ($group eq '') {
+ my $studentsel = &discourse(\%access_status);
+ if ($studentsel) {
+ if ($env{'environment.wysiwygeditor'} eq 'on') {
+ $r->print($studentsel);
+ } else {
+ $r->print('
'.
+ &mt('Could not forward [quant,_1,message].',$count).
+ ' ');
+ foreach my $key (keys(%forwardfail)) {
+ $r->print(&mt('Could not deliver forwarded message.').' '.
+ &mt('The recipient addresses may need to be corrected').' ('.$forwardfail{$key}.').