--- loncom/interface/lonfeedback.pm 2006/11/29 03:23:02 1.220 +++ loncom/interface/lonfeedback.pm 2008/11/18 19:14:22 1.256 @@ -1,7 +1,7 @@ # The LearningOnline Network # Feedback # -# $Id: lonfeedback.pm,v 1.220 2006/11/29 03:23:02 raeburn Exp $ +# $Id: lonfeedback.pm,v 1.256 2008/11/18 19:14:22 jms Exp $ # # Copyright Michigan State University Board of Trustees # @@ -27,6 +27,133 @@ # ### +=pod + +=head1 NAME + +Apache::lonfeedback.pm + +=head1 SYNOPSIS + +Handles feedback from students to instructors and system administrators. + +Provides a screenshot of the current resource, as well as previous attempts if the resource was a homework. + +Used by lonmsg.pm. + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 OVERVIEW + +None + +=head1 SUBROUTINES + +=over + +=item discussion_open() + +=item discussion_visible() + +=item list_discussion() + +=item send_feedback_link() + +=item send_message_link() + +=item action_links_bar() + +=item postingform_display() + +=item build_posting_display + +=item filter_regexp() + +=item get_post_contents() + +=item replicate_attachments() + +=item mail_screen() + +=item print_display_options() + +=item print_sortfilter_options() + +=item print_showposters() + +=item get_post_versions() + +=item get_post_attachments() + +=item fail_redirect() + +=item redirect_back() + +=item no_redirect_back() + +=item screen_header() + +=item resource_output() + +=item clear_out_html() + +=item assemble_email() + +=item feedback_available() + +=item send_msg() + +=item adddiscuss() + +=item get_discussion_info() + +=item show_preview() + +=item newline_to_br() + +=item generate_preview_button() + +=item modify_attachments() + +=item process_attachments() + +=item generate_attachments_button() + +=item extract_attachments() + +=item construct_attachmenturl() + +=item add_blog_checkbox() + +=item has_discussion() + +=item sort_filter_names() + +=item handler() + +=item blocked_reply_or_edit() + +=item wrap_symb() + +=item dewrapper() + +=item get_feedurl() + +=item get_feedurl_and_clean_symb() + +=item editing_allowed() + +=item check_group_priv() + +=item group_args() + +=item get_resource_title() + +=back + +=cut + package Apache::lonfeedback; use strict; @@ -44,7 +171,6 @@ use HTML::LCParser(); use Apache::lonspeller(); use Apache::longroup; use Cwd; -use lib '/home/httpd/lib/perl/'; use LONCAPA; sub discussion_open { @@ -75,6 +201,9 @@ sub discussion_visible { sub list_discussion { my ($mode,$status,$ressymb,$imsextras,$group)=@_; + unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); } + unless ($ressymb) { return ''; } + $ressymb=&wrap_symb($ressymb); my $outputtarget=$env{'form.grade_target'}; if (defined($env{'form.export'})) { if($env{'form.export'}) { @@ -86,13 +215,28 @@ sub list_discussion { $outputtarget = 'export'; } } - if (not &discussion_visible($status)) { return ''; } + if (not &discussion_visible($status)) { + if ($mode ne 'board') { + &Apache::lonenc::check_encrypt(\$ressymb); + return '
'.&send_message_link($ressymb); + } + } if ($group ne '' && $mode eq 'board') { if (&check_group_priv($group,'vgb') ne 'ok') { return ''; } } + my ($blocked,$blocktext) = + &Apache::loncommon::blocking_status('boards'); + if ($blocked) { + &Apache::lonenc::check_encrypt(\$ressymb); + if ($mode ne 'board') { + $blocktext.='
'.&send_message_link($ressymb); + } + return $blocktext; + } + my @bgcols = ("#cccccc","#eeeeee"); my $discussiononly=0; if ($mode eq 'board') { $discussiononly=1; } @@ -103,9 +247,6 @@ sub list_discussion { $crs.='_'.$env{'request.course.sec'}; } $crs=~s/\_/\//g; - unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); } - unless ($ressymb) { return ''; } - $ressymb=&wrap_symb($ressymb); my $encsymb=&Apache::lonenc::check_encrypt($ressymb); my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs) && ($ressymb=~/\.(problem|exam|quiz|assess|survey|form|task)$/)); @@ -133,7 +274,7 @@ sub list_discussion { my $previous = 0; my $visit = 0; my $newpostsflag = 0; - my @posters = split/\&/,$dischash{$userpickkey}; + my @posters = split(/\&/,$dischash{$userpickkey}); # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts. &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']); @@ -162,19 +303,19 @@ sub list_discussion { my ($classgroups,$studentgroups); if ($env{'form.rolefilter'}) { %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); - foreach (keys %roleshash) { - my ($role,$uname,$udom,$sec) = split/:/,$_; + foreach my $rolekey (keys(%roleshash)) { + my ($role,$uname,$udom,$sec) = split(/:/,$rolekey); if ($role =~ /^cr/) { $role = 'cr'; } - my ($end,$start) = split/:/,$roleshash{$_}; + my ($end,$start) = split(/:/,$roleshash{$rolekey}); my $now = time; my $status = 'Active'; if (($now < $start) || ($end > 0 && $now > $end)) { $status = 'Expired'; } if ($uname && $udom) { - push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status; + push(@{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status); } } my ($classlist,$keylist) = @@ -184,7 +325,7 @@ sub list_discussion { while (my ($student,$data) = each %$classlist) { my ($section,$status) = ($data->[$sec_index], $data->[$status_index]); - push @{$roleinfo{$student}}, 'st:'.$section.':'.$status; + push(@{$roleinfo{$student}}, 'st:'.$section.':'.$status); } ($classgroups,$studentgroups) = &Apache::loncoursedata::get_group_memberships($classlist,$keylist, @@ -421,55 +562,10 @@ imscp_v1p1.xsd http://www.imsglobal.org/ |; $discussion.='
'; - $discussion .=''; - + $discussion .= &action_links_bar($colspan,$ressymb,$visible, + $newpostsflag,$group, + $prevread,$markondisp); + my $escsymb=&escape($ressymb); my $numhidden = keys(%notshown); if ($numhidden > 0) { my $colspan = $maxdepth+1; @@ -493,39 +589,39 @@ imscp_v1p1.xsd http://www.imsglobal.org/ # Choose sort mechanism my @showposts = (); if ($sortposts eq 'descdate') { - @showposts = (sort { $b <=> $a } keys %alldiscussion); + @showposts = (sort { $b <=> $a } keys(%alldiscussion)); } elsif ($sortposts eq 'thread') { - @showposts = (sort { $a <=> $b } keys %alldiscussion); + @showposts = (sort { $a <=> $b } keys(%alldiscussion)); } elsif ($sortposts eq 'subject') { - foreach (sort keys %subjectsort) { - push @showposts, @{$subjectsort{$_}}; + foreach my $key (sort(keys(%subjectsort))) { + push(@showposts, @{$subjectsort{$key}}); } } elsif ($sortposts eq 'username') { - foreach my $domain (sort keys %usernamesort) { - foreach (sort keys %{$usernamesort{$domain}}) { - push @showposts, @{$usernamesort{$domain}{$_}}; + foreach my $domain (sort(keys(%usernamesort))) { + foreach my $key (sort(keys(%{$usernamesort{$domain}}))) { + push(@showposts, @{$usernamesort{$domain}{$key}}); } } } elsif ($sortposts eq 'lastfirst') { - foreach my $last (sort keys %namesort) { - foreach (sort keys %{$namesort{$last}}) { - push @showposts, @{$namesort{$last}{$_}}; + foreach my $last (sort(keys(%namesort))) { + foreach my $key (sort(keys(%{$namesort{$last}}))) { + push(@showposts, @{$namesort{$last}{$key}}); } } } else { - @showposts = (sort { $a <=> $b } keys %alldiscussion); + @showposts = (sort { $a <=> $b } keys(%alldiscussion)); } my $currdepth = 0; my $firstidx = $alldiscussion{$showposts[0]}; - foreach (@showposts) { + foreach my $post (@showposts) { unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) { - $alldiscussion{$_} = $_; + $alldiscussion{$post} = $post; } - unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) { + unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) { if ($outputtarget ne 'tex' && $outputtarget ne 'export') { $discussion.="\n"; } - my $thisdepth=$depth[$alldiscussion{$_}]; + my $thisdepth=$depth[$alldiscussion{$post}]; if ($outputtarget ne 'tex' && $outputtarget ne 'export') { for (1..$thisdepth) { $discussion.=''; @@ -534,52 +630,52 @@ imscp_v1p1.xsd http://www.imsglobal.org/ my $colspan=$maxdepth-$thisdepth+1; if ($outputtarget eq 'tex') { #cleanup block - $discussionitems[$alldiscussion{$_}]=~s/]*)>/
'. - ''; - my $escsymb=&escape($ressymb); - if ($visible>2) { - $discussion.=''; - if ($newpostsflag) { - if (!$markondisp) { - $discussion .=''; - } - } else { - $discussion .= ''; - } - $discussion .= '
'. - ''.&mt('Threaded View').'  '. - ''.&mt('Chronological View').'   - '.&mt('Sorting/Filtering options').'  '; - } else { - $discussion .= ''; - } - $discussion .=''.&mt('Export').'?  '. - &mt('Preferences on what is marked as NEW'). - '
'.&mt('Mark NEW posts no longer new').''; - } else { - $discussion .= '
  
   
/; - $discussionitems[$alldiscussion{$_}]=~s/]*)>]*)>/
/; + $discussionitems[$alldiscussion{$post}]=~s/]*)>//; + $discussionitems[$alldiscussion{$post}]=~s/]*)>]*)>/'; } } @@ -652,8 +748,8 @@ END } if (@rolefilter > 0) { $filterchoice .= ''.&mt('roles').'-'; - foreach (@rolefilter) { - $filterchoice .= ' '.$role_types{$_}.','; + foreach my $role (@rolefilter) { + $filterchoice .= ' '.$role_types{$role}.','; } $filterchoice =~ s/,$//; $filterchoice .= '
        '; @@ -668,7 +764,7 @@ END } } if ($dischash{$toggkey}) { - my $storebutton = &mt('Store read/unread changes'); + my $storebutton = &mt('Save read/unread changes'); $discussion.=' -
/; my $threadinsert=''; if ($thisdepth > 0) { $threadinsert='
Reply: '.$thisdepth.''; } - $discussionitems[$alldiscussion{$_}]=~s/<\/td>]*)>/$threadinsert<\/td>
/; - $discussionitems[$alldiscussion{$_}]=~s/]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g; - $discussionitems[$alldiscussion{$_}]=~s/(|<\/b>|<\/a>|]+)>)//g; + $discussionitems[$alldiscussion{$post}]=~s/<\/td>]*)>/$threadinsert<\/td>/; + $discussionitems[$alldiscussion{$post}]=~s/]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g; + $discussionitems[$alldiscussion{$post}]=~s/(|<\/b>|<\/a>|]+)>)//g; - $discussionitems[$alldiscussion{$_}]='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.$discussionitems[$alldiscussion{$_}]; - $discussion.=$discussionitems[$alldiscussion{$_}]; + $discussionitems[$alldiscussion{$post}]='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.$discussionitems[$alldiscussion{$post}]; + $discussion.=$discussionitems[$alldiscussion{$post}]; } elsif ($outputtarget eq 'export') { - my $postfilename = $alldiscussion{$_}.'-'.$imsitems{$alldiscussion{$_}}{'timestamp'}.'.html'; + my $postfilename = $alldiscussion{$post}.'-'.$imsitems{$alldiscussion{$post}}{'timestamp'}.'.html'; if ($manifestok) { - if (($depth[$alldiscussion{$_}] <= $currdepth) && ($alldiscussion{$_} != $firstidx)) { + if (($depth[$alldiscussion{$post}] <= $currdepth) && ($alldiscussion{$post} != $firstidx)) { print $manifestfile ' '."\n"; } - $currdepth = $depth[$alldiscussion{$_}]; + $currdepth = $depth[$alldiscussion{$post}]; print $manifestfile "\n". - ''. - ''.$imsitems{$alldiscussion{$_}}{'title'}.''; + ''. + ''.$imsitems{$alldiscussion{$post}}{'title'}.''; $imsresources .= "\n". - ''."\n". + ''."\n". ''."\n". - $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'currversion'}}."\n". + $imsfiles{$alldiscussion{$post}}{$imsitems{$alldiscussion{$post}}{'currversion'}}."\n". ''; } my $postingfile; my $postingfilename = $tempexport.'/'.$postfilename; if ($postingfile = Apache::File->new('>'.$postingfilename)) { print $postingfile 'Discussion Post'. - $imsitems{$alldiscussion{$_}}{'title'}.' '. - $imsitems{$alldiscussion{$_}}{'sender'}. - $imsitems{$alldiscussion{$_}}{'timestamp'}.'

'. - $imsitems{$alldiscussion{$_}}{'message'}.'
'. - $imsitems{$alldiscussion{$_}}{'attach'}.''."\n"; + $imsitems{$alldiscussion{$post}}{'title'}.' '. + $imsitems{$alldiscussion{$post}}{'sender'}. + $imsitems{$alldiscussion{$post}}{'timestamp'}.'

'. + $imsitems{$alldiscussion{$post}}{'message'}.'
'. + $imsitems{$alldiscussion{$post}}{'attach'}.''."\n"; close($postingfile); } else { - $discussion .= $lt{'aerr'}.' '.$alldiscussion{$_}.'
'; + $discussion .= $lt{'aerr'}.' '.$alldiscussion{$post}.'
'; } - $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$_}}{'allattachments'},$tempexport); + $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$post}}{'allattachments'},$tempexport); } else { - $discussion.='
'. $discussionitems[$alldiscussion{$_}]. + $discussion.=''. $discussionitems[$alldiscussion{$post}]. '
'. ''."\n". '
-

END + $discussion .= &action_links_bar($colspan,$ressymb,$visible, + $newpostsflag,$group, + $prevread,$markondisp); + $discussion .= " +
+

\n"; } if ($outputtarget eq 'export') { if ($manifestok) { @@ -759,23 +859,94 @@ END } } } else { - $discussion.='
'; + $discussion.='
'; + if ($outputtarget ne 'tex') { + $discussion.= &send_message_link($ressymb); + } + $discussion.=''; + } + return $discussion; +} + +sub send_feedback_link { + my ($ressymb,$target) = @_; + my $output = ''. + ' '. + ''.&mt('Post Discussion').''; + return $output; +} + +sub send_message_link { + my ($ressymb) = @_; + my $output = ''. + ' '.&mt('Send Message').''; + return $output; +} + +sub action_links_bar { + my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp) = @_; + my $discussion = ''. + ''; + my $escsymb=&escape($ressymb); + if ($visible>2) { + $discussion .= ''; + if ($newpostsflag) { + if (!$markondisp) { + $discussion .=''; + } + } else { + $discussion .= ''; + } + $discussion .= '
'. + ''.&mt('Threaded View').'  '. + ''.&mt('Chronological View').'   + '.&mt('Sorting/Filtering options').'  '; + } else { + $discussion .= ''; + } + $discussion .=''.&mt('Export').'?  '. + &mt('Preferences on what is marked as NEW'). + '
'.&mt('Mark NEW posts no longer new').''; + } else { + $discussion .= '
  
