--- loncom/interface/lonfeedback.pm 2004/08/31 18:28:18 1.120 +++ loncom/interface/lonfeedback.pm 2005/02/17 08:29:42 1.153 @@ -1,7 +1,7 @@ # The LearningOnline Network # Feedback # -# $Id: lonfeedback.pm,v 1.120 2004/08/31 18:28:18 albertel Exp $ +# $Id: lonfeedback.pm,v 1.153 2005/02/17 08:29:42 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,18 +36,20 @@ use Apache::loncommon(); use Apache::lontexconvert(); use Apache::lonlocal; # must not have () use Apache::lonhtmlcommon(); +use Apache::lonnavmaps; +use Apache::lonenc(); use HTML::LCParser(); use Apache::lonspeller(); use Cwd; sub discussion_open { - my ($status)=@_; + my ($status,$symb)=@_; if (defined($status) && !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER' || $status eq 'OPEN')) { return 0; } - my $close=&Apache::lonnet::EXT('resource.0.discussend'); + my $close=&Apache::lonnet::EXT('resource.0.discussend',$symb); if (defined($close) && $close ne '' && $close < time) { return 0; } @@ -59,20 +61,25 @@ sub discussion_visible { if (not &discussion_open($status)) { my $hidden=&Apache::lonnet::EXT('resource.0.discusshide'); if (lc($hidden) eq 'yes' or $hidden eq '' or !defined($hidden)) { - return 0; + if (!$ENV{'request.role.adv'}) { return 0; } } } return 1; } sub list_discussion { - my ($mode,$status,$symb)=@_; + my ($mode,$status,$ressymb,$imsextras)=@_; my $outputtarget=$ENV{'form.grade_target'}; if (defined($ENV{'form.export'})) { if($ENV{'form.export'}) { $outputtarget = 'export'; } - } + } + if (defined($imsextras)) { + if ($$imsextras{'caller'} eq 'imsexport') { + $outputtarget = 'export'; + } + } if (not &discussion_visible($status)) { return ''; } my @bgcols = ("#cccccc","#eeeeee"); my $discussiononly=0; @@ -82,22 +89,18 @@ sub list_discussion { my $cid=$ENV{'request.course.id'}; if ($ENV{'request.course.sec'}) { $crs.='_'.$ENV{'request.course.sec'}; - } - $crs=~s/\_/\//g; - unless ($symb) { - $symb=&Apache::lonnet::symbread(); } - unless ($symb) { return ''; } + $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)$/)); + my %usernamesort = (); my %namesort =(); my %subjectsort = (); -# backward compatibility (bulletin boards used to be 'wrapped') - my $ressymb=$symb; - if ($mode eq 'board') { - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - } # Get discussion display settings for this discussion my $lastkey = $ressymb.'_lastread'; @@ -108,7 +111,7 @@ sub list_discussion { my $userpickkey = $ressymb.'_userpick'; my $toggkey = $ressymb.'_readtoggle'; my $readkey = $ressymb.'_read'; - + $ressymb=$encsymb; my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$ENV{'user.domain'},$ENV{'user.name'}); my %discinfo = (); my $showonlyunread = 0; @@ -123,9 +126,19 @@ sub list_discussion { # 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','totposters']); my $sortposts = $ENV{'form.sortposts'}; - my $rolefilter = $ENV{'form.rolefilter'}; my $statusfilter = $ENV{'form.statusfilter'}; - my $sectionpick = $ENV{'form.sectionpick'}; + my @sectionpick = (); + if ($ENV{'form.sectionpick'} =~ /,/) { + @sectionpick = split/,/,$ENV{'form.sectionpick'}; + } else { + $sectionpick[0] = $ENV{'form.sectionpick'}; + } + my @rolefilter = (); + if ($ENV{'form.rolefilter'} =~ /,/) { + @rolefilter = split/,/,$ENV{'form.rolefilter'}; + } else { + $rolefilter[0] = $ENV{'form.rolefilter'}; + } my $totposters = $ENV{'form.totposters'}; $previous = $ENV{'form.previous'}; if ($previous > 0) { @@ -139,17 +152,22 @@ sub list_discussion { # Get information about students and non-students in course for filtering display of posts my %roleshash = (); my %roleinfo = (); - if ($rolefilter) { + if ($ENV{'form.rolefilter'}) { %roleshash = &Apache::lonnet::dump('nohist_userroles',$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'}); foreach (keys %roleshash) { my ($role,$uname,$udom,$sec) = split/:/,$_; + if ($role =~ /^cr/) { + $role = 'cr'; + } my ($end,$start) = split/:/,$roleshash{$_}; my $now = time; my $status = 'Active'; if (($now < $start) || ($end > 0 && $now > $end)) { $status = 'Expired'; } - push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status; + if ($uname && $udom) { + push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status; + } } my ($classlist) = &Apache::loncoursedata::get_classlist( $ENV{'request.course.id'}, @@ -165,40 +183,43 @@ sub list_discussion { } # Get discussion display default settings for user - my %userenv = &Apache::lonnet::get('environment',['discdisplay','discmarkread'],$ENV{'user.domain'},$ENV{'user.name'}); - my $discdisplay=$userenv{'discdisplay'}; - if ($discdisplay eq 'unread') { + if ($ENV{'environment.discdisplay'} eq 'unread') { $showonlyunread = 1; } - my $discmarkread=$userenv{'discmarkread'}; - if ($discmarkread eq 'ondisp') { + if ($ENV{'environment.discmarkread'} eq 'ondisp') { $markondisp = 1; } # Override user's default if user specified display setting for this discussion if (defined($dischash{$ondispkey})) { - $markondisp = $dischash{$ondispkey}; + unless ($dischash{$ondispkey} eq '') { + $markondisp = $dischash{$ondispkey}; + } } if ($markondisp) { $discinfo{$lastkey} = time; } if (defined($dischash{$showkey})) { - $showonlyunread = $dischash{$showkey}; + unless ($dischash{$showkey} eq '') { + $showonlyunread = $dischash{$showkey}; + } } if (defined($dischash{$markkey})) { - $showunmark = $dischash{$markkey}; + unless ($dischash{$markkey} eq '') { + $showunmark = $dischash{$markkey}; + } } if (defined($dischash{$visitkey})) { - $visit = $dischash{$visitkey}; + unless ($dischash{$visitkey} eq '') { + $visit = $dischash{$visitkey}; + } } $visit ++; my $seeid=&Apache::lonnet::allowed('rin',$crs); - my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs) - && ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/)); my @discussionitems=(); my %shown = (); my @posteridentity=(); @@ -224,7 +245,7 @@ sub list_discussion { $discinfo{$visitkey} = $visit; &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget); + &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,$statusfilter,$toggkey,$outputtarget); my $discussion=''; my $manifestfile; @@ -309,22 +330,32 @@ sub list_discussion { } elsif ($outputtarget eq 'export') { # Create temporary directory if this is an export my $now = time; - $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports'; - if (!-e $tempexport) { - mkdir($tempexport,0700); - } - $tempexport .= '/'.$now; - if (!-e $tempexport) { - mkdir($tempexport,0700); + if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) { + $tempexport = $$imsextras{'tempexport'}; + if (!-e $tempexport) { + mkdir($tempexport,0700); + } + $tempexport .= '/'.$$imsextras{'count'}; + if (!-e $tempexport) { + mkdir($tempexport,0700); + } + } else { + $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports'; + if (!-e $tempexport) { + mkdir($tempexport,0700); + } + $tempexport .= '/'.$now; + if (!-e $tempexport) { + mkdir($tempexport,0700); + } + $tempexport .= '/'.$ENV{'user.domain'}.'_'.$ENV{'user.name'}; } - $tempexport .= '/'.$ENV{'user.domain'}.'_'.$ENV{'user.name'}; if (!-e $tempexport) { mkdir($tempexport,0700); } # open manifest file my $manifest = '/imsmanifest.xml'; my $manifestfilename = $tempexport.$manifest; - print STDERR "manifestfilename is $manifestfilename\n"; if ($manifestfile = Apache::File->new('>'.$manifestfilename)) { $manifestok=1; print $manifestfile qq| @@ -355,22 +386,22 @@ imscp_v1p1.xsd http://www.imsglobal.org/ } |; - $discussion.='
'; + $discussion.='
'; $discussion .=' END + if ($sortposts) { + my %sort_types = (); + my %role_types = (); + my %status_types = (); + &sort_filter_names(\%sort_types,\%role_types,\%status_types); + + $discussion .= ''; + } + } if ($dischash{$toggkey}) { my $storebutton = &mt('Store read/unread changes'); $discussion.=' - - + - +
'. ''; if ($visible>2) { $discussion.=''; if ($newpostsflag) { if (!$markondisp) { - $discussion .=''; } @@ -398,7 +429,7 @@ imscp_v1p1.xsd http://www.imsglobal.org/ if ($numhidden > 0) { my $colspan = $maxdepth+1; $discussion.="\n".' -
'. - '  '. - '   -   '.&mt('Mark NEW posts no longer new').'  '; + $discussion .=''.&mt('Mark NEW posts no longer new').'  '; } else { $discussion .= ' 
'. - ' $b } keys %alldiscussion); } my $currdepth = 0; my $firstidx = $alldiscussion{$showposts[0]}; foreach (@showposts) { - unless (($sortposts eq 'thread') || ($sortposts eq 'ascdate' && $ENV{'environment.threadeddiscussion'}) || ($outputtarget eq 'export')) { + unless (($sortposts eq 'thread') || (($sortposts eq '') && ($ENV{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) { $alldiscussion{$_} = $_; } unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) { @@ -474,7 +504,6 @@ imscp_v1p1.xsd http://www.imsglobal.org/ my $postfilename = $alldiscussion{$_}.'-'.$imsitems{$alldiscussion{$_}}{'timestamp'}.'.html'; if ($manifestok) { if (($depth[$alldiscussion{$_}] <= $currdepth) && ($alldiscussion{$_} != $firstidx)) { - print STDERR "depth is $depth[$alldiscussion{$_}], currdepth is $currdepth, idx is $alldiscussion{$_}, firstidx is $firstidx\n"; print $manifestfile ' '."\n"; } $currdepth = $depth[$alldiscussion{$_}]; @@ -483,8 +512,8 @@ imscp_v1p1.xsd http://www.imsglobal.org/ $imsitems{$alldiscussion{$_}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$_}.'">'. ''.$imsitems{$alldiscussion{$_}}{'title'}.''; $imsresources .= "\n". - ''. - ''."\n". + ''."\n". + ''."\n". $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'currversion'}}."\n". ''; } @@ -541,13 +570,54 @@ END $discussion .= <   + $lt{'chgt'}?
'.&mt('Sorted by').': '.$sort_types{$sortposts}.'
'; + if (defined($ENV{'form.totposters'})) { + $discussion .= &mt('Posts by').':'; + if ($totposters > 0) { + foreach my $poster (@posters) { + $poster =~ s/:/\@/; + $discussion .= ' '.$poster.','; + } + $discussion =~ s/,$//; + } else { + $discussion .= &mt('None selected'); + } + } else { + my $filterchoice =''; + if (@sectionpick > 0) { + $filterchoice = ''.&mt('sections').'- '.$ENV{'form.sectionpick'}; + $filterchoice .= '    '; + } + if (@rolefilter > 0) { + $filterchoice .= ''.&mt('roles').'-'; + foreach (@rolefilter) { + $filterchoice .= ' '.$role_types{$_}.','; + } + $filterchoice =~ s/,$//; + $filterchoice .= '
        '; + } + if ($statusfilter) { + $filterchoice .= ''.&mt('status').'- '.$status_types{$statusfilter}; + } + if ($filterchoice) { + $discussion .= ''.&mt('Filters').': '.$filterchoice; + } + $discussion .= '
'. @@ -580,27 +650,31 @@ END |; close($manifestfile); + if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) { + $discussion = $copyresult; + } else { #Create zip file in prtspool - my $imszipfile = '/prtspool/'. - $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. - time.'_'.rand(1000000000).'.zip'; + my $imszipfile = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.zip'; # zip can cause an sh launch which can pass along all of %ENV # which can be too large for /bin/sh to handle - my %oldENV=%ENV; - undef(%ENV); - my $cwd = &getcwd(); - my $imszip = '/home/httpd/'.$imszipfile; - chdir $tempexport; - open(OUTPUT, "zip -r $imszip * 2> /dev/null |"); - close(OUTPUT); - chdir $cwd; - %ENV=%oldENV; - undef(%oldENV); - $discussion .= 'Download the zip file from Discussion Posting Archive
'; - if ($copyresult) { - $discussion .= 'The following errors occurred during export - '.$copyresult; + my %oldENV=%ENV; + undef(%ENV); + my $cwd = &getcwd(); + my $imszip = '/home/httpd/'.$imszipfile; + chdir $tempexport; + open(OUTPUT, "zip -r $imszip * 2> /dev/null |"); + close(OUTPUT); + chdir $cwd; + %ENV=%oldENV; + undef(%oldENV); + $discussion .= 'Download the zip file from Discussion Posting Archive
'; + if ($copyresult) { + $discussion .= 'The following errors occurred during export -
'.$copyresult; + } } } else { $discussion .= '
Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.
'; @@ -618,15 +692,16 @@ END my $subject = ''; if ($ENV{'form.origpage'}) { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['addnewattach','deloldattach','delnewattach','timestamp','idx','subject','comment']); - $subject = &HTML::Entities::encode($ENV{'form.subject'},'<>&"'); - $comment = &HTML::Entities::encode($ENV{'form.comment'},'<>&"'); + $subject = &Apache::lonnet::unescape($ENV{'form.subject'}); + $comment = &Apache::lonnet::unescape($ENV{'form.comment'}); my @keepold = (); &process_attachments(\@currnewattach,\@currdelold,\@keepold); if (@currnewattach > 0) { $attachnum += @currnewattach; } } - $discussion.=(< @@ -639,41 +714,42 @@ to course faculty
Title: 

ENDDISCUSS - if ($ENV{'form.origpage'}) { - $discussion.=''."\n"; - foreach (@currnewattach) { - $discussion.=''."\n"; - } - } - $discussion.="\n"; - if ($outputtarget ne 'tex') { - $discussion.=&generate_attachments_button('',$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,'',$mode); - if (@currnewattach > 0) { - $newattachmsg .= 'New attachments
'; - if (@currnewattach > 1) { - $newattachmsg .= '
    '; - foreach my $item (@currnewattach) { - $item =~ m#.*/([^/]+)$#; - $newattachmsg .= '
  1. '.$1.'
  2. '."\n"; + if ($ENV{'form.origpage'}) { + $discussion.=''."\n"; + foreach (@currnewattach) { + $discussion.=''."\n"; + } + } + $discussion.="\n"; + if ($outputtarget ne 'tex') { + $discussion.=&generate_attachments_button('',$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,'',$mode); + if (@currnewattach > 0) { + $newattachmsg .= 'New attachments
    '; + if (@currnewattach > 1) { + $newattachmsg .= '
      '; + foreach my $item (@currnewattach) { + $item =~ m#.*/([^/]+)$#; + $newattachmsg .= '
    1. '.$1.'
    2. '."\n"; + } + $newattachmsg .= '
    '."\n"; + } else { + $currnewattach[0] =~ m#.*/([^/]+)$#; + $newattachmsg .= ''.$1.'
    '."\n"; } - $newattachmsg .= '
'."\n"; - } else { - $currnewattach[0] =~ m#.*/([^/]+)$#; - $newattachmsg .= ''.$1.'
'."\n"; } - } - $discussion.=$newattachmsg; - $discussion.=&generate_preview_button(); + $discussion.=$newattachmsg; + $discussion.=&generate_preview_button(); + } } - } else { - if (&discussion_open($status) && - &Apache::lonnet::allowed('pch', - $ENV{'request.course.id'}. - ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { + } else { + if (&discussion_open($status) && + &Apache::lonnet::allowed('pch', + $ENV{'request.course.id'}. + ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { if ($outputtarget ne 'tex') { $discussion.='
'. - ''. + $ressymb.':::" '.$target.'>'. + ''. &mt('Post Discussion').'
'; } } @@ -683,11 +759,10 @@ ENDDISCUSS sub build_posting_display { my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget) = @_; - my @original=(); my @index=(); - - my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'}, + my $symb=&Apache::lonenc::check_decrypt($ressymb); + my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); @@ -696,6 +771,11 @@ sub build_posting_display { if ($prevread eq '0') { $prevread = $oldest-1; } + my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp); + if ($sortposts) { + ($skiptest,$roleregexp,$secregexp,$statusregexp) = &filter_regexp($rolefilter,$sectionpick,$statusfilter); + $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp; + } for (my $id=1;$id<=$contrib{'version'};$id++) { my $idx=$id; my $posttime = $contrib{$idx.':timestamp'}; @@ -708,7 +788,7 @@ sub build_posting_display { my $origindex='0.'; my $numoldver=0; if ($contrib{$idx.':replyto'}) { - if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) { + if ( (($ENV{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) { # this is a follow-up message $original[$idx]=$original[$contrib{$idx.':replyto'}]; $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1; @@ -894,16 +974,16 @@ sub build_posting_display { $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb); } if ($$dischash{$readkey}=~/\.$idx\./) { - $ctlink = ''.&mt('Mark unread').'? '; + $ctlink = ''; } else { - $ctlink = ''.&mt('Mark read').'? '; + $ctlink = ''; } } #figure out at what position this needs to print } if ($outputtarget eq 'export' || $message) { my $thisindex=$idx; - if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) { + if ( (($ENV{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) { $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2); } $$alldiscussion{$thisindex}=$idx; @@ -944,47 +1024,33 @@ sub build_posting_display { my $uname = $contrib{$idx.':sendername'}; my $udom = $contrib{$idx.':senderdomain'}; my $poster = $uname.':'.$udom; - my $rolematch = ''; - my $skiptest = 1; - if ($totposters > 0) { - if (grep/^$poster$/,@{$posters}) { - $$shown{$idx} = 1; - } - } else { - if ($rolefilter) { - if ($rolefilter eq 'all') { - $rolematch = '([^:]+)'; - } else { - $rolematch = $rolefilter; - $skiptest = 0; - } - } - if ($sectionpick) { - if ($sectionpick eq 'all') { - $rolematch .= ':([^:]*)'; - } else { - $rolematch .= ':'.$sectionpick; - $skiptest = 0; - } - } - if ($statusfilter) { - if ($statusfilter eq 'all') { - $rolematch .= ':([^:]+)'; - } else { - $rolematch .= ':'.$statusfilter; - $skiptest = 0; + if (defined($ENV{'form.totposters'})) { + if ($totposters == 0) { + $$shown{$idx} = 0; + } elsif ($totposters > 0) { + if (grep/^$poster$/,@{$posters}) { + $$shown{$idx} = 1; } } + } elsif ($sortposts) { if ($skiptest) { $$shown{$idx} = 1; } else { foreach my $role (@{$$roleinfo{$poster}}) { - if ($role =~ m/^$rolematch$/) { + if ($role =~ /^cc:/) { + my $cc_regexp = $roleregexp.':[^:]*:'.$statusregexp; + if ($role =~ /$cc_regexp/) { + $$shown{$idx} = 1; + last; + } + } elsif ($role =~ /^$rolematch$/) { $$shown{$idx} = 1; last; } } } + } else { + $$shown{$idx} = 1; } } unless ($$notshown{$idx} == 1) { @@ -1034,6 +1100,60 @@ sub build_posting_display { } } +sub filter_regexp { + my ($rolefilter,$sectionpick,$statusfilter) = @_; + my ($roleregexp,$secregexp,$statusregexp); + my $skiptest = 1; + if (@{$rolefilter} > 0) { + my @okrolefilter = (); + foreach (@{$rolefilter}) { + unless ($_ eq '') { + push @okrolefilter, $_; + } + } + if (@okrolefilter > 0) { + if (grep/^all$/,@okrolefilter) { + $roleregexp='[^:]+'; + } else { + if (@okrolefilter == 1) { + $roleregexp=$okrolefilter[0]; + } else { + $roleregexp='('.join('|',@okrolefilter).')'; + } + $skiptest = 0; + } + } + } + if (@{$sectionpick} > 0) { + my @oksectionpick = (); + foreach (@{$sectionpick}) { + unless ($_ eq '') { + push @oksectionpick, $_; + } + } + if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) { + if (@oksectionpick == 1) { + $secregexp = $oksectionpick[0]; + } else { + $secregexp .= '('.join('|',@oksectionpick).')'; + } + $skiptest = 0; + } else { + $secregexp .= '[^:]*'; + } + } + if (defined($statusfilter) && $statusfilter ne '') { + if ($statusfilter eq 'all') { + $statusregexp = '[^:]+'; + } else { + $statusregexp = $statusfilter; + $skiptest = 0; + } + } + return ($skiptest,$roleregexp,$secregexp,$statusregexp); +} + + sub get_post_contents { my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$numver) = @_; my $discussion = ''; @@ -1046,12 +1166,14 @@ sub get_post_contents { return $discussion; } } - $$screenname=&Apache::loncommon::screenname( - $$contrib{$idx.':sendername'}, - $$contrib{$idx.':senderdomain'}); - $$plainname=&Apache::loncommon::nickname( - $$contrib{$idx.':sendername'}, - $$contrib{$idx.':senderdomain'}); +# $$screenname=&Apache::loncommon::screenname( +# $$contrib{$idx.':sendername'}, +# $$contrib{$idx.':senderdomain'}); +# $$plainname=&Apache::loncommon::nickname( +# $$contrib{$idx.':sendername'}, +# $$contrib{$idx.':senderdomain'}); + ($$screenname,$$plainname)=($$contrib{$idx.':screenname'}, + $$contrib{$idx.':plainname'}); my $sender=&Apache::loncommon::aboutmewrapper( $$plainname, $$contrib{$idx.':sendername'}, @@ -1149,22 +1271,23 @@ sub replicate_attachments { $i ++; } my ($content,$rtncode); - print STDERR "File to replicate is $$attachrefs{$id}{'filename'} in $1,$2\n"; my $uploadreply = &Apache::lonnet::getuploaded('GET',$$attachrefs{$id}{'filename'},$1,$2,$content,$rtncode); if ($uploadreply eq 'ok') { - my $attachcopy; - if ($attachcopy = Apache::File->new('>'.$destination)) { - print $attachcopy $content; - close($attachcopy); - } else { - $response .= 'Error copying a file attachment to IMS package: '.$!.'
'."\n"; - } + my $attachcopy; + if ($attachcopy = Apache::File->new('>'.$destination)) { + print $attachcopy $content; + close($attachcopy); + } else { + $response .= 'Error copying file attachment - '.$5.' to IMS package: '.$!.'
'."\n"; + } } else { - print STDERR "return code from lonnet was $rtncode\n"; + &Apache::lonnet::logthis("Replication of attachment failed when building IMS export of discussion posts - domain: $1, course: $2, file: $$attachrefs{$id}{'filename'} -error: $rtncode"); + $response .= 'Error copying file attachment - '.$5.' to IMS package: '.$rtncode.'
'."\n"; } } } } + return $response; } sub mail_screen { @@ -1306,15 +1429,16 @@ END } if ($ENV{'form.origpage'}) { - $subject = $ENV{'form.subject'}; - $comment = $ENV{'form.comment'}; + $subject = &Apache::lonnet::unescape($ENV{'form.subject'}); + $comment = &Apache::lonnet::unescape($ENV{'form.comment'}); &process_attachments(\@currnewattach,\@currdelold,\@keepold); } my $latexHelp=&Apache::loncommon::helpLatexCheatsheet(); my $htmlheader=&Apache::lonhtmlcommon::htmlareaheaders(); my $send=&mt('Send'); + my $html=&Apache::lonxml::xmlbegin(); $r->print(< +$html The LearningOnline Network with CAPA @@ -1470,10 +1594,8 @@ END sub print_display_options { my ($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl) = @_; - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; my $function = &Apache::loncommon::get_users_function(); my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg', @@ -1540,8 +1662,9 @@ sub print_display_options { $currtogg = $lt{'toggon'}; $disctogg = 'toggon'; } + my $html=&Apache::lonxml::xmlbegin(); $r->print(< +$html $lt{'dido'} @@ -1632,18 +1755,18 @@ $lt{'sdpf'}
$lt{'prca'}
  1. $l
$lt{'disa'} $lt{$discdisp} $lt{'chgt'} "$dispchangeA" +
-  $lt{'chgt'} "$dispchangeB" +
$lt{'npmr'} $lt{$discmark}$lt{'chgt'} "$markchange"
$lt{'dotm'} $lt{$disctogg}$lt{'chgt'} "$toggchange"
@@ -1654,6 +1777,7 @@ $lt{'sdpf'}
$lt{'prca'}
  1. $l

    + @@ -1671,38 +1795,22 @@ END sub print_sortfilter_options { my ($r,$symb,$previous,$feedurl) = @_; - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } + + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + + &Apache::lonenc::check_encrypt(\$symb); my @sections = (); my $section_sel = ''; my $numsections = 0; my $numvisible = 5; - my ($classlist) = &Apache::loncoursedata::get_classlist( - $ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - - my $sec_index = &Apache::loncoursedata::CL_SECTION(); - my $status_index = &Apache::loncoursedata::CL_STATUS(); my %sectioncount = (); - while (my ($student,$data) = each %$classlist) { - my ($section,$status) = ($data->[$sec_index], - $data->[$status_index]); - unless ($section eq '' || $section =~ /^\s*$/) { - if (!defined($sectioncount{$section})) { - $sectioncount{$section} = 1; - $numsections ++; - } else { - $sectioncount{$section} ++; - } - } - } - - if ($ENV{'request.course.sec'} !~ /^\s*$/) { - @sections = ($ENV{'request.course.sec'}); - $numvisible = 1; + + $numsections = &Apache::loncommon::get_sections($ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'},\%sectioncount); + + if ($ENV{'request.course.sec'} !~ /^\s*$/) { #Restrict section choice to current section + @sections = ('all',$ENV{'request.course.sec'}); + $numvisible = 2; } else { @sections = sort {$a cmp $b} keys(%sectioncount); unshift(@sections,'all'); # Put 'all' at the front of the list @@ -1724,19 +1832,49 @@ sub print_sortfilter_options { 'diop' => 'Display Options', 'curr' => 'Current setting ', 'actn' => 'Action', - 'prca' => 'Options can be set that control the sort order of the posts, in addition to which posts are displayed.', + 'prca' => 'Set options that control the sort order of posts, and/or which posts are displayed.', 'soor' => 'Sort order', - 'disp' => 'Specific user roles', - 'actv' => 'Specific role status', + 'spur' => 'Specific user roles', + 'sprs' => 'Specific role status', 'spse' => 'Specific sections', 'psub' => 'Pick specific users (by name)', 'shal' => 'Show a list of current posters' ); + + my %sort_types = (); + my %role_types = (); + my %status_types = (); + &sort_filter_names(\%sort_types,\%role_types,\%status_types); + my $html=&Apache::lonxml::xmlbegin(); $r->print(< +$html $lt{'diso'} + $bodytag
    @@ -1746,60 +1884,61 @@ $bodytag $lt{'soor'}   - $lt{'disp'} + $lt{'sprs'}   - $lt{'actv'} + $lt{'spur'}   $lt{'spse'}   $lt{'psub'} - +   - - +
    @@ -1810,24 +1949,15 @@ END sub print_showposters { my ($r,$symb,$previous,$feedurl,$sortposts) = @_; - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } -# backward compatibility (bulletin boards used to be 'wrapped') - my $ressymb=$symb; - if ($ressymb =~ /bulletin___\d+___/) { - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - } + + &Apache::lonenc::check_encrypt(\$symb); my $crs='/'.$ENV{'request.course.id'}; if ($ENV{'request.course.sec'}) { $crs.='_'.$ENV{'request.course.sec'}; } $crs=~s/\_/\//g; my $seeid=&Apache::lonnet::allowed('rin',$crs); - my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'}, + 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 %namesort = (); @@ -1868,8 +1998,9 @@ sub print_showposters { } } } + my $html=&Apache::lonxml::xmlbegin(); $r->print(< +$html $lt{'diso'} @@ -1896,7 +2027,7 @@ END next; } else { $count ++; - $r->print(''.$count.''.$last.', '.$first.' ('.$uname.','.$udom.')'.$postcounts{$_}.''); + $r->print(''.$count.''.$postcounts{$_}.''); } } } @@ -1977,65 +2108,29 @@ sub get_post_attachments { return; } -sub build_ims_export { - my ($r,$symb,$previous,$feedurl) = @_; - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - 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 @depth=(); - my %alldiscussion=(); - my @discussionitems=(); - my %usernamesort = (); - my %subjectsort = (); - my %namesort = (); - my %notshown = (); - my %newitem = (); - my %dischash = (); - my %shown = (); - my %roleinfo = (); - my @posters=(); - my $maxdepth=0; - my $visible=0; - my $newpostsflag=0; - my $status; - my $viewgrades; - my $seeid; - my $prevread; - my $sortposts; - my $ressymb; - my $target; - my $readkey; - my $showunmark; - my $showonlyunread; - -} - - - -sub fail_redirect {; +sub fail_redirect { my ($r,$feedurl) = @_; if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; + my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); + my $html=&Apache::lonxml::xmlbegin(); $r->print (< -Feedback not sent +$html + +Feedback not sent - + Sorry, no recipients ... -Continue +
    Continue ENDFAILREDIR } sub redirect_back { - my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$secpick,$numpicks) = @_; + my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$numpicks) = @_; my $sorttag = ''; my $roletag = ''; my $statustag = ''; @@ -2043,10 +2138,11 @@ sub redirect_back { my $userpicktag = ''; my $qrystr = ''; my $prevtag = ''; - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } + + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + + &dewrapper(\$feedurl); if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; if ($previous > 0) { $qrystr = 'previous='.$previous; @@ -2065,29 +2161,55 @@ sub redirect_back { $feedurl .= '?'.$sortqry; } $sorttag = ''; - if ( (defined($numpicks)) && ($numpicks > 0) ) { + if (defined($numpicks)) { my $userpickqry = 'totposters='.$numpicks; $feedurl .= '&'.$userpickqry; $userpicktag = ''; } else { - my $roleqry = 'rolefilter='.$rolefilter; - $feedurl .= '&'.$roleqry; - $roletag = ''; + if (ref($sectionpick) eq 'ARRAY') { + $feedurl .= '§ionpick='; + $sectag .= ''; + } else { + $feedurl .= '§ionpick='.$sectionpick; + $sectag = ''; + } + if (ref($rolefilter) eq 'ARRAY') { + $feedurl .= '&rolefilter='; + $roletag .= ''; + } else { + $feedurl .= '&rolefilter='.$rolefilter; + $roletag = ''; + } $feedurl .= '&statusfilter='.$statusfilter; $statustag =''; - $feedurl .= '§ionpick='.$secpick; - $sectag = ''; } } + $feedurl=&Apache::lonenc::check_encrypt($feedurl); + my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); + my $html=&Apache::lonxml::xmlbegin(); $r->print (< +$html Feedback sent - + $typestyle Sent $sendsomething message(s), and $sendposts post(s). $status @@ -2099,7 +2221,7 @@ $roletag $sectag $userpicktag -Continue +
    Continue ENDREDIR @@ -2109,69 +2231,75 @@ sub no_redirect_back { my ($r,$feedurl) = @_; my $nofeed=&mt('Sorry, no feedback possible on this resource ...'); my $continue=&mt('Continue'); + my $html=&Apache::lonxml::xmlbegin(); $r->print (< -Feedback not sent +$html + +Feedback not sent ENDNOREDIR if ($feedurl!~/^\/adm\/feedback/) { - $r->print(''); + $r->print(''); } - + $feedurl=&Apache::lonenc::check_encrypt($feedurl); + my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); $r->print (< - + $nofeed -$continue +
    $continue ENDNOREDIRTWO } sub screen_header { - my ($feedurl) = @_; + my ($feedurl,$symb) = @_; my $msgoptions=''; my $discussoptions=''; unless (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) { if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) { $msgoptions= - '

    '. - &mt('Feedback to resource author').'

    '; + '

    '; } if (&feedback_available(1)) { $msgoptions.= - '
    '. - &mt('Question about resource content'); + '

    '; } if (&feedback_available(0,1)) { $msgoptions.= - '
    '. - &mt('Question/Comment/Feedback about course content'); + '

    '; } if (&feedback_available(0,0,1)) { $msgoptions.= - '
    '. - &mt('Question/Comment/Feedback about course policy'); + '

    '; } } if ($ENV{'request.course.id'}) { - if (&discussion_open() && + if (&discussion_open(undef,$symb) && &Apache::lonnet::allowed('pch', $ENV{'request.course.id'}. ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { - $discussoptions=' '. &mt('Contribution to course discussion of resource'); - $discussoptions.='
    '. + $discussoptions.='
    '; + } } - if ($msgoptions) { $msgoptions='

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

    '.$msgoptions; } + if ($msgoptions) { $msgoptions='

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

    '.$msgoptions; } if ($discussoptions) { - $discussoptions='

    '.&mt('Discussion Contributions').'

    '.$discussoptions; } + $discussoptions='

    '.&mt('Discussion Contributions').'

    '.$discussoptions; } return $msgoptions.$discussoptions; } @@ -2216,8 +2344,6 @@ sub clear_out_html { sub assemble_email { my ($feedurl,$message,$prevattempts,$usersaw,$useranswer)=@_; my $email=<<"ENDEMAIL"; -Refers to $feedurl - $message ENDEMAIL my $citations=<<"ENDCITE"; @@ -2334,7 +2460,13 @@ sub send_msg { sub adddiscuss { my ($symb,$email,$anon,$attachmenturl,$subject)=@_; my $status=''; - if (&discussion_open() && + my $realsymb; + if ($symb=~/^bulletin___/) { + my $filename=(&Apache::lonnet::decode_symb($symb))[2]; + $filename=~s|^adm/wrapper/||; + $realsymb=&Apache::lonnet::symbread($filename); + } + if (&discussion_open(undef,$realsymb) && &Apache::lonnet::allowed('pch',$ENV{'request.course.id'}. ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { @@ -2363,6 +2495,7 @@ sub adddiscuss { $contrib{'history'} = ''; my $numoldver = 0; my ($oldsymb,$oldidx)=split(/\:\:\:/,$ENV{'form.editdisc'}); + &Apache::lonenc::check_decrypt(\$oldsymb); $oldsymb=~s|(bulletin___\d+___)adm/wrapper/|$1|; # get timestamp for last post and history my %oldcontrib=&Apache::lonnet::restore($oldsymb,$ENV{'request.course.id'}, @@ -2438,6 +2571,8 @@ sub adddiscuss { sub show_preview { my $r=shift; + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; my $message=&clear_out_html($ENV{'form.comment'}); $message=~s/\n/\
    /g; $message=&Apache::lonspeller::markeduptext($message); @@ -2445,9 +2580,11 @@ sub show_preview { my $subject=&clear_out_html($ENV{'form.subject'}); $subject=~s/\n/\
    /g; $subject=&Apache::lontexconvert::msgtexconverted($subject); - $r->print('
    '. - 'Subject: '.$subject.'

    '. - $message.'
    '); + my $html=&Apache::lonxml::xmlbegin(); + $r->print($html.''. + '
    '. + 'Subject: '.$subject.'

    '. + $message.'
    '); } sub generate_preview_button { @@ -2464,7 +2601,8 @@ ENDPREVIEW sub modify_attachments { my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_; - my $subject=&clear_out_html($ENV{'form.subject'}); + my $orig_subject = &Apache::lonnet::unescape($ENV{'form.subject'}); + my $subject=&clear_out_html($orig_subject); $subject=~s/\n/\
    /g; $subject=&Apache::lontexconvert::msgtexconverted($subject); my $timestamp=$ENV{'form.timestamp'}; @@ -2477,8 +2615,10 @@ sub modify_attachments { if ($idx) { &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold); } + &Apache::lonenc::check_encrypt(\$symb); + my $html=&Apache::lonxml::xmlbegin(); $r->print(< +$html Managing Attachments