--- loncom/interface/lonfeedback.pm 2004/08/03 21:29:32 1.112 +++ loncom/interface/lonfeedback.pm 2005/02/17 04:11:20 1.151 @@ -1,7 +1,7 @@ # The LearningOnline Network # Feedback # -# $Id: lonfeedback.pm,v 1.112 2004/08/03 21:29:32 raeburn Exp $ +# $Id: lonfeedback.pm,v 1.151 2005/02/17 04:11:20 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,17 +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; } @@ -58,15 +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; @@ -76,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'; @@ -102,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; @@ -117,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) { @@ -133,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'}, @@ -159,52 +183,54 @@ 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=(); - my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + + my $current=0; my $visible=0; my @depth=(); - my @original=(); - my @index=(); - my @replies=(); + my @replies = (); my %alldiscussion=(); + my %imsitems=(); + my %imsfiles=(); my %notshown = (); my %newitem = (); my $maxdepth=0; @@ -219,346 +245,14 @@ sub list_discussion { $discinfo{$visitkey} = $visit; &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - - if ($contrib{'version'}) { - my $oldest = $contrib{'1:timestamp'}; - if ($prevread eq '0') { - $prevread = $oldest-1; - } - for (my $id=1;$id<=$contrib{'version'};$id++) { - my $idx=$id; - my $posttime = $contrib{$idx.':timestamp'}; - if ($prevread <= $posttime) { - $newpostsflag = 1; - } - my $hidden=($contrib{'hidden'}=~/\.$idx\./); - my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./); - my $deleted=($contrib{'deleted'}=~/\.$idx\./); - my $origindex='0.'; - my $numoldver=0; - if ($contrib{$idx.':replyto'}) { - if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread')) { -# this is a follow-up message - $original[$idx]=$original[$contrib{$idx.':replyto'}]; - $depth[$idx]=$depth[$contrib{$idx.':replyto'}]+1; - $origindex=$index[$contrib{$idx.':replyto'}]; - if ($depth[$idx]>$maxdepth) { $maxdepth=$depth[$idx]; } - } else { - $original[$idx]=0; - $depth[$idx]=0; - } - } else { -# this is an original message - $original[$idx]=0; - $depth[$idx]=0; - } - if ($replies[$depth[$idx]]) { - $replies[$depth[$idx]]++; - } else { - $replies[$depth[$idx]]=1; - } - unless ((($hidden) && (!$seeid)) || ($deleted)) { - $visible++; - if ($contrib{$idx.':history'}) { - if ($contrib{$idx.':history'} =~ /:/) { - my @oldversions = split/:/,$contrib{$idx.':history'}; - $numoldver = @oldversions; - } else { - $numoldver = 1; - } - } - my ($message,$subject); - if ($idx > 0) { - if ($contrib{$idx.':message'} =~ /^/) { - my %versions = (); - &get_post_versions(\%versions,$contrib{$idx.':message'},$numoldver); - $message = &HTML::Entities::decode($versions{$numoldver}); - } else { - $message = $contrib{$idx.':message'}; - } - } else { - $message=$contrib{$idx.':message'}; - } - my $attachmenturls = $contrib{$idx.':attachmenturl'}; - $message=~s/\n/\
/g; - $message=&Apache::lontexconvert::msgtexconverted($message); - if ($idx > 0) { - if ($contrib{$idx.':subject'} =~ /^/g; - $subject=&Apache::lontexconvert::msgtexconverted($subject); - } - if ($attachmenturls) { - my @attachments = (); - my %currattach = (); - &extract_attachments($attachmenturls,$idx,$numoldver,\$message,\@attachments,\%currattach); - } - if ($message) { - if ($hidden) { - $message=''.$message.''; - if ($studenthidden) { - $message .='

Deleted by poster (student).'; - } - } - my $screenname=&Apache::loncommon::screenname( - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}); - my $plainname=&Apache::loncommon::nickname( - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}); - - my $sender=&mt('Anonymous'); -# Set up for sorting by subject - if ($contrib{$idx.':subject'} eq '') { - if (defined($subjectsort{'__No subject'})) { - push @{$subjectsort{'__No subject'}}, $idx; - } else { - @{$subjectsort{'__No subject'}} = ("$idx"); - } - } else { - if (defined($subjectsort{$contrib{$idx.':subject'}})) { - push @{$subjectsort{$contrib{$idx.':subject'}}}, $idx; - } else { - @{$subjectsort{$contrib{$idx.':subject'}}} = ("$idx"); - } - } - if ((!$contrib{$idx.':anonymous'}) || ($seeid)) { - $sender=&Apache::loncommon::aboutmewrapper( - $plainname, - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}).' ('. - $contrib{$idx.':sendername'}.' at '. - $contrib{$idx.':senderdomain'}.')'; - if ($contrib{$idx.':anonymous'}) { - $sender.=' ['.&mt('anonymous').'] '. - $screenname; - } -# 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; - } else { - @{$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx"); - } -# Set up for sorting by last name, then first name - my %names = &Apache::lonnet::get('environment',['firstname','lastname'], - $contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'}); - my $lastname = $names{'lastname'}; - my $firstname = $names{'firstname'}; - if ($lastname eq '') { - $lastname = '_'; - } - if ($firstname eq '') { - $firstname = '_'; - } - unless (defined($namesort{$lastname})) { - %{$namesort{$lastname}} = (); - } - if (defined($namesort{$lastname}{$firstname})) { - push @{$namesort{$lastname}{$firstname}}, $idx; - } else { - @{$namesort{$lastname}{$firstname}} = ("$idx"); - } - if ($ENV{"course.$cid.allow_discussion_post_editing"} =~ m/yes/i) { - if (($ENV{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($ENV{'user.name'} eq $contrib{$idx.':sendername'})) { - $sender.=' '.&mt('Edit').''; unless ($seeid) { - $sender.=" '; - } - } - } - if ($seeid) { - if ($hidden) { - unless ($studenthidden) { - $sender.=' '.&mt('Make Visible').''; - } - } else { - $sender.=' '.&mt('Hide').''; - } - $sender.=' '.&mt('Delete').''; - } - } else { - if ($screenname) { - $sender=''.$screenname.''; - } -# Set up for sorting by domain, then username for anonymous - unless (defined($usernamesort{'__anon'})) { - %{$usernamesort{'__anon'}} = (); - } - if (defined($usernamesort{'__anon'}{'__anon'})) { - push @{$usernamesort{'__anon'}{'__anon'}}, $idx; - } else { - @{$usernamesort{'__anon'}{'__anon'}} = ("$idx"); - } -# Set up for sorting by last name, then first name for anonymous - unless (defined($namesort{'__anon'})) { - %{$namesort{'__anon'}} = (); - } - if (defined($namesort{'__anon'}{'__anon'})) { - push @{$namesort{'__anon'}{'__anon'}}, $idx; - } else { - @{$namesort{'__anon'}{'__anon'}} = ("$idx"); - } - } - if (&discussion_open($status) && - &Apache::lonnet::allowed('pch', - $ENV{'request.course.id'}. - ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { - $sender.=' '.&mt('Reply').''; - } - my $vgrlink; - if ($viewgrades) { - $vgrlink=&Apache::loncommon::submlink('Submissions', - $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$symb); - } - my $ctlink; - if ($dischash{$readkey}=~/\.$idx\./) { - $ctlink = ''.&mt('Mark unread').'? '; - } else { - $ctlink = ''.&mt('Mark read').'? '; - } -#figure out at what position this needs to print - my $thisindex=$idx; - if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread')) { - $thisindex=$origindex.substr('00'.$replies[$depth[$idx]],-2,2); - } - $alldiscussion{$thisindex}=$idx; - $shown{$idx} = 0; - $index[$idx]=$thisindex; - my $spansize = 2; - if ($showonlyunread && $prevread > $posttime) { - $notshown{$idx} = 1; - } elsif ($showunmark && $dischash{$readkey}=~/\.$idx\./) { - $notshown{$idx} = 1; - } else { -# apply filters - 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 ($skiptest) { - $shown{$idx} = 1; - } else { - foreach my $role (@{$roleinfo{$poster}}) { - if ($role =~ m/^$rolematch$/) { - $shown{$idx} = 1; - last; - } - } - } - } - } - unless ($notshown{$idx} == 1) { - if ($prevread > 0 && $prevread <= $posttime) { - $newitem{$idx} = 1; - $discussionitems[$idx] .= ' -

- '; - } else { - $newitem{$idx} = 0; - $discussionitems[$idx] .= ' -

NEW
- '; - } - $discussionitems[$idx] .= ''; - if ($dischash{$toggkey}) { - $discussionitems[$idx].=''; - } - $discussionitems[$idx].= '
   '. - ''.$subject.'  '. - $sender.' '.$vgrlink.' ('. - &Apache::lonlocal::locallocaltime($posttime).')  '. - $ctlink.'

'.$message.'

'; - if ($contrib{$idx.':history'}) { - my @postversions = (); - $discussionitems[$idx] .= '
'.&mt('This post has been edited by the author.'); - if ($seeid) { - $discussionitems[$idx] .= '  '.&mt('Display all versions').''; - } - $discussionitems[$idx].='
'.&mt('Earlier version(s) were posted on: '); - if ($contrib{$idx.':history'} =~ m/:/) { - @postversions = split/:/,$contrib{$idx.':history'}; - } else { - @postversions = ("$contrib{$idx.':history'}"); - } - for (my $i=0; $i<@postversions; $i++) { - my $version = $i+1; - $discussionitems[$idx] .= ''.$version.'. - '.&Apache::lonlocal::locallocaltime($postversions[$i]).' '; - } - } - } - } - } - } - } + &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; + my $manifestok=0; + my $tempexport; + my $imsresources; + my $copyresult; my $function = &Apache::loncommon::get_users_function(); my $color = &Apache::loncommon::designparm($function.'.tabbg', @@ -627,7 +321,56 @@ sub list_discussion { if ($visible) { # Print the discusssion - if ($outputtarget ne 'tex') { + if ($outputtarget eq 'tex') { + $discussion.='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'. + '\textbf{DISCUSSIONS}\makebox[2 cm][b]{\hrulefill}'. + '\vskip 0 mm\noindent\textbf{'.$lt{'cuse'}.'}:\vskip 0 mm'. + '\noindent\textbf{'.$lt{'disa'}.'}: \textit{'.$currdisp.'}\vskip 0 mm'. + '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}'; + } elsif ($outputtarget eq 'export') { +# Create temporary directory if this is an export + my $now = time; + 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'}; + } + if (!-e $tempexport) { + mkdir($tempexport,0700); + } +# open manifest file + my $manifest = '/imsmanifest.xml'; + my $manifestfilename = $tempexport.$manifest; + if ($manifestfile = Apache::File->new('>'.$manifestfilename)) { + $manifestok=1; + print $manifestfile qq| + + + + + Discussion for $ressymb\n|; + } else { + $discussion .= 'An error occurred opening the manifest file.
'; + } + } else { my $colspan=$maxdepth+1; $discussion.= qq| |; - $discussion.='
'; + $discussion.='
'; $discussion .=''; - } else { - $discussion.='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'. - '\textbf{DISCUSSIONS}\makebox[2 cm][b]{\hrulefill}'. - '\vskip 0 mm\noindent\textbf{'.$lt{'cuse'}.'}:\vskip 0 mm'. - '\noindent\textbf{'.$lt{'disa'}.'}: \textit{'.$currdisp.'}\vskip 0 mm'. - '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}'; - } - my $numhidden = keys %notshown; - if ($numhidden > 0) { - my $colspan = $maxdepth+1; - $discussion.="\n".''; } - $discussion .= '
'; } # Choose sort mechanism @@ -729,31 +467,26 @@ sub list_discussion { } } } else { - $sortposts = 'ascdate'; @showposts = (sort { $a <=> $b } keys %alldiscussion); } + my $currdepth = 0; + my $firstidx = $alldiscussion{$showposts[0]}; foreach (@showposts) { - unless (($sortposts eq 'thread') || ($sortposts eq 'ascdate' && $ENV{'environment.threadeddiscussion'})) { + unless (($sortposts eq 'thread') || (($sortposts eq '') && ($ENV{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) { $alldiscussion{$_} = $_; } unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) { - if ($outputtarget ne 'tex') { + if ($outputtarget ne 'tex' && $outputtarget ne 'export') { $discussion.="\n"; - } else { - $discussion.='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'; } my $thisdepth=$depth[$alldiscussion{$_}]; - if ($outputtarget ne 'tex') { + if ($outputtarget ne 'tex' && $outputtarget ne 'export') { for (1..$thisdepth) { $discussion.=''; } } my $colspan=$maxdepth-$thisdepth+1; - if ($outputtarget ne 'tex') { - $discussion.=''; - } else { + if ($outputtarget eq 'tex') { #cleanup block $discussionitems[$alldiscussion{$_}]=~s/]*)>/
'. ''; if ($visible>2) { $discussion.=''; if ($newpostsflag) { if (!$markondisp) { - $discussion .=''; } @@ -681,29 +424,24 @@ sub list_discussion { $discussion .= ''; } $discussion .= '
'. - '  '. - '   -   '.&mt('Mark NEW posts no longer new').'  '; + $discussion .=''.&mt('Mark NEW posts no longer new').'  '; } else { $discussion .= '  
'. - ''.&mt('Show all posts').' '.&mt('to display').' '. + + my $numhidden = keys %notshown; + if ($numhidden > 0) { + my $colspan = $maxdepth+1; + $discussion.="\n".'
'. + ''.&mt('Show all posts').' '.&mt('to display').' '. $numhidden.' '; - if ($showunmark) { - $discussion .= &mt('posts previously marked read'); - } else { - $discussion .= &mt('previously viewed posts'); + if ($showunmark) { + $discussion .= &mt('posts previously marked read'); + } else { + $discussion .= &mt('previously viewed posts'); + } + $discussion .= '
   '. - $discussionitems[$alldiscussion{$_}]. - '
/; $discussionitems[$alldiscussion{$_}]=~s/]*)>]*)>/'; + } } } - if ($outputtarget ne 'tex') { + unless ($outputtarget eq 'tex' || $outputtarget eq 'export') { my $colspan=$maxdepth+1; $discussion .= < @@ -806,13 +570,54 @@ END $discussion .= < -
/; @@ -764,17 +497,48 @@ sub list_discussion { $discussionitems[$alldiscussion{$_}]=~s/<\/td>]*)>/$threadinsert<\/td>/; $discussionitems[$alldiscussion{$_}]=~s/]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g; $discussionitems[$alldiscussion{$_}]=~s/(|<\/b>|<\/a>|]+)>)//g; - - #FIXME xmlparse can't be safely called from inside xmlparse - # due to the global variables that are use, the safe - # space etc. I expect this has unforseen issues that - # need resolving. - - $discussion.=&Apache::lonxml::xmlparse('','tex',$discussionitems[$alldiscussion{$_}]); - } + + $discussionitems[$alldiscussion{$_}]='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.$discussionitems[$alldiscussion{$_}]; + $discussion.=$discussionitems[$alldiscussion{$_}]; + } elsif ($outputtarget eq 'export') { + my $postfilename = $alldiscussion{$_}.'-'.$imsitems{$alldiscussion{$_}}{'timestamp'}.'.html'; + if ($manifestok) { + if (($depth[$alldiscussion{$_}] <= $currdepth) && ($alldiscussion{$_} != $firstidx)) { + print $manifestfile ' '."\n"; + } + $currdepth = $depth[$alldiscussion{$_}]; + print $manifestfile "\n". + ''. + ''.$imsitems{$alldiscussion{$_}}{'title'}.''; + $imsresources .= "\n". + ''."\n". + ''."\n". + $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'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"; + close($postingfile); + } else { + $discussion .= 'An error occurred opening the export file for posting '.$alldiscussion{$_}.'
'; + } + $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$_}}{'allattachments'},$tempexport); + } else { + $discussion.='
'. $discussionitems[$alldiscussion{$_}]. + '
  + $lt{'chgt'}?
END + if ($sortposts) { + my %sort_types = (); + my %role_types = (); + my %status_types = (); + &sort_filter_names(\%sort_types,\%role_types,\%status_types); + + $discussion .= ''.&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 .= '
'; + } + } if ($dischash{$toggkey}) { my $storebutton = &mt('Store read/unread changes'); $discussion.=''. @@ -829,7 +634,53 @@ END

END - } + } + if ($outputtarget eq 'export') { + if ($manifestok) { + while ($currdepth > 0) { + print $manifestfile " \n"; + $currdepth --; + } + print $manifestfile qq| +
+
+ + $imsresources + +
+ |; + 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'; + # 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; + } + } + } 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.
'; + } + return $discussion; + } } if ($discussiononly) { my $now = time; @@ -841,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.=(< @@ -862,46 +714,580 @@ 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'}:''))) { + 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').'
'; } } } - return $discussion; + return $discussion; +} + +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 $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'}); + + if ($contrib{'version'}) { + my $oldest = $contrib{'1:timestamp'}; + 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'}; + if ($prevread <= $posttime) { + $$newpostsflag = 1; + } + my $hidden=($contrib{'hidden'}=~/\.$idx\./); + my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./); + my $deleted=($contrib{'deleted'}=~/\.$idx\./); + my $origindex='0.'; + my $numoldver=0; + if ($contrib{$idx.':replyto'}) { + 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; + $origindex=$index[$contrib{$idx.':replyto'}]; + if ($$depth[$idx]>$$maxdepth) { $$maxdepth=$$depth[$idx]; } + } else { + $original[$idx]=0; + $$depth[$idx]=0; + } + } else { +# this is an original message + $original[$idx]=0; + $$depth[$idx]=0; + } + if ($$replies[$$depth[$idx]]) { + $$replies[$$depth[$idx]]++; + } else { + $$replies[$$depth[$idx]]=1; + } + unless ((($hidden) && (!$seeid)) || ($deleted)) { + $$visible++; + if ($contrib{$idx.':history'}) { + if ($contrib{$idx.':history'} =~ /:/) { + my @oldversions = split/:/,$contrib{$idx.':history'}; + $numoldver = @oldversions; + } else { + $numoldver = 1; + } + } + $$current = $numoldver; + my %messages = (); + my %subjects = (); + my %attachtxt = (); + my %allattachments = (); + my ($screenname,$plainname); + my $sender = &mt('Anonymous'); + my ($message,$subject,$vgrlink,$ctlink); + &get_post_contents(\%contrib,$idx,$seeid,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,$numoldver); + + +# Set up for sorting by subject + unless ($outputtarget eq 'export') { + $message=$messages{$numoldver}; + $message.=$attachtxt{$numoldver}; + $subject=$subjects{$numoldver}; + if ($message) { + if ($hidden) { + $message=''.$message.''; + if ($studenthidden) { + $message .='

Deleted by poster (student).'; + } + } + + if ($subject eq '') { + if (defined($$subjectsort{'__No subject'})) { + push @{$$subjectsort{'__No subject'}}, $idx; + } else { + @{$$subjectsort{'__No subject'}} = ("$idx"); + } + } else { + if (defined($$subjectsort{$subject})) { + push @{$$subjectsort{$subject}}, $idx; + } else { + @{$$subjectsort{$subject}} = ("$idx"); + } + } + if ((!$contrib{$idx.':anonymous'}) || ($seeid)) { + $sender=&Apache::loncommon::aboutmewrapper( + $plainname, + $contrib{$idx.':sendername'}, + $contrib{$idx.':senderdomain'}).' ('. + $contrib{$idx.':sendername'}.' at '. + $contrib{$idx.':senderdomain'}.')'; + if ($contrib{$idx.':anonymous'}) { + $sender.=' ['.&mt('anonymous').'] '. + $screenname; + } + +# 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; + } else { + @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx"); + } +# Set up for sorting by last name, then first name + my %names = &Apache::lonnet::get('environment', + ['firstname','lastname'],$contrib{$idx.':senderdomain'}, + ,$contrib{$idx.':sendername'}); + my $lastname = $names{'lastname'}; + my $firstname = $names{'firstname'}; + if ($lastname eq '') { + $lastname = '_'; + } + if ($firstname eq '') { + $firstname = '_'; + } + unless (defined($$namesort{$lastname})) { + %{$$namesort{$lastname}} = (); + } + if (defined($$namesort{$lastname}{$firstname})) { + push @{$$namesort{$lastname}{$firstname}}, $idx; + } else { + @{$$namesort{$lastname}{$firstname}} = ("$idx"); + } + if ($ENV{'course.'.$ENV{'request.course.id'}.'.allow_discussion_post_editing'} =~ m/yes/i) { + if (($ENV{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($ENV{'user.name'} eq $contrib{$idx.':sendername'})) { + $sender.=' '.&mt('Edit').''; + unless ($seeid) { + $sender.=" '; + } + } + } + if ($seeid) { + if ($hidden) { + unless ($studenthidden) { + $sender.=' '.&mt('Make Visible').''; + } + } else { + $sender.=' '.&mt('Hide').''; + } + $sender.=' '.&mt('Delete').''; + } + } else { + if ($screenname) { + $sender=''.$screenname.''; + } +# Set up for sorting by domain, then username for anonymous + unless (defined($$usernamesort{'__anon'})) { + %{$$usernamesort{'__anon'}} = (); + } + if (defined($$usernamesort{'__anon'}{'__anon'})) { + push @{$$usernamesort{'__anon'}{'__anon'}}, $idx; + } else { + @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx"); + } +# Set up for sorting by last name, then first name for anonymous + unless (defined($$namesort{'__anon'})) { + %{$$namesort{'__anon'}} = (); + } + if (defined($$namesort{'__anon'}{'__anon'})) { + push @{$$namesort{'__anon'}{'__anon'}}, $idx; + } else { + @{$$namesort{'__anon'}{'__anon'}} = ("$idx"); + } + } + if (&discussion_open($status) && + &Apache::lonnet::allowed('pch', + $ENV{'request.course.id'}. + ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { + $sender.=' '.&mt('Reply').''; + } + if ($viewgrades) { + $vgrlink=&Apache::loncommon::submlink('Submissions', + $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb); + } + if ($$dischash{$readkey}=~/\.$idx\./) { + $ctlink = ''; + } else { + $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 'thread') || ($outputtarget eq 'export')) { + $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2); + } + $$alldiscussion{$thisindex}=$idx; + $$shown{$idx} = 0; + $index[$idx]=$thisindex; + } + if ($outputtarget eq 'export') { + %{$$imsitems{$idx}} = (); + $$imsitems{$idx}{'isvisible'}='true'; + if ($hidden) { + $$imsitems{$idx}{'isvisible'}='false'; + } + $$imsitems{$idx}{'title'}=$subjects{$numoldver}; + $$imsitems{$idx}{'message'}=$messages{$numoldver}; + $$imsitems{$idx}{'attach'}=$attachtxt{$numoldver}; + $$imsitems{$idx}{'timestamp'}=$contrib{$idx.':timestamp'}; + $$imsitems{$idx}{'sender'}=$plainname.' ('. + $contrib{$idx.':sendername'}.' at '. + $contrib{$idx.':senderdomain'}.')'; + $$imsitems{$idx}{'isanonymous'}='false'; + if ($contrib{$idx.':anonymous'}) { + $$imsitems{$idx}{'isanonymous'}='true'; + } + $$imsitems{$idx}{'currversion'}=$numoldver; + %{$$imsitems{$idx}{'allattachments'}}=%allattachments; + unless ($messages{$numoldver} eq '' && $attachtxt{$numoldver} eq '') { + $$shown{$idx} = 1; + } + } else { + if ($message) { + my $spansize = 2; + if ($showonlyunread && $prevread > $posttime) { + $$notshown{$idx} = 1; + } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) { + $$notshown{$idx} = 1; + } else { +# apply filters + my $uname = $contrib{$idx.':sendername'}; + my $udom = $contrib{$idx.':senderdomain'}; + my $poster = $uname.':'.$udom; + 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 =~ /^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) { + if ($prevread > 0 && $prevread <= $posttime) { + $$newitem{$idx} = 1; + $$discussionitems[$idx] .= ' +

+ '; + } else { + $$newitem{$idx} = 0; + $$discussionitems[$idx] .= ' +

NEW
+ '; + } + $$discussionitems[$idx] .= ''; + if ($$dischash{$toggkey}) { + $$discussionitems[$idx].=''; + } + $$discussionitems[$idx].= '
   '. + ''.$subject.'  '. + $sender.' '.$vgrlink.' ('. + &Apache::lonlocal::locallocaltime($posttime).')  '. + $ctlink.'

'. + $message.'

'; + if ($contrib{$idx.':history'}) { + my @postversions = (); + $$discussionitems[$idx] .= &mt('This post has been edited by the author.'); + if ($seeid) { + $$discussionitems[$idx] .= '  '.&mt('Display all versions').''; + } + $$discussionitems[$idx].='
'.&mt('Earlier version(s) were posted on: '); + if ($contrib{$idx.':history'} =~ m/:/) { + @postversions = split/:/,$contrib{$idx.':history'}; + } else { + @postversions = ("$contrib{$idx.':history'}"); + } + for (my $i=0; $i<@postversions; $i++) { + my $version = $i+1; + $$discussionitems[$idx] .= ''.$version.'. - '.&Apache::lonlocal::locallocaltime($postversions[$i]).' '; + } + } + } + } + } + } + } + } +} + +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 = ''; + my $start=$numver; + my $end=$numver + 1; + %{$$imsfiles{$idx}}=(); + if ($type eq 'allversions') { + unless($seeid) { + $discussion=&mt('You do not have privileges to view all versions of posts.').&mt('Please select a different role'); + return $discussion; + } + } +# $$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'}, + $$contrib{$idx.':senderdomain'}).' ('. + $$contrib{$idx.':sendername'}.' at '. + $$contrib{$idx.':senderdomain'}.')'; + my $attachmenturls = $$contrib{$idx.':attachmenturl'}; + my @postversions = (); + if ($type eq 'allversions' || $type eq 'export') { + $start = 0; + if ($$contrib{$idx.':history'}) { + if ($$contrib{$idx.':history'} =~ m/:/) { + @postversions = split/:/,$$contrib{$idx.':history'}; + } else { + @postversions = ("$$contrib{$idx.':history'}"); + } + } + &get_post_versions($messages,$$contrib{$idx.':message'},1); + &get_post_versions($subjects,$$contrib{$idx.':subject'},1); + push @postversions,$$contrib{$idx.':timestamp'}; + $end = @postversions; + } else { + &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver); + &get_post_versions($subjects,$$contrib{$idx.':subject'},1,$numver); + } + + if ($$contrib{$idx.':anonymous'}) { + $sender.=' ['.&mt('anonymous').'] '.$$screenname; + } + if ($type eq 'allversions') { + $discussion=(''.$sender.'
    '); + } + for (my $i=$start; $i<$end; $i++) { + my ($timesent,$attachmsg); + my %currattach = (); + $timesent = &Apache::lonlocal::locallocaltime($postversions[$i]); + $$messages{$i}=~s/\n/\
    /g; + $$messages{$i}=&Apache::lontexconvert::msgtexconverted($$messages{$i}); + $$subjects{$i}=~s/\n/\
    /g; + $$subjects{$i}=&Apache::lontexconvert::msgtexconverted($$subjects{$i}); + if ($attachmenturls) { + &extract_attachments($attachmenturls,$idx,$i,\$attachmsg,$allattachments,\%currattach); + } + if ($type eq 'export') { + $$imsfiles{$idx}{$i} = ''; + if ($attachmsg) { + $$attachtxt{$i} = '
    Attachments:
    '; + foreach (sort keys %currattach) { + if ($$allattachments{$_}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) { + my $fname = $1.$3.'/'.$4; + $$imsfiles{$idx}{$i} .= ''."\n"; + $$attachtxt{$i}.= ''.$4.'
    '; + } + } + } + } else { + if ($attachmsg) { + $$attachtxt{$i} = '
    Attachments:'.$attachmsg.'
    '; + } else { + $$attachtxt{$i} = ''; + } + } + if ($type eq 'allversions') { + $discussion.= <<"END"; +
  • $$subjects{$i}, $timesent
    +$$messages{$i}
    +$$attachtxt{$i}
  • +END + } + } + if ($type eq 'allversions') { + $discussion.=('
'); + return $discussion; + } else { + return; + } +} + +sub replicate_attachments { + my ($attachrefs,$tempexport) = @_; + my $response; + 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 $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5; + if (!-e $destination) { + my $i= 0; + while ($i<@extras) { + $path .= '/'.$extras[$i]; + if (!-e $path) { + mkdir($path,0700); + } + $i ++; + } + my ($content,$rtncode); + 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 file attachment - '.$5.' to IMS package: '.$!.'
'."\n"; + } + } else { + &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 { @@ -925,7 +1311,7 @@ sub mail_screen { my @currnewattach = (); my @currdelold = (); my @keepold = (); - my @attachments = (); + my %attachments = (); my %currattach = (); my $attachnum = 0; my $anonchk = (< 0) { - if ($contrib{$idx.':message'} =~ /^/g; $quote='
'.&Apache::lontexconvert::msgtexconverted($message).'
'; if ($idx > 0) { - if ($contrib{$idx.':subject'} =~ /^&"'); } else { $attachmenturls = $contrib{$idx.':attachmenturl'}; - if ($contrib{$idx.':message'} =~ /^/) { - my %versions = (); - &get_post_versions(\%versions,$contrib{$idx.':message'},$numoldver); - $comment = $versions{$numoldver}; - } else { - $comment = &HTML::Entities::encode($contrib{$idx.':message'},'<>&"'); - } - if ($contrib{$idx.':subject'} =~ //) { - my %versions = (); - &get_post_versions(\%versions,$contrib{$idx.':subject'},$numoldver); - $subject = $versions{$numoldver}; - } else { - $subject = &HTML::Entities::encode($contrib{$idx.':subject'},'<>&"'); + if ($idx > 0) { + my %msgversions = (); + &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver); + $comment = $msgversions{$numoldver}; + my %subversions = (); + &get_post_versions(\%subversions,$contrib{$idx.':subject'},0,$numoldver); + $subject = $subversions{$numoldver}; } if (defined($contrib{$idx.':replyto'})) { $parentmsg = $contrib{$idx.':replyto'}; @@ -1060,8 +1429,8 @@ 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(); @@ -1109,7 +1478,7 @@ $htmlheader } if (rec) { - if (typeof(document.mailform.onsubmit)!='undefined') { + if (typeof(document.mailform.onsubmit)=='function') { document.mailform.onsubmit(); } document.mailform.submit(); @@ -1163,7 +1532,7 @@ END } if ($ENV{'form.editdisc'}) { if ($attachmenturls) { - &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\@attachments,\%currattach,\@currdelold); + &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold); $attachnum = scalar(keys %currattach); foreach (keys %currattach) { $r->print(''."\n"); @@ -1224,10 +1593,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', @@ -1386,18 +1753,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" + @@ -1408,6 +1775,7 @@ $lt{'sdpf'}
    $lt{'prca'}
    1. $l

      + @@ -1425,38 +1793,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 @@ -1478,19 +1830,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); + $r->print(< $lt{'diso'} + $bodytag
      @@ -1500,60 +1882,61 @@ $bodytag $lt{'soor'}   - $lt{'disp'} + $lt{'sprs'}   - $lt{'actv'} + $lt{'spur'}   $lt{'spse'}   $lt{'psub'} - +   - - +
      @@ -1564,24 +1947,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 = (); @@ -1650,7 +2024,7 @@ END next; } else { $count ++; - $r->print(''.$count.''.$last.', '.$first.' ('.$uname.','.$udom.')'.$postcounts{$_}.''); + $r->print(''.$count.''.$postcounts{$_}.''); } } } @@ -1671,27 +2045,70 @@ END } sub get_post_versions { - my ($versions,$incoming,$numver) = @_; - my $p = HTML::LCParser->new(\$incoming); - my $done = 0; - while ( (my $token = $p->get_tag("version")) && (!$done)) { - my $num = $token->[1]{num}; - my $text = $p->get_text("/version"); - if (defined($numver)) { - if ($num == $numver) { - $$versions{$numver}=$text; - $done = 1; + my ($versions,$incoming,$htmldecode,$numver) = @_; + if ($incoming =~ /^/) { + my $p = HTML::LCParser->new(\$incoming); + my $done = 0; + while ( (my $token = $p->get_tag("version")) && (!$done)) { + my $num = $token->[1]{num}; + my $text = $p->get_text("/version"); + if (defined($numver)) { + if ($num == $numver) { + if ($htmldecode) { + $text = &HTML::Entities::decode($text); + } + $$versions{$numver}=$text; + $done = 1; + } + } else { + if ($htmldecode) { + $text = &HTML::Entities::decode($text); + } + $$versions{$num}=$text; } + } + } else { + if (!defined($numver)) { + $numver = 0; + } + if ($htmldecode) { + $$versions{$numver} = $incoming; } else { - $$versions{$num}=$text; + $$versions{$numver} = &HTML::Entities::encode($incoming,'<>&"'); } } return; } +sub get_post_attachments { + my ($attachments,$attachmenturls) = @_; + my $num; + if ($attachmenturls =~ m/^/) { + my $p = HTML::LCParser->new(\$attachmenturls); + while (my $token = $p->get_tag("attachment","filename","post")) { + if ($token->[0] eq "attachment") { + $num = $token->[1]{id}; + %{$$attachments{$num}} =(); + } elsif ($token->[0] eq "filename") { + $$attachments{$num}{'filename'} = $p->get_text("/filename"); + } elsif ($token->[0] eq "post") { + my $id = $token->[1]{id}; + $$attachments{$num}{$id} = $p->get_text("/post"); + } + } + } else { + %{$$attachments{'0'}} = (); + $$attachments{'0'}{'filename'} = $attachmenturls; + $$attachments{'0'}{'0'} = 'n'; + } + + return; +} + sub fail_redirect { my ($r,$feedurl) = @_; if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; + my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); $r->print (< Feedback not sent @@ -1699,15 +2116,16 @@ sub fail_redirect { - + Sorry, no recipients ... +
      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 = ''; @@ -1715,10 +2133,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; @@ -1737,20 +2156,45 @@ 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'); $r->print (< @@ -1759,7 +2203,7 @@ sub redirect_back { - + $typestyle Sent $sendsomething message(s), and $sendposts post(s). $status @@ -1771,6 +2215,7 @@ $roletag $sectag $userpicktag +
      Continue ENDREDIR @@ -1779,6 +2224,7 @@ ENDREDIR sub no_redirect_back { my ($r,$feedurl) = @_; my $nofeed=&mt('Sorry, no feedback possible on this resource ...'); + my $continue=&mt('Continue'); $r->print (< Feedback not sent @@ -1786,61 +2232,66 @@ sub no_redirect_back { 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 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; } @@ -1885,8 +2336,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"; @@ -2003,7 +2452,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'}:''))) { @@ -2032,6 +2487,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'}, @@ -2107,6 +2563,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); @@ -2126,14 +2584,15 @@ sub generate_preview_button { +onClick="if (typeof(document.mailform.onsubmit)=='function') {document.mailform.onsubmit();};this.form.comment.value=document.mailform.comment.value;this.form.subject.value=document.mailform.subject.value;this.form.submit();" /> 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'}; @@ -2141,11 +2600,12 @@ sub modify_attachments { my $bodytag=&Apache::loncommon::bodytag('Discussion Post Attachments', '',''); my $msg = ''; - my @attachments = (); + my %attachments = (); my %currattach = (); if ($idx) { - &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\@attachments,\%currattach,$currdelold); + &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold); } + &Apache::lonenc::check_encrypt(\$symb); $r->print(< @@ -2162,17 +2622,17 @@ $bodytag
      - Subject:$subject

      + Subject: $subject

      END if ($idx) { if ($attachmenturls) { my @currold = keys %currattach; if (@currold > 0) { $r->print("The following attachments were part of the most recent saved version of this posting.
      Check the checkboxes for any you wish to remove
      \n"); - foreach (@currold) { - my $id = $_; - $attachments[$id] =~ m#/([^/]+)$#; - $r->print(' '.$1.'
      '."\n"); + foreach my $id (@currold) { + my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'}); + $attachurl =~ m#/([^/]+)$#; + $r->print('
      '."\n"); } $r->print("
      "); } @@ -2182,7 +2642,7 @@ END $r->print("The following attachments have been uploaded for inclusion with this posting.
      Check the checkboxes for any you wish to remove
      \n"); foreach (@{$currnewattach}) { $_ =~ m#/([^/]+)$#; - $r->print(' '.$1.'
      '."\n"); + $r->print('
      '."\n"); } $r->print("
      "); } @@ -2269,7 +2729,7 @@ sub generate_attachments_button { my $response = (< Click to add/remove attachments:  0) { - unless (grep/^$attachid$/,@{$currdelold}) { - my $id = $i; - $$currattach{$id} = $1; - } - } else { - my $id = $i; - $$currattach{$id} = $1; - } - } else { - my $id = $i; - $$currattach{$id} = $1; + %{$attachments}=(); + &get_post_attachments($attachments,$attachmenturls); + foreach my $id (sort keys %{$attachments}) { + if (exists($$attachments{$id}{$numoldver})) { + if (defined($currdelold)) { + if (@{$currdelold} > 0) { + unless (grep/^$id$/,@{$currdelold}) { + $$currattach{$id} = $$attachments{$id}{$numoldver}; } + } else { + $$currattach{$id} = $$attachments{$id}{$numoldver}; } + } else { + $$currattach{$id} = $$attachments{$id}{$numoldver}; } } - my @attached = (sort { $a <=> $b } keys %{$currattach}); - if (@attached == 1) { - my $id = $attached[0]; - $$attachments[$attached[0]]=~m|/([^/]+)$|; - $$message.='
      '. - $1.'
      '; + } + my @attached = (sort { $a <=> $b } keys %{$currattach}); + if (@attached == 1) { + my $id = $attached[0]; + my $attachurl; + if ($attachmenturls =~ m/^/) { + $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'}); + } else { + $attachurl = $$attachments{$id}{'filename'}; + } + $attachurl=~m|/([^/]+)$|; + $$message.='
      '. + $1.'
      '; + &Apache::lonnet::allowuploaded('/adm/feedback', + $attachurl); + } elsif (@attached > 1) { + $$message.='
        '; + foreach (@attached) { + my $id = $_; + my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'}); + my ($fname) + =($attachurl=~m|/([^/]+)$|); + $$message .= '
      1. '. + $fname.'
      2. '; &Apache::lonnet::allowuploaded('/adm/feedback', - $$attachments[$id]); - } elsif (@attached > 1) { - $$message.='
          '; - foreach (@attached) { - my $id = $_; - my ($fname) - =($$attachments[$id]=~m|/([^/]+)$|); - $$message .= '
        1. '. - $fname.'
        2. '; - &Apache::lonnet::allowuploaded('/adm/feedback', - $$attachments[$id]); - } - $$message .= '

        '; + $attachurl); } - } else { - my ($fname) - =($attachmenturls=~m|/([^/]+)$|); - $$message .='

        '.&mt('Attachment'). - ': '. - $fname.'

        '; - $$attachments[0] = $attachmenturls; - $$currattach{'0'} = 'n'; - &Apache::lonnet::allowuploaded('/adm/feedback', - $attachmenturls); + $$message .= '
      '; } } @@ -2372,7 +2817,7 @@ sub construct_attachmenturl { my ($currnewattach,$keepold,$symb,$idx)=@_; my $oldattachmenturl; my $newattachmenturl; - my $startnum = 1; + my $startnum = 0; my $currver = 0; if (($ENV{'form.editdisc'}) && ($idx)) { my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, @@ -2390,40 +2835,85 @@ sub construct_attachmenturl { $currver = 1; } if ($oldattachmenturl) { - if ($oldattachmenturl =~ m/::::\d+:[\.yn\d]+::::/) { - my @attachments = split/::::\d+:[\.yn\d]+::::/,$oldattachmenturl; - shift @attachments; - $startnum += @attachments; - my $searchstr = '::::'; - $newattachmenturl = '::::'; - for (my $i=0; $i<@attachments; $i++) { - if ($oldattachmenturl =~ m#^\Q$searchstr\E(\d+)(:[\.yn\d]+)::::#) { - my $attachid = $1 - 1; - $searchstr .= $1.$2.'::::'.$attachments[$i].'::::'; - $newattachmenturl .= $1.$2; - if (grep/^$attachid$/,@{$keepold}) { - $newattachmenturl .= '.'.$currver.'n.'; + if ($oldattachmenturl =~ m/^/) { + my %attachments = (); + my $prevver = $currver-1; + &get_post_attachments(\%attachments,$oldattachmenturl); + my $numattach = scalar(keys %attachments); + $startnum += $numattach; + 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}{$_}.''; } - $newattachmenturl .= '::::'.$attachments[$i].'::::'; } + if (grep/^$num$/,@{$keepold}) { + $newattachmenturl .= ''.$attachments{$num}{$prevver}.''; + } + $newattachmenturl .= ''; } - $newattachmenturl =~ s/::::$//; } else { - $newattachmenturl = '::::1:.0n.'; + $newattachmenturl = ''.&HTML::Entities::encode($oldattachmenturl).'n'; unless (grep/^0$/,@{$keepold}) { - $newattachmenturl .= '.1n.'; + $newattachmenturl .= 'n'; } - $newattachmenturl .= '::::'.$oldattachmenturl; + $newattachmenturl .= ''; $startnum ++; } } } for (my $i=0; $i<@{$currnewattach}; $i++) { my $attachnum = $startnum + $i; - $newattachmenturl .= '::::'.$attachnum.':.'.$currver.'n.::::'.$$currnewattach[$i]; + $newattachmenturl .= ''.&HTML::Entities::encode($$currnewattach[$i]).'n'; } return $newattachmenturl; } + +sub has_discussion { + my $resourcesref = shift; + my $navmap = Apache::lonnavmaps::navmap->new(); + my @allres=$navmap->retrieveResources(); + foreach my $resource (@allres) { + if ($resource->hasDiscussion()) { + my $ressymb; + if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) { + $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard'; + } else { + $ressymb = $resource->symb(); + } + push @{$resourcesref}, $ressymb; + } + } + return; +} + +sub sort_filter_names { + my ($sort_types,$role_types,$status_types) = @_; + %{$sort_types} = ( + ascdate => 'Date order - oldest first', + descdate => 'Date order - newest first', + thread => 'Threaded', + subject => 'By subject', + username => 'By domain and username', + lastfirst => 'By last name, first name' + ); + %{$role_types} = ( + all => 'All roles', + st => 'Students', + cc => 'Course Coordinators', + in => 'Instructors', + ta => 'TAs', + ep => 'Exam proctors', + ad => 'Administrators', + cr => 'Custom roles' + ); + %{$status_types} = ( + all => 'Roles of any status', + Active => 'Only active roles', + Expired => 'Only inactive roles' + ); +} sub handler { my $r = shift; @@ -2436,13 +2926,13 @@ sub handler { # --------------------------- Get query string for limited number of parameters &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','threadedon','threadedoff','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navmaps','navurl','sortfilter','sortposts','applysort','rolefilter','statusfilter','sectionpick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions']); + ['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','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export']); + if ($ENV{'form.discsymb'}) { - my $symb = $ENV{'form.discsymb'}; + my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.discsymb'}); my $readkey = $symb.'_read'; - my %readinghash = (); my $chgcount = 0; - %readinghash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$readkey],$ENV{'user.domain'},$ENV{'user.name'}); + my %readinghash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$readkey],$ENV{'user.domain'},$ENV{'user.name'}); foreach my $key (keys %ENV) { if ($key =~ m/^form\.postunread_(\d+)/) { if ($readinghash{$readkey} =~ /\.$1\./) { @@ -2457,22 +2947,18 @@ sub handler { } } if ($chgcount > 0) { - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%readinghash,$ENV{'user.domain'},$ENV{'user.name'}); + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', + \%readinghash,$ENV{'user.domain'},$ENV{'user.name'}); } - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; - my $feedurl = &Apache::lonnet::clutter($url); - &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'
      ','0','0','',$previous,'','','',); + &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'
      ', + '0','0','',$ENV{'form.previous'},'','','',); return OK; } if ($ENV{'form.allversions'}) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - my $bodytag=&Apache::loncommon::bodytag('Discussion Post Versions', - '',''); - $r->print (<print(< Post Versions @@ -2484,186 +2970,96 @@ END if ($ENV{'request.course.sec'}) { $crs.='_'.$ENV{'request.course.sec'}; } - $crs=~s/\_/\//g; + $crs=~s|_|/|g; my $seeid=&Apache::lonnet::allowed('rin',$crs); my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.allversions'}); - my $ressymb=$symb; - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } + ($symb)=&get_feedurl_and_clean_symb($symb); if ($idx > 0) { - my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - if ($contrib{$idx.':history'}) { - my $attachmenturls = $contrib{$idx.':attachmenturl'}; - my @postversions = (); - my %messages = (); - my %subjects = (); - if ($contrib{$idx.':history'} =~ m/:/) { - @postversions = split/:/,$contrib{$idx.':history'}; - } else { - @postversions = ("$contrib{$idx.':history'}"); - } - if (@postversions > 0) { - &get_post_versions(\%messages,$contrib{$idx.':message'}); - &get_post_versions(\%subjects,$contrib{$idx.':subject'}); - push @postversions,$contrib{$idx.':timestamp'}; - my $screenname=&Apache::loncommon::screenname( - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}); - my $plainname=&Apache::loncommon::nickname( - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}); - my $sender=&Apache::loncommon::aboutmewrapper( - $plainname, - $contrib{$idx.':sendername'}, - $contrib{$idx.':senderdomain'}).' ('. - $contrib{$idx.':sendername'}.' at '. - $contrib{$idx.':senderdomain'}.')'; - if ($contrib{$idx.':anonymous'}) { - $sender.=' ['.&mt('anonymous').'] '.$screenname; - } - $r->print(''.$sender.'
        '); - for (my $i=0; $i<@postversions; $i++) { - my ($timesent,$message,$subject,$attachmsg); - $timesent = &Apache::lonlocal::locallocaltime($postversions[$i]); - $message=&HTML::Entities::decode($messages{$i}); - $subject=&HTML::Entities::decode($subjects{$i}); - $message=~s/\n/\
        /g; - $message=&Apache::lontexconvert::msgtexconverted($message); - $subject=~s/\n/\
        /g; - $subject=&Apache::lontexconvert::msgtexconverted($subject); - if ($attachmenturls) { - my @attachments = (); - my %currattach = (); - &extract_attachments($attachmenturls,$idx,$i,\$attachmsg,\@attachments,\%currattach); - } - if ($attachmsg) { - $attachmsg = '
        Attachments:'.$attachmsg.'
        '; - } else { - $attachmsg = '
        '; - } - $r->print (<$subject, $timesent
        -$message
        -$attachmsg -END - } - $r->print('
      '); - } - } + my %messages = (); + my %subjects = (); + my %attachmsgs = (); + my %allattachments = (); + my %imsfiles = (); + my ($screenname,$plainname); + my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname)); } return OK; } if ($ENV{'form.posterlist'}) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.posterlist'}; - my $sortposts = $ENV{'form.sortposts'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; - my $feedurl = &Apache::lonnet::clutter($url); - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - &print_showposters($r,$symb,$previous,$feedurl,$sortposts); + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'}); + &print_showposters($r,$symb,$ENV{'form.previous'},$feedurl, + $ENV{'form.sortposts'}); return OK; } if ($ENV{'form.userpick'}) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.userpick'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; -# backward compatibility (bulletin boards used to be 'wrapped') - my $ressymb=$symb; - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - my $sort=$ENV{'form.sortposts'}; - my @posters = (); - if (ref($ENV{'form.stuinfo'}) eq 'ARRAY') { - @posters = $ENV{'form.stuinfo'}; - } else { - $posters[0] = $ENV{'form.stuinfo'}; - } + my @posters = &Apache::loncommon::get_env_multiple('form.stuinfo'); + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.userpick'}); my $numpicks = @posters; - if (defined($ENV{'form.userpick'})) { - my %discinfo = (); - $discinfo{$ressymb.'_userpick'} = join('&',@posters); - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - } - my $feedurl = &Apache::lonnet::clutter($url); - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - &redirect_back($r,$feedurl,&mt('Changed sort/filter').'
      ','0','0','',$previous,$sort,'','','',$numpicks); + my %discinfo; + $discinfo{$symb.'_userpick'} = join('&',@posters); + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', + \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + &redirect_back($r,$feedurl,&mt('Changed sort/filter').'
      ','0','0', + '',$ENV{'form.previous'},$ENV{'form.sortposts'},'','','', + $numpicks); return OK; } if ($ENV{'form.applysort'}) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.applysort'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; - my $sort = $ENV{'form.sortposts'}; - my $rolefilter = $ENV{'form.rolefilter'}; - my $statusfilter = $ENV{'form.statusfilter'}; - my $secpick = $ENV{'form.sectionpick'}; - my $feedurl = &Apache::lonnet::clutter($url); - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - &redirect_back($r,$feedurl,&mt('Changed sort/filter').'
      ','0','0','',$previous,$sort,$rolefilter,$statusfilter,$secpick); + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'}); + &redirect_back($r,$feedurl,&mt('Changed sort/filter').'
      ','0','0', + '',$ENV{'form.previous'},$ENV{'form.sortposts'}, + $ENV{'form.rolefilter'},$ENV{'form.statusfilter'}, + $ENV{'form.sectionpick'}); return OK; - } elsif ($ENV{'form.sortfilter'}) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.sortfilter'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; - my $feedurl = &Apache::lonnet::clutter($url); - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - &print_sortfilter_options($r,$symb,$previous,$feedurl); + } elsif ($ENV{'form.cmd'} eq 'sortfilter') { + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'}); + &print_sortfilter_options($r,$symb,$ENV{'form.previous'},$feedurl); return OK; - } elsif ($ENV{'form.navmaps'}) { + } elsif ($ENV{'form.navtime'}) { my %discinfo = (); my @resources = (); - if ($ENV{'form.navmaps'} =~ /:/) { - @resources = split/:/,$ENV{'form.navmaps'}; + if (defined($ENV{'form.navmaps'})) { + if ($ENV{'form.navmaps'} =~ /:/) { + @resources = split/:/,$ENV{'form.navmaps'}; + } else { + @resources = ("$ENV{'form.navmaps'}"); + } } else { - @resources = ("$ENV{'form.navmaps'}"); + &has_discussion(\@resources); } my $numitems = @resources; my $feedurl = '/adm/navmaps'; - if ($ENV{'form.navurl'}) { - $feedurl .= '?'.$ENV{'form.navurl'}; - } + if ($ENV{'form.navurl'}) { $feedurl .= '?'.$ENV{'form.navurl'}; } my %lt = &Apache::lonlocal::texthash( 'mnpa' => 'Marked "New" posts as read in a total of', - 'robb' => 'resources/bulletin boards.' + 'robb' => 'resources/bulletin boards.', + 'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.' ); foreach (@resources) { # backward compatibility (bulletin boards used to be 'wrapped') my $ressymb=$_; + &Apache::lonenc::check_decrypt(\$ressymb); if ($ressymb =~ m/bulletin___\d+___/) { unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper/|; } } my $lastkey = $ressymb.'_lastread'; - $discinfo{$lastkey} = time; + $discinfo{$lastkey} = $ENV{'form.navtime'}; + } + my $textline = "$lt{'mnpa'} $numitems $lt{'robb'}"; + if ($numitems > 0) { + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', + \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + } else { + $textline = "$lt{'twnp'}"; } - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; + my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif'); $r->print (< @@ -2672,307 +3068,244 @@ END - -$lt{'mnpa'} $numitems $lt{'robb'} + +$textline
      +
      Continue ENDREDIR return OK; } elsif ($ENV{'form.modifydisp'}) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.modifydisp'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $previous=$ENV{'form.previous'}; - my ($dispchgA,$dispchgB,$markchg,$toggchg) = split/_/,$ENV{'form.changes'}; - my $feedurl = &Apache::lonnet::clutter($url); - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - &print_display_options($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl); - return OK; - } elsif (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'}) || ($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || $ENV{'form.onlyunmark'} || $ENV{'form.toggoff'} || $ENV{'form.toggon'} ) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $previous=$ENV{'form.previous'}; - my ($map,$ind,$url); - if ( ($ENV{'form.toggoff'}) || ($ENV{'form.toggon'}) ) { -# ------------------------------ Modify setting for read/unread toggle for each post - my $symb=$ENV{'form.toggoff'}?$ENV{'form.toggoff'}:$ENV{'form.toggon'}; - my $ressymb = $symb; - ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - my %discinfo = (); - my $toggkey = $ressymb.'_readtoggle'; - if ($ENV{'form.toggon'}) { - $discinfo{$toggkey} = 1; - } elsif ($ENV{'form.toggoff'}) { - $discinfo{$toggkey} = 0; - } - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - } - if (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'})) { -# ---------------------- Modify setting for identification of 'NEW' posts in this discussion - my $symb=$ENV{'form.markondisp'}?$ENV{'form.markondisp'}:$ENV{'form.markonread'}; - my $ressymb = $symb; - ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - my %discinfo = (); - my $lastkey = $ressymb.'_lastread'; - my $ondispkey = $ressymb.'_markondisp'; - if ($ENV{'form.markondisp'}) { - $discinfo{$lastkey} = time; - $discinfo{$ondispkey} = 1; - } elsif ($ENV{'form.markonread'}) { - if ( $previous > 0 ) { - $discinfo{$lastkey} = $previous; - } - $discinfo{$ondispkey} = 0; - } - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - } - if (($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || ($ENV{'form.onlyunmark'}) ) { -# ----------------------------------------------------------------- Modify display setting for this discussion - my $symb; - if ($ENV{'form.allposts'}) { - $symb = $ENV{'form.allposts'}; - } elsif ($ENV{'form.onlyunread'}) { - $symb = $ENV{'form.onlyunread'}; - } else { - $symb = $ENV{'form.onlyunmark'}; - } - my $ressymb = $symb; - ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; - } - my %discinfo = (); - if ($ENV{'form.allposts'}) { - $discinfo{$ressymb.'_showonlyunread'} = 0; - $discinfo{$ressymb.'_showonlyunmark'} = 0; - } elsif ($ENV{'form.onlyunread'}) { - $discinfo{$ressymb.'_showonlyunread'} = 1; - } else { - $discinfo{$ressymb.'_showonlyunmark'} = 1; - } - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - } - if (($ENV{'form.markonread'}) || ($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || ($ENV{'form.onlyunmark'}) ||($ENV{'form.toggoff'}) || ($ENV{'form.toggon'}) ) { - &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'
      ','0','0','',$previous); - } else { - &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'
      ','0','0'); - } + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.modifydisp'}); + my ($dispchgA,$dispchgB,$markchg,$toggchg) = + split(/_/,$ENV{'form.changes'}); + &print_display_options($r,$symb,$ENV{'form.previous'},$dispchgA, + $dispchgB,$markchg,$toggchg,$feedurl); return OK; - } elsif ($ENV{'form.markread'}) { -# ----------------------------------------------------------------- Mark new posts not NEW - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - my $symb=$ENV{'form.markread'}; - my $ressymb = $symb; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { - $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } elsif ($ENV{'form.markondisp'} || $ENV{'form.markonread'} || + $ENV{'form.allposts'} || $ENV{'form.onlyunread'} || + $ENV{'form.onlyunmark'} || $ENV{'form.toggoff'} || + $ENV{'form.toggon'} || $ENV{'form.markread'}) { + my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'}); + my %discinfo; +# ------------------------ Modify setting for read/unread toggle for each post + if ($ENV{'form.toggoff'}) { $discinfo{$symb.'_readtoggle'}=0; } + if ($ENV{'form.toggon'}) { $discinfo{$symb.'_readtoggle'}=1; } +# --------- Modify setting for identification of 'NEW' posts in this discussion + if ($ENV{'form.markondisp'}) { + $discinfo{$symb.'_lastread'} = time; + $discinfo{$symb.'_markondisp'} = 1; + } + if ($ENV{'form.markonread'}) { + if ( $ENV{'form.previous'} > 0 ) { + $discinfo{$symb.'_lastread'} = $ENV{'form.previous'}; + } + $discinfo{$symb.'_markondisp'} = 0; } - my %discinfo = (); - my $lastkey = $ressymb.'_lastread'; - $discinfo{$lastkey} = time; - &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); - &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed reading status').'
      ','0','0'); +# --------------------------------- Modify display setting for this discussion + if ($ENV{'form.allposts'}) { + $discinfo{$symb.'_showonlyunread'} = 0; + $discinfo{$symb.'_showonlyunmark'} = 0; + } + if ($ENV{'form.onlyunread'}) { $discinfo{$symb.'_showonlyunread'} = 1; } + if ($ENV{'form.onlyunmark'}) { $discinfo{$symb.'_showonlyunmark'} = 1; } +# ----------------------------------------------------- Mark new posts not NEW + if ($ENV{'form.markread'}) { $discinfo{$symb.'_lastread'} = time; } + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', + \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + my $previous=$ENV{'form.previous'}; + if ($ENV{'form.markondisp'}) { $previous=undef; } + &redirect_back($r,$feedurl,&mt('Changed display status').'
      ', + '0','0','',$previous); return OK; } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) { # ----------------------------------------------------------------- Hide/unhide - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; + my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'}; + my ($symb,$idx)=split(/\:\:\:/,$entry); + ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb); - my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'}; - - my ($symb,$idx)=split(/\:\:\:/,$entry); - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + 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 %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + my $currenthidden=$contrib{'hidden'}; + my $currentstudenthidden=$contrib{'studenthidden'}; - - my $currenthidden=$contrib{'hidden'}; - my $currentstudenthidden=$contrib{'studenthidden'}; + 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 $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); - - if ($ENV{'form.hide'}) { - $currenthidden.='.'.$idx.'.'; - unless ($seeid) { - $currentstudenthidden.='.'.$idx.'.'; - } - } else { - $currenthidden=~s/\.$idx\.//g; - } - my %newhash=('hidden' => $currenthidden); - if ( ($ENV{'form.hide'}) && (!$seeid) ) { - $newhash{'studenthidden'} = $currentstudenthidden; - } + if ($ENV{'form.hide'}) { + $currenthidden.='.'.$idx.'.'; + unless ($seeid) { + $currentstudenthidden.='.'.$idx.'.'; + } + } else { + $currenthidden=~s/\.$idx\.//g; + } + my %newhash=('hidden' => $currenthidden); + if ( ($ENV{'form.hide'}) && (!$seeid) ) { + $newhash{'studenthidden'} = $currentstudenthidden; + } - &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'}, - $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'}); - &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed discussion status').'
      ','0','0','',$ENV{'form.previous'}); - } elsif (($ENV{'form.threadedon'}) || ($ENV{'form.threadedoff'})) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - if ($ENV{'form.threadedon'}) { + &redirect_back($r,$feedurl,&mt('Changed discussion status').'
      ', + '0','0','',$ENV{'form.previous'}); + return OK; + } elsif ($ENV{'form.cmd'}=~/^(threadedoff|threadedon)$/) { + 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'); } else { &Apache::lonnet::del('environment',['threadeddiscussion']); &Apache::lonnet::delenv('environment\.threadeddiscussion'); } - my $symb=$ENV{'form.threadedon'}?$ENV{'form.threadedon'}:$ENV{'form.threadedoff'}; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed discussion view mode').'
      ','0','0','',$ENV{'form.previous'}); + &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'
      ', + '0','0','',$ENV{'form.previous'}); + return OK; } elsif ($ENV{'form.deldisc'}) { # --------------------------------------------------------------- Hide for good - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - - my $entry=$ENV{'form.deldisc'}; - - my ($symb,$idx)=split(/\:\:\:/,$entry); - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - - 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 $currentdeleted=$contrib{'deleted'}; - - $currentdeleted.='.'.$idx.'.'; - - my %newhash=('deleted' => $currentdeleted); - - &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - - &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed discussion status').'
      ','0','0','',$ENV{'form.previous'}); + my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.deldisc'}); + ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb); + 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 %newhash=('deleted' => $contrib{'deleted'}.".$idx."); + &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + &redirect_back($r,$feedurl,&mt('Changed discussion status').'
      ', + '0','0','',$ENV{'form.previous'}); + return OK; } elsif ($ENV{'form.preview'}) { # -------------------------------------------------------- User wants a preview - $r->content_type('text/html'); - $r->send_http_header; &show_preview($r); + return OK; } elsif ($ENV{'form.attach'}) { # -------------------------------------------------------- Work on attachments &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','anondiscuss','discuss']); - my @currnewattach = (); - my @currdelold = (); - my @keepold = (); + my (@currnewattach,@currdelold,@keepold); &process_attachments(\@currnewattach,\@currdelold,\@keepold); if (exists($ENV{'form.addnewattach.filename'})) { unless (length($ENV{'form.addnewattach'})>131072) { my $subdir = 'feedback/'.$ENV{'form.timestamp'}; my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir); - push @currnewattach, $newattachment; + push @currnewattach, $newattachment; } } - my $attachmenturls = ''; + my $attachmenturls; + my ($symb) = &get_feedurl_and_clean_symb($ENV{'form.attach'}); my $idx = $ENV{'form.idx'}; - my $symb = $ENV{'form.attach'}; if ($idx) { my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); $attachmenturls = $contrib{$idx.':attachmenturl'}; } - &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,$attachmenturls); - } elsif ($ENV{'form.chgreads'}) { + &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx, + $attachmenturls); + return OK; + } elsif ($ENV{'form.export'}) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ENV{'form.chgreads'}); - &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed read status').'
      ','0','0'); + my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.export'}); + my $mode='board'; + my $status='OPEN'; + my $previous=$ENV{'form.previous'}; + if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library)$/) { + $mode='problem'; + $status=$Apache::inputtags::status[-1]; + } + my $discussion = &list_discussion($mode,$status,$symb); + my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion'); + $r->print($bodytag.$discussion); + return OK; } else { # ------------------------------------------------------------- Normal feedback - my $feedurl=$ENV{'form.postdata'}; - $feedurl=~s/^http\:\/\///; - $feedurl=~s/^$ENV{'SERVER_NAME'}//; - $feedurl=~s/^$ENV{'HTTP_HOST'}//; - $feedurl=~s/\?.+$//; + my $feedurl=$ENV{'form.postdata'}; + $feedurl=~s/^http\:\/\///; + $feedurl=~s/^$ENV{'SERVER_NAME'}//; + $feedurl=~s/^$ENV{'HTTP_HOST'}//; + $feedurl=~s/\?.+$//; - 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 { - $symb=&Apache::lonnet::symbread($feedurl); - } - unless ($symb) { - $symb=$ENV{'form.symb'}; - if ($symb) { + 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); + $feedurl=&Apache::lonnet::clutter($url); + } elsif ($ENV{'form.origpage'}) { + $symb=""; + } else { + $symb=&Apache::lonnet::symbread($feedurl); + } + 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); + my $goahead=1; + if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) { + unless ($symb) { $goahead=0; } + } + # backward compatibility (bulletin boards used to be 'wrapped') + if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { + $feedurl=~s|^/adm/wrapper||; + } + if (!$goahead) { + # Ambiguous Problem Resource + $r->internal_redirect('/adm/ambiguous'); + return OK; } - } - my $goahead=1; - if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) { - unless ($symb) { $goahead=0; } - } - # backward compatibility (bulletin boards used to be 'wrapped') - if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { - $feedurl=~s|^/adm/wrapper||; - } - if ($goahead) { # Go ahead with feedback, no ambiguous reference - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - - if ( - ( - ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:) - ) - || - ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:)) - || - ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/)) - ) { + unless ( + ( + ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:) + ) + || + ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:)) + || + ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/)) + ) { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; +# Unable to give feedback + &no_redirect_back($r,$feedurl); + } # --------------------------------------------------- Print login screen header - unless ($ENV{'form.sendit'}) { - my $options=&screen_header($feedurl); - if ($options) { - &mail_screen($r,$feedurl,$options); - } else { - &fail_redirect($r,$feedurl); + unless ($ENV{'form.sendit'}) { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + my $options=&screen_header($feedurl,$symb); + if ($options) { + &mail_screen($r,$feedurl,$options); + } else { + &fail_redirect($r,$feedurl); + } + return OK; } - } else { # Get previous user input my $prevattempts=&Apache::loncommon::get_previous_attempt( - $symb,$ENV{'user.name'},$ENV{'user.domain'}, - $ENV{'request.course.id'}); + $symb,$ENV{'user.name'},$ENV{'user.domain'}, + $ENV{'request.course.id'}); # Get output from resource my $usersaw=&resource_output($feedurl); @@ -2980,26 +3313,28 @@ ENDREDIR # 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'}); + $symb,$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=''; - if (($ENV{'form.origpage'}) || ($ENV{'form.editdisc'}) || ($ENV{'form.replydisc'})) { - my ($symb,$idx); - if ($ENV{'form.replydisc'}) { - ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'}); - } elsif ($ENV{'form.editdisc'}) { - ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'}); - } elsif ($ENV{'form.origpage'}) { - $symb = $ENV{'form.symb'}; - } - my @currnewattach = (); - my @deloldattach = (); - my @keepold = (); - &process_attachments(\@currnewattach,\@deloldattach,\@keepold); - $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|; - $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx); + if (($ENV{'form.origpage'}) || ($ENV{'form.editdisc'}) || + ($ENV{'form.replydisc'})) { + my ($symb,$idx); + if ($ENV{'form.replydisc'}) { + ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'}); + } elsif ($ENV{'form.editdisc'}) { + ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'}); + } elsif ($ENV{'form.origpage'}) { + $symb = $ENV{'form.symb'}; + } + &Apache::lonenc::check_decrypt(\$symb); + my @currnewattach = (); + my @deloldattach = (); + my @keepold = (); + &process_attachments(\@currnewattach,\@deloldattach,\@keepold); + $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'); @@ -3010,49 +3345,65 @@ ENDREDIR # Assemble email my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts, - $usersaw,$useranswer); + $usersaw,$useranswer); # Who gets this? my ($typestyle,%to) = &decide_receiver($feedurl); # Actually send mail my ($status,$numsent)=&send_msg($feedurl,$email,$citations, - $attachmenturl,%to); + $attachmenturl,%to); # Discussion? Store that. my $numpost=0; - if ($ENV{'form.discuss'}) { - my $subject = &clear_out_html($ENV{'form.subject'}); - $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl,$subject); + if ($ENV{'form.discuss'} || $ENV{'form.anondiscuss'}) { + my $subject = &clear_out_html($ENV{'form.subject'}); + my $anonmode=(defined($ENV{'form.anondiscuss'})); + $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl, + $subject); $numpost++; } - - if ($ENV{'form.anondiscuss'}) { - my $subject = &clear_out_html($ENV{'form.subject'}); - $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl,$subject); - $numpost++; - } - - + # Receipt screen and redirect back to where came from &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'}); - - } - } else { -# Unable to give feedback - &no_redirect_back($r,$feedurl); - } - } else { -# Ambiguous Problem Resource - if ( &Apache::lonnet::mod_perl_version() == 2 ) { - &Apache::lonnet::cleanenv(); - } - $r->internal_redirect('/adm/ambiguous'); } -} return OK; } +sub wrap_symb { + my ($ressymb)=@_; + if ($ressymb =~ /bulletin___\d+___/) { + unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { + $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } + } + return $ressymb; +} +sub dewrapper { + my ($feedurl)=@_; + if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { + $$feedurl=~s|^/adm/wrapper||; + } +} + +sub get_feedurl { + my ($symb)=@_; + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + my $feedurl = &Apache::lonnet::clutter($url); + &dewrapper(\$feedurl); + return $feedurl; +} + +sub get_feedurl_and_clean_symb { + my ($symb)=@_; + &Apache::lonenc::check_decrypt(\$symb); +# backward compatibility (bulletin boards used to be 'wrapped') + unless ($symb =~ m|bulletin___\d+___adm/wrapper|) { + $symb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } + my $feedurl = &get_feedurl($symb); + return ($symb,$feedurl); +} 1; __END__