'; return $discussion; } @@ -815,11 +986,16 @@ ENDDISCUSS if ($group ne '') { $postingform .=''; } + my $blockblog = &Apache::loncommon::blocking_status('blogs'); + if (!$blockblog) { + $postingform .= &add_blog_checkbox(); + } $postingform .= "\n"; if ($outputtarget ne 'tex') { $postingform .= &generate_attachments_button('',$attachnum,$ressymb, $now,$currnewattach, - $currdelold,'',$mode); + $currdelold,'',$mode, + $blockblog); if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) { $newattachmsg = '
'.$lt{'newa'}.'
'; if (@{$currnewattach} > 1) { @@ -851,6 +1027,9 @@ sub build_posting_display { $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); + my $see_anonymous = + &Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')); + if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) { $skip_group_check = 1; } @@ -901,7 +1080,7 @@ sub build_posting_display { $$visible++; if ($contrib{$idx.':history'}) { if ($contrib{$idx.':history'} =~ /:/) { - my @oldversions = split/:/,$contrib{$idx.':history'}; + my @oldversions = split(/:/,$contrib{$idx.':history'}); $numoldver = @oldversions; } else { $numoldver = 1; @@ -940,35 +1119,37 @@ sub build_posting_display { if ($subject eq '') { if (defined($$subjectsort{'__No subject'})) { - push @{$$subjectsort{'__No subject'}}, $idx; + push(@{$$subjectsort{'__No subject'}}, $idx); } else { @{$$subjectsort{'__No subject'}} = ("$idx"); } } else { if (defined($$subjectsort{$subject})) { - push @{$$subjectsort{$subject}}, $idx; + push(@{$$subjectsort{$subject}}, $idx); } else { @{$$subjectsort{$subject}} = ("$idx"); } } - if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) { + if (!$contrib{$idx.':anonymous'} || $see_anonymous) { $sender=&Apache::loncommon::aboutmewrapper( $plainname, $contrib{$idx.':sendername'}, $contrib{$idx.':senderdomain'}).' ('. - $contrib{$idx.':sendername'}.' at '. + $contrib{$idx.':sendername'}.':'. $contrib{$idx.':senderdomain'}.')'; if ($contrib{$idx.':anonymous'}) { $sender.=' ['.$$anonhash{$key}.'] '. $screenname; } - + if ($see_anonymous) { + $sender.=&Apache::loncommon::student_image_tag($contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'}); + } # Set up for sorting by domain, then username unless (defined($$usernamesort{$contrib{$idx.':senderdomain'}})) { %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = (); } if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) { - push @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx; + push(@{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx); } else { @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx"); } @@ -988,7 +1169,7 @@ sub build_posting_display { %{$$namesort{$lastname}} = (); } if (defined($$namesort{$lastname}{$firstname})) { - push @{$$namesort{$lastname}{$firstname}}, $idx; + push(@{$$namesort{$lastname}{$firstname}}, $idx); } else { @{$$namesort{$lastname}{$firstname}} = ("$idx"); } @@ -1044,7 +1225,7 @@ sub build_posting_display { %{$$usernamesort{'__anon'}} = (); } if (defined($$usernamesort{'__anon'}{'__anon'})) { - push @{$$usernamesort{'__anon'}{'__anon'}}, $idx; + push(@{$$usernamesort{'__anon'}{'__anon'}}, $idx); } else { @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx"); } @@ -1053,7 +1234,7 @@ sub build_posting_display { %{$$namesort{'__anon'}} = (); } if (defined($$namesort{'__anon'}{'__anon'})) { - push @{$$namesort{'__anon'}{'__anon'}}, $idx; + push(@{$$namesort{'__anon'}{'__anon'}}, $idx); } else { @{$$namesort{'__anon'}{'__anon'}} = ("$idx"); } @@ -1186,7 +1367,7 @@ sub build_posting_display { $$newitem{$idx} = 1; $$discussionitems[$idx] .= '

- '; + '; } else { $$newitem{$idx} = 0; $$discussionitems[$idx] .= ' @@ -1213,7 +1394,7 @@ sub build_posting_display { } $$discussionitems[$idx].='
'.&mt('Earlier version(s) were posted on: '); if ($contrib{$idx.':history'} =~ m/:/) { - @postversions = split/:/,$contrib{$idx.':history'}; + @postversions = split(/:/,$contrib{$idx.':history'}); } else { @postversions = ("$contrib{$idx.':history'}"); } @@ -1236,9 +1417,9 @@ sub filter_regexp { my $skiptest = 1; if (@{$rolefilter} > 0) { my @okrolefilter = (); - foreach (@{$rolefilter}) { - unless ($_ eq '') { - push @okrolefilter, $_; + foreach my $role (@{$rolefilter}) { + unless ($role eq '') { + push(@okrolefilter, $role); } } if (@okrolefilter > 0) { @@ -1256,9 +1437,9 @@ sub filter_regexp { } if (@{$sectionpick} > 0) { my @oksectionpick = (); - foreach (@{$sectionpick}) { - unless ($_ eq '') { - push @oksectionpick, $_; + foreach my $sec (@{$sectionpick}) { + unless ($sec eq '') { + push(@oksectionpick, $sec); } } if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) { @@ -1320,7 +1501,7 @@ sub get_post_contents { } &get_post_versions($messages,$$contrib{$idx.':message'},1); &get_post_versions($subjects,$$contrib{$idx.':subject'},1); - push @postversions,$$contrib{$idx.':timestamp'}; + push(@postversions,$$contrib{$idx.':timestamp'}); $end = @postversions; } else { &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver); @@ -1348,8 +1529,8 @@ sub get_post_contents { $$imsfiles{$idx}{$i} = ''; if ($attachmsg) { $$attachtxt{$i} = '
'.&mt('Attachments').':
'; - foreach (sort keys %currattach) { - if ($$allattachments{$_}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) { + foreach my $key (sort(keys(%currattach))) { + if ($$allattachments{$key}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) { my $fname = $1.$3.'/'.$4; $$imsfiles{$idx}{$i} .= ''."\n"; $$attachtxt{$i}.= ''.$4.'
'; @@ -1382,11 +1563,11 @@ END sub replicate_attachments { my ($attachrefs,$tempexport) = @_; my $response; - foreach my $id (keys %{$attachrefs}) { + foreach my $id (keys(%{$attachrefs})) { if ($$attachrefs{$id}{'filename'} =~ m-^/uploaded/([^/]+)/([^/]+)(/feedback)?(/?\d*)/([^/]+)$-) { my $path = $tempexport; my $tail = $1.'/'.$2.$4; - my @extras = split/\//,$tail; + my @extras = split(/\//,$tail); my $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5; if (!-e $destination) { my $i= 0; @@ -1418,7 +1599,7 @@ sub replicate_attachments { } sub mail_screen { - my ($r,$feedurl,$options) = @_; + my ($r,$feedurl,$options,$caller_symb,$attachmaxtext) = @_; if (exists($env{'form.origpage'})) { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog','group','ref']); } @@ -1428,10 +1609,9 @@ sub mail_screen { 'myqu' => 'My question/comment/feedback:', 'title' => 'Title', 'reta' => 'Retained attachments', - 'atta' => 'Attachment (128 KB max size)', - ); - my $title=&Apache::lonnet::gettitle($feedurl); - if (!$title) { $title = $feedurl; } + 'atta' => 'Attachment', + ); + my $restitle = &get_resource_title($caller_symb,$feedurl); my $quote=''; my $subject = ''; my $comment = ''; @@ -1497,7 +1677,7 @@ END unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) { if ($contrib{$idx.':history'}) { if ($contrib{$idx.':history'} =~ /:/) { - my @oldversions = split/:/,$contrib{$idx.':history'}; + my @oldversions = split(/:/,$contrib{$idx.':history'}); $numoldver = @oldversions; } else { $numoldver = 1; @@ -1506,7 +1686,7 @@ END if ($env{'form.replydisc'}) { if ($contrib{$idx.':history'}) { if ($contrib{$idx.':history'} =~ /:/) { - my @oldversions = split/:/,$contrib{$idx.':history'}; + my @oldversions = split(/:/,$contrib{$idx.':history'}); $numoldver = @oldversions; } else { $numoldver = 1; @@ -1520,7 +1700,7 @@ END if ($idx > 0) { my %subversions = (); &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver); - $subject = &mt('Re: ')..$subversions{$numoldver}; + $subject = &mt('Re: ').$subversions{$numoldver}; } $subject = &HTML::Entities::encode($subject,'<>&"'); } else { @@ -1619,7 +1799,7 @@ END $r->print(<$title +

$restitle

$prevtag @@ -1650,25 +1830,25 @@ $lt{'title'}: '."\n"); + foreach my $attach (@currnewattach) { + $r->print(''."\n"); } - foreach (@currdelold) { - $r->print(''."\n"); + foreach my $oldatt (@currdelold) { + $r->print(''."\n"); } } if ($env{'form.editdisc'}) { if ($attachmenturls) { &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold); - $attachnum = scalar(keys %currattach); - foreach (keys %currattach) { - $r->print(''."\n"); + $attachnum = scalar(keys(%currattach)); + foreach my $key (keys(%currattach)) { + $r->print(''."\n"); } } } } else { $r->print(< +$lt{'atta'} $attachmaxtext:

END } @@ -1688,6 +1868,7 @@ END if ($env{'form.editdisc'} || $env{'form.replydisc'}) { my $now = time; my $ressymb = $symb; + &Apache::lonenc::check_encrypt(\$ressymb); my $postidx = ''; if ($env{'form.editdisc'}) { $postidx = $idx; @@ -1695,7 +1876,8 @@ END if (@currnewattach > 0) { $attachnum += @currnewattach; } - $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver)); + my $blockblog = &Apache::loncommon::blocking_status('blogs'); + $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver,'',$blockblog)); if ($attachnum > 0) { if (@currnewattach > 0) { $newattachmsg .= '
'.&mt('New attachments').'
'; @@ -1747,7 +1929,7 @@ sub print_display_options { 'unread' => 'New posts only', 'unmark' => 'Posts not marked read', 'ondisp' => 'Once displayed', - 'onmark' => 'Once marked not NEW ', + 'onmark' => 'Once marked not NEW', 'toggon' => 'Shown', 'toggoff' => 'Not shown', 'disa' => 'Posts displayed?', @@ -1905,6 +2087,7 @@ END
END + my $save = &mt('Save Changes'); $r->print(&Apache::loncommon::end_data_table_row()); $r->print(&Apache::loncommon::end_data_table()); $r->print(< - + END if (exists($env{'form.group'})) { $r->print(''); @@ -2004,7 +2187,7 @@ sub print_sortfilter_options { 'spgr' => 'Specific groups', 'psub' => 'Pick specific users (by name)', 'shal' => 'Show a list of current posters', - 'stor' => 'Store changes', + 'stor' => 'Save changes', ); my %sort_types = (); @@ -2200,7 +2383,7 @@ sub print_showposters { $postcounts{$poster} ++; if (defined($namesort{$lastname}{$firstname})) { if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) { - push @{$namesort{$lastname}{$firstname}}, $poster; + push(@{$namesort{$lastname}{$firstname}}, $poster); } } else { @{$namesort{$lastname}{$firstname}} = ("$poster"); @@ -2225,19 +2408,19 @@ $start_page END my $count = 0; - foreach my $last (sort keys %namesort) { - foreach my $first (sort keys %{$namesort{$last}}) { - foreach (sort @{$namesort{$last}{$first}}) { - my ($uname,$udom) = split/:/,$_; + foreach my $last (sort(keys(%namesort))) { + foreach my $first (sort(keys(%{$namesort{$last}}))) { + foreach my $user (sort(@{$namesort{$last}{$first}})) { + my ($uname,$udom) = split(/:/,$user); if (!$uname || !$udom) { next; } else { $count ++; $r->print(&Apache::loncommon::start_data_table_row(). ' - + - '. + '. &Apache::loncommon::end_data_table_row()); } } @@ -2335,7 +2518,7 @@ ENDFAILREDIR } sub redirect_back { - my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group) = @_; + my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group,$toolarge) = @_; my $sorttag = ''; my $roletag = ''; my $statustag = ''; @@ -2374,9 +2557,9 @@ sub redirect_back { if (ref($sectionpick) eq 'ARRAY') { $feedurl .= '§ionpick='; $sectag .= '$status $prevtag @@ -2487,7 +2671,7 @@ sub no_redirect_back { my $end_page = &Apache::loncommon::end_page(); - $feedurl=&Apache::lonenc::check_encrypt($feedurl); + &Apache::lonenc::check_encrypt(\$feedurl); my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); $r->print (<

'; } + my %optionhash=(); + foreach my $type ('question','comment','policy') { + $optionhash{$type}=$env{'course.'.$env{'request.course.id'}.'.'.$type.'.email.text'}; + } if (&feedback_available(1)) { $msgoptions.= '

'; + ($optionhash{'question'}?$optionhash{'question'}:&mt('Question about resource content')).'

'; } if (&feedback_available(0,1)) { $msgoptions.= '

'; } if (&feedback_available(0,0,1)) { $msgoptions.= '

'; } } if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) { - if (&discussion_open(undef,$symb) && + my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('boards'); + if (!$blocked && &discussion_open(undef,$symb) && &Apache::lonnet::allowed('pch', $env{'request.course.id'}. ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) { $discussoptions='

'. ''.&mt('Change Screenname').''; + my $blockblog = &Apache::loncommon::blocking_status('blogs'); + if (!$blockblog) { + $discussoptions.= &add_blog_checkbox(); + } } - $discussoptions.='
'; } if ($msgoptions) { $msgoptions='

'.&mt('Sending Messages').'

'.$msgoptions; } if ($discussoptions) { @@ -2587,7 +2778,7 @@ sub clear_out_html { } sub assemble_email { - my ($feedurl,$message,$prevattempts,$usersaw,$useranswer)=@_; + my ($message,$prevattempts,$usersaw,$useranswer)=@_; my %lt = &Apache::lonlocal::texthash( 'prev' => 'Previous attempts of student (if applicable)', 'orig' => 'Original screen output (if applicable)', @@ -2608,136 +2799,53 @@ ENDCITE return ($email,$citations); } -sub secapply { - my $rec=shift; - my $defaultflag=shift; - $rec=~s/\s+//g; - $rec=~s/\@/\:/g; - my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/); - if ($sections) { - foreach (split(/\;/,$sections)) { - if (($_ eq $env{'request.course.sec'}) || - ($defaultflag && ($_ eq '*'))) { - return $adr; - } - } - } else { - return $rec; - } - return ''; -} - -=pod - -=over 4 - -=item * - -decide_receiver($feedurl,$author,$question,$course,$policy,$defaultflag); - -Arguments - $feedurl - /res/ url of resource (only need if $author is true) - $author,$question,$course,$policy - all true/false parameters - if true will attempt to find the addresses of user that should receive - this type of feedback (author - feedback to author of resource $feedurl, - $question 'Resource Content Questions', $course 'Course Content Question', - $policy 'Course Policy') - (Additionally it also checks $env for whether the corresponding form. - element exists, for ease of use in a html response context) - - $defaultflag - (internal should be left blank) if true gather addresses - that aren't for a section even if I have a section - (used for reccursion internally, first we look for - addresses for our specific section then we recurse - and look for non section addresses) - -Returns - $typestyle - string of html text, describing what addresses were found - %to - a hash, which keys are addresses of users to send messages to - the keys will look like name:domain - -=cut - -sub decide_receiver { - my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_; - my $typestyle=''; - my %to=(); - if ($env{'form.discuss'} eq 'author' ||$author) { - $typestyle.='Submitting as Author Feedback
'; - $feedurl=~/^\/res\/(\w+)\/(\w+)\//; - $to{$2.':'.$1}=1; - } - if ($env{'form.discuss'} eq 'question' ||$question) { - $typestyle.=&mt('Submitting as Question').'
'; - foreach (split(/\,/, - $env{'course.'.$env{'request.course.id'}.'.question.email'}) - ) { - my $rec=&secapply($_,$defaultflag); - if ($rec) { $to{$rec}=1; } - } - } - if ($env{'form.discuss'} eq 'course' ||$course) { - $typestyle.=&mt('Submitting as Comment').'
'; - foreach (split(/\,/, - $env{'course.'.$env{'request.course.id'}.'.comment.email'}) - ) { - my $rec=&secapply($_,$defaultflag); - if ($rec) { $to{$rec}=1; } - } - } - if ($env{'form.discuss'} eq 'policy' ||$policy) { - $typestyle.=&mt('Submitting as Policy Feedback').'
'; - foreach (split(/\,/, - $env{'course.'.$env{'request.course.id'}.'.policy.email'}) - ) { - my $rec=&secapply($_,$defaultflag); - if ($rec) { $to{$rec}=1; } - } - } - if ((scalar(%to) eq '0') && (!$defaultflag)) { - ($typestyle,%to)= - &decide_receiver($feedurl,$author,$question,$course,$policy,1); - } - return ($typestyle,%to); -} sub feedback_available { my ($question,$course,$policy)=@_; - my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy); + my ($typestyle,%to)=&Apache::lonmsg::decide_receiver('',0,$question, + $course,$policy); return scalar(%to); } sub send_msg { - my ($title,$feedurl,$email,$citations,$attachmenturl,%to)=@_; - my $status=''; - my $sendsomething=0; - if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; } - unless ($title=~/\w/) { $title=&mt('Feedback'); } - foreach (keys %to) { - if ($_) { - my $declutter=&Apache::lonnet::declutter($feedurl); - unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_), - $title.' ['.$declutter.']',$email,$citations,$feedurl, - $attachmenturl)=~/ok/) { - $status.='
'.&mt('Error sending message to').' '.$_.'
'; - } else { - $sendsomething++; - } + my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,%to)=@_; + my $status=''; + my $sendsomething=0; + my $restitle = &get_resource_title($symb,$feedurl); + if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; } + unless ($title=~/\w/) { $title=&mt('Feedback'); } + foreach my $key (keys(%to)) { + if ($key) { + my ($user,$domain) = split(/\:/,$key,2); + if (!defined($user)) { + $status.='
'.&mt('Error sending message to [_1], no user specified.',$key); + } elsif (!defined($domain)) { + $status.='
'.&mt('Error sending message to [_1], no domain specified.',$key); + } else { + unless (&Apache::lonmsg::user_normal_msg($user,$domain, + $title.' ['.$restitle.']',$email,$citations,$feedurl, + $attachmenturl,undef,undef,$symb,$restitle)=~/ok/) { + $status.='
'.&mt('Error sending message to').' '.$key.'
'; + } else { + $sendsomething++; + } + } + } } - } + my %record=&Apache::lonnet::restore('_feedback'); - my ($temp)=keys %record; + my ($temp)=keys(%record); unless ($temp=~/^error\:/) { - my %newrecord=(); - $newrecord{'resource'}=$feedurl; - $newrecord{'subnumber'}=$record{'subnumber'}+1; - unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') { - $status.='
'.&mt('Not registered').'
'; - } + my %newrecord=(); + $newrecord{'resource'}=$feedurl; + $newrecord{'subnumber'}=$record{'subnumber'}+1; + unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') { + $status.='
'.&mt('Not registered').'
'; + } } - - return ($status,$sendsomething); + + return ($status,$sendsomething); } sub adddiscuss { @@ -2770,10 +2878,11 @@ sub adddiscuss { $contrib{'anonymous'}='true'; } if (($symb) && ($email)) { + my $now = time; if ($env{'form.editdisc'}) { $contrib{'ip'}=$ENV{'REMOTE_ADDR'}; $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'}; - $contrib{'timestamp'} = time; + $contrib{'timestamp'} = $now; $contrib{'history'} = ''; my $numoldver = 0; my ($oldsymb,$oldidx)=split(/\:\:\:/,$env{'form.editdisc'}); @@ -2788,7 +2897,7 @@ sub adddiscuss { } if (defined($oldcontrib{$oldidx.':history'})) { if ($oldcontrib{$oldidx.':history'} =~ /:/) { - my @oldversions = split/:/,$oldcontrib{$oldidx.':history'}; + my @oldversions = split(/:/,$oldcontrib{$oldidx.':history'}); $numoldver = @oldversions; } else { $numoldver = 1; @@ -2824,14 +2933,14 @@ sub adddiscuss { $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); } - my %storenewentry=($symb => time); + my %storenewentry=($symb => $now); $status.='
'.&mt('Updating discussion time').': '. &Apache::lonnet::put('discussiontimes',\%storenewentry, $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); } my %record=&Apache::lonnet::restore('_discussion'); - my ($temp)=keys %record; + my ($temp)=keys(%record); unless ($temp=~/^error\:/) { my %newrecord=(); $newrecord{'resource'}=$symb; @@ -2845,6 +2954,48 @@ sub adddiscuss { return $status.'
'; } +sub get_discussion_info { + my ($idx,%contrib) = @_; + my $changelast = 0; + my $count = 0; + my $hiddenflag = 0; + my $deletedflag = 0; + my ($hidden,$deleted,%info,$newlastdisc); + my $version = $contrib{'version'}; + if ($version) { + for (my $id=$version; $id>0; $id--) { + my $vkeys=$contrib{$id.':keys'}; + my @keys=split(/:/,$vkeys); + if (grep(/^hidden$/,@keys)) { + if (!$hiddenflag) { + $hidden = $contrib{$id.':hidden'}; + $hiddenflag = 1; + } + } elsif (grep(/^deleted$/,@keys)) { + if (!$deletedflag) { + $deleted = $contrib{$id.':deleted'}; + $deletedflag = 1; + } + } else { + if (($hidden !~/\.$id\./) && ($deleted !~/\.$id\./)) { + $count++; + $info{$count}{'id'} = $id; + $info{$count}{'timestamp'}=$contrib{$id.':timestamp'}; + } + } + } + if ($info{'1'}{'id'} == $idx) { + $changelast = 1; + if ($count > 1) { + $newlastdisc = $info{'2'}{'timestamp'}; + } else { + $newlastdisc = 0; + } + } + } + return ($changelast,$newlastdisc); +} + # ----------------------------------------------------------- Preview function sub show_preview { @@ -2909,7 +3060,8 @@ ENDPREVIEW } sub modify_attachments { - my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_; + my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls, + $attachmaxtext,$toolarge)=@_; my %lt = &Apache::lonlocal::texthash( 'subj' => 'Subject', @@ -2917,7 +3069,7 @@ sub modify_attachments { 'chth' => 'Check the checkboxes for any you wish to remove.', 'thef' => 'The following attachments have been uploaded for inclusion with this posting.', 'adda' => 'Add a new attachment to this post.', - 'stch' => 'Store Changes', + 'stch' => 'Save Changes', ); my $js = < @@ -2951,15 +3103,17 @@ END $r->print(< -
NEW
'.&mt('NEW').'$lt{$disctogg}
'.$count.' '.$last.', '.$first.' ('.$uname.':'.$udom.')'.$postcounts{$_}.''.$postcounts{$user}.'
+
+
- + + + + +
+ Subject: $subject

END if ($idx) { if ($attachmenturls) { - my @currold = keys %currattach; + my @currold = keys(%currattach); if (@currold > 0) { $r->print($lt{'thfo'}.'
'.$lt{'chth'}.'
'."\n"); foreach my $id (@currold) { @@ -2973,16 +3127,22 @@ END } if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) { $r->print($lt{'thef'}.'
'.$lt{'chth'}.'
'."\n"); - foreach (@{$currnewattach}) { - $_ =~ m#/([^/]+)$#; - $r->print('
'."\n"); + foreach my $attach (@{$currnewattach}) { + $attach =~ m#/([^/]+)$#; + $r->print('
'."\n"); } $r->print("
"); } $r->print(< +
+ $lt{'adda'}
$attachmaxtext
@@ -3020,14 +3180,14 @@ sub process_attachments { my @currnew = (); foreach my $newone (@{$currnewattach}) { my $delflag = 0; - foreach (@currdelnew) { - if ($newone eq $_) { + foreach my $item (@currdelnew) { + if ($newone eq $item) { $delflag = 1; last; } } unless ($delflag) { - push @currnew, $newone; + push(@currnew, $newone); } } @{$currnewattach} = @currnew; @@ -3036,7 +3196,8 @@ sub process_attachments { } sub generate_attachments_button { - my ($idx,$attachnum,$ressymb,$now,$currnewattach,$deloldattach,$numoldver,$mode) = @_; + my ($idx,$attachnum,$ressymb,$now,$currnewattach,$deloldattach, + $numoldver,$mode,$blockblog) = @_; my $origpage = $ENV{'REQUEST_URI'}; my $att=$attachnum.' '.&mt("attachments"); my %lt = &Apache::lonlocal::texthash( @@ -3048,6 +3209,9 @@ sub generate_attachments_button { $lt{'clic'}:  ENDATTACH if (defined($deloldattach)) { if (@{$deloldattach} > 0) { - foreach (@{$deloldattach}) { - $response .= ''."\n"; + foreach my $delatt (@{$deloldattach}) { + $response .= ''."\n"; } } } if (defined($currnewattach)) { if (@{$currnewattach} > 0) { - foreach (@{$currnewattach}) { - $response .= ''."\n"; + foreach my $attach (@{$currnewattach}) { + $response .= ''."\n"; } } } @@ -3084,7 +3248,7 @@ sub extract_attachments { my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_; %{$attachments}=(); &get_post_attachments($attachments,$attachmenturls); - foreach my $id (sort keys %{$attachments}) { + foreach my $id (sort(keys(%{$attachments}))) { if (exists($$attachments{$id}{$numoldver})) { if (defined($currdelold)) { if (@{$currdelold} > 0) { @@ -3099,7 +3263,7 @@ sub extract_attachments { } } } - my @attached = (sort { $a <=> $b } keys %{$currattach}); + my @attached = (sort { $a <=> $b } keys(%{$currattach})); if (@attached == 1) { my $id = $attached[0]; my $attachurl; @@ -3115,8 +3279,8 @@ sub extract_attachments { $attachurl); } elsif (@attached > 1) { $$message.='

    '; - foreach (@attached) { - my $id = $_; + foreach my $attach (@attached) { + my $id = $attach; my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'}); my ($fname) =($attachurl=~m|/([^/]+)$|); @@ -3143,7 +3307,7 @@ sub construct_attachmenturl { $oldattachmenturl = $contrib{$idx.':attachmenturl'}; if ($contrib{$idx.':history'}) { if ($contrib{$idx.':history'} =~ /:/) { - my @oldversions = split/:/,$contrib{$idx.':history'}; + my @oldversions = split(/:/,$contrib{$idx.':history'}); $currver = 1 + scalar(@oldversions); } else { $currver = 2; @@ -3156,13 +3320,13 @@ sub construct_attachmenturl { my %attachments = (); my $prevver = $currver-1; &get_post_attachments(\%attachments,$oldattachmenturl); - my $numattach = scalar(keys %attachments); + my $numattach = scalar(keys(%attachments)); $startnum += $numattach; - foreach my $num (sort {$a <=> $b} keys %attachments) { + foreach my $num (sort {$a <=> $b} keys(%attachments)) { $newattachmenturl .= ''.$attachments{$num}{'filename'}.''; - foreach $_ (sort {$a <=> $b} keys %{$attachments{$num}}) { - unless ($_ eq 'filename') { - $newattachmenturl .= ''.$attachments{$num}{$_}.''; + foreach my $item (sort {$a <=> $b} keys(%{$attachments{$num}})) { + unless ($item eq 'filename') { + $newattachmenturl .= ''.$attachments{$num}{$item}.''; } } if (grep/^$num$/,@{$keepold}) { @@ -3187,6 +3351,26 @@ sub construct_attachmenturl { return $newattachmenturl; } +sub add_blog_checkbox { + my ($checkstatus); + if ($env{'form.blog'}) { + $checkstatus = 'checked="checked"'; + } + my $output = ' +
    +
    '."\n"; + return $output; +} + sub has_discussion { my $resourcesref = shift; my $navmap = Apache::lonnavmaps::navmap->new(); @@ -3194,7 +3378,7 @@ sub has_discussion { foreach my $resource (@allres) { if ($resource->hasDiscussion()) { my $ressymb = $resource->wrap_symb(); - push @{$resourcesref}, $ressymb; + push(@{$resourcesref}, $ressymb); } } return; @@ -3241,6 +3425,10 @@ sub handler { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']); my $group = $env{'form.group'}; + my %attachmax = ( + text => '(128 KB max size)', + num => 131072, + ); if ($env{'form.editdisc'}) { if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) { my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0]; @@ -3256,7 +3444,7 @@ sub handler { my $readkey = $symb.'_read'; my $chgcount = 0; my %readinghash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$readkey],$env{'user.domain'},$env{'user.name'}); - foreach my $key (keys %env) { + foreach my $key (keys(%env)) { if ($key =~ m/^form\.postunread_(\d+)/) { if ($readinghash{$readkey} =~ /\.$1\./) { $readinghash{$readkey} =~ s/\.$1\.//; @@ -3355,7 +3543,7 @@ sub handler { my @resources = (); if (defined($env{'form.navmaps'})) { if ($env{'form.navmaps'} =~ /:/) { - @resources = split/:/,$env{'form.navmaps'}; + @resources = split(/:/,$env{'form.navmaps'}); } else { @resources = ("$env{'form.navmaps'}"); } @@ -3370,8 +3558,8 @@ sub handler { 'robb' => 'resources/bulletin boards.', 'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.' ); - foreach (@resources) { - my $ressymb=$_; + foreach my $res (@resources) { + my $ressymb=$res; &Apache::lonenc::check_decrypt(\$ressymb); my $lastkey = $ressymb.'_lastread'; $discinfo{$lastkey} = $env{'form.navtime'}; @@ -3489,7 +3677,16 @@ ENDREDIR if ( ($env{'form.hide'}) && (!$seeid) ) { $newhash{'studenthidden'} = $currentstudenthidden; } - + if ($env{'form.hide'}) { + my $changelast = 0; + my $newlast; + ($changelast,$newlast) = &get_discussion_info($idx,%contrib); + if ($changelast) { + &Apache::lonnet::put('discussiontimes',{$symb => $newlast}, + $env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}); + } + } &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'}, $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); @@ -3502,7 +3699,7 @@ ENDREDIR my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'}); if ($env{'form.cmd'} eq 'threadedon') { &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'}); - &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on'); + &Apache::lonnet::appenv({'environment.threadeddiscussion' => 'on'}); } else { &Apache::lonnet::del('environment',['threadeddiscussion']); &Apache::lonnet::delenv('environment\.threadeddiscussion'); @@ -3518,6 +3715,11 @@ ENDREDIR my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'}, $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); + my ($changelast,$newlast) = &get_discussion_info($idx,%contrib); + if ($changelast) { + &Apache::lonnet::put('discussiontimes',{$symb => $newlast}, + $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); + } my %newhash=('deleted' => $contrib{'deleted'}.".$idx."); &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'}, $env{'course.'.$env{'request.course.id'}.'.domain'}, @@ -3535,13 +3737,15 @@ ENDREDIR &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','discuss','blog']); - my (@currnewattach,@currdelold,@keepold); + my (@currnewattach,@currdelold,@keepold,$toolarge); &process_attachments(\@currnewattach,\@currdelold,\@keepold); if (exists($env{'form.addnewattach.filename'})) { - unless (length($env{'form.addnewattach'})>131072) { + if (length($env{'form.addnewattach'})<=$attachmax{'num'}) { my $subdir = 'feedback/'.$env{'form.timestamp'}; my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir); - push @currnewattach, $newattachment; + push(@currnewattach, $newattachment); + } else { + $toolarge = '

    '.&mt('Attachment not included - exceeded permitted length').'

    '; } } my $attachmenturls; @@ -3554,7 +3758,7 @@ ENDREDIR $attachmenturls = $contrib{$idx.':attachmenturl'}; } &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx, - $attachmenturls); + $attachmenturls,$attachmax{'text'},$toolarge); return OK; } elsif ($env{'form.export'}) { &Apache::loncommon::content_type($r,'text/html'); @@ -3585,12 +3789,8 @@ ENDREDIR my $symb; if ($env{'form.replydisc'}) { $symb=(split(/\:\:\:/,$env{'form.replydisc'}))[0]; - my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); - $feedurl=&Apache::lonnet::clutter($url); } elsif ($env{'form.editdisc'}) { $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0]; - my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); - $feedurl=&Apache::lonnet::clutter($url); } elsif ($env{'form.origpage'}) { $symb=""; } else { @@ -3598,18 +3798,18 @@ ENDREDIR } unless ($symb) { $symb=$env{'form.symb'}; - if ($symb) { - my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); - $feedurl=&Apache::lonnet::clutter($url); - } } - &Apache::lonenc::check_decrypt(\$symb); + if (defined($symb)) { + ($symb,$feedurl)=&get_feedurl_and_clean_symb($symb); + } else { + # backward compatibility (bulletin boards used to be 'wrapped') + &Apache::lonenc::check_decrypt(\$feedurl); + &dewrapper(\$feedurl); + } my $goahead=1; if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form|task)$/) { unless ($symb) { $goahead=0; } } - # backward compatibility (bulletin boards used to be 'wrapped') - &dewrapper(\$feedurl); if (!$goahead) { # Ambiguous Problem Resource $r->internal_redirect('/adm/ambiguous'); @@ -3628,16 +3828,26 @@ ENDREDIR &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; # Unable to give feedback + &Apache::lonenc::check_encrypt(\$feedurl); &no_redirect_back($r,$feedurl); return OK; } # --------------------------------------------------- Print login screen header unless ($env{'form.sendit'}) { + &Apache::lonenc::check_encrypt(\$feedurl); &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; + if (($env{'form.replydisc'}) || ($env{'form.editdisc'})) { + my ($blocked,$blocktext) = + &Apache::loncommon::blocking_status('boards'); + if ($blocked) { + $r->print(&blocked_reply_or_edit($blocktext)); + return OK; + } + } my $options=&screen_header($feedurl,$symb); if ($options) { - &mail_screen($r,$feedurl,$options); + &mail_screen($r,$feedurl,$options,$symb,$attachmax{'text'}); } else { &fail_redirect($r,$feedurl); } @@ -3650,16 +3860,20 @@ ENDREDIR $env{'request.course.id'}); # Get output from resource + &Apache::lonenc::check_encrypt(\$feedurl); my $usersaw=&resource_output($feedurl); # Get resource answer (need to allow student to view grades for this to work) - &Apache::lonnet::appenv(('allowed.vgr'=>'F')); - my $useranswer=&Apache::loncommon::get_student_answers( - $symb,$env{'user.name'},$env{'user.domain'}, - $env{'request.course.id'}); + &Apache::lonnet::appenv({'allowed.vgr'=>'F'}); + my $usersymb = &Apache::lonenc::check_encrypt($symb); + my $useranswer= + &Apache::loncommon::get_student_answers( + $usersymb,$env{'user.name'},$env{'user.domain'}, + $env{'request.course.id'}); &Apache::lonnet::delenv('allowed.vgr'); # Get attachments, if any, and not too large my $attachmenturl=''; + my $toolarge=''; if (($env{'form.origpage'}) || ($env{'form.editdisc'}) || ($env{'form.replydisc'})) { my ($symb,$idx); @@ -3678,25 +3892,29 @@ ENDREDIR $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|; $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx); } elsif ($env{'form.attachment.filename'}) { - unless (length($env{'form.attachment'})>131072) { - $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback'); - } + if (length($env{'form.attachment'})<=$attachmax{'num'}) { + my $now = time; + my $subdir = 'feedback/'.$now; + $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,$subdir); + } else { + $toolarge = '

    '.&mt('Attachment not included - exceeded permitted length').'

    '; + } } # Filter HTML out of message (could be nasty) my $message=&clear_out_html($env{'form.comment'}); # Assemble email - my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts, + my ($email,$citations)=&assemble_email($message,$prevattempts, $usersaw,$useranswer); # Who gets this? - my ($typestyle,%to) = &decide_receiver($feedurl); + my ($typestyle,%to) = &Apache::lonmsg::decide_receiver($feedurl); # Actually send mail my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'}, undef,1), $feedurl,$email,$citations, - $attachmenturl,%to); + $attachmenturl,$usersymb,%to); # Discussion? Store that. my $numpost=0; @@ -3723,9 +3941,18 @@ ENDREDIR } # Receipt screen and redirect back to where came from - &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group); + &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group,$toolarge); } return OK; +} + +sub blocked_reply_or_edit { + my ($blocktext) = @_; + return + &Apache::loncommon::start_page('Resource Feedback and Discussion'). + $blocktext.'

    '. + &mt('Back to previous page'). + &Apache::loncommon::end_page(); } sub wrap_symb { @@ -3830,5 +4057,32 @@ sub group_args { return $extra_args; } +sub get_resource_title { + my ($symb,$feedurl) = @_; + my ($restitle,$plainurl); + if (defined($symb)) { + my $plain_symb = &Apache::lonenc::check_decrypt($symb); + $restitle = &Apache::lonnet::gettitle($plain_symb); + } + if (defined($feedurl)) { + $plainurl = &Apache::lonenc::check_decrypt($feedurl); + } + if (!defined($restitle)) { + if (defined($feedurl)) { + $restitle = &Apache::lonnet::gettitle($plainurl); + } + } + if ($plainurl ne $feedurl) { + my ($plain_filename) = ($plainurl =~ m-/([^/]+)$-); + if ($plain_filename eq $restitle) { + $restitle = &mt('Untitled resource'); + } + } + if ($restitle eq '') { + $restitle = &mt('Untitled resource'); + } + return $restitle; +} + 1; __END__