--- loncom/interface/lonfeedback.pm 2004/08/03 21:29:32 1.112 +++ loncom/interface/lonfeedback.pm 2007/10/26 20:51:43 1.251 @@ -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.251 2007/10/26 20:51:43 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -35,18 +35,26 @@ use Apache::lonmsg(); use Apache::loncommon(); use Apache::lontexconvert(); use Apache::lonlocal; # must not have () +use Apache::lonnet; use Apache::lonhtmlcommon(); +use Apache::lonnavmaps; +use Apache::lonenc(); +use Apache::lonrss(); use HTML::LCParser(); use Apache::lonspeller(); +use Apache::longroup; +use Cwd; +use LONCAPA; sub discussion_open { - my ($status)=@_; + my ($status,$symb)=@_; + if ($env{'request.role.adv'}) { return 1; } 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,40 +66,67 @@ 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 $outputtarget=$ENV{'form.grade_target'}; - if (not &discussion_visible($status)) { return ''; } + my ($mode,$status,$ressymb,$imsextras,$group)=@_; + unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); } + unless ($ressymb) { return ''; } + $ressymb=&wrap_symb($ressymb); + my $outputtarget=$env{'form.grade_target'}; + if (defined($env{'form.export'})) { + if($env{'form.export'}) { + $outputtarget = 'export'; + } + } + if (defined($imsextras)) { + if ($$imsextras{'caller'} eq 'imsexport') { + $outputtarget = 'export'; + } + } + if (not &discussion_visible($status)) { + if ($mode ne 'board') { + &Apache::lonenc::check_encrypt(\$ressymb); + return '
'.&send_message_link($ressymb); + } + } + if ($group ne '' && $mode eq 'board') { + if (&check_group_priv($group,'vgb') ne 'ok') { + return ''; + } + } + + my ($blocked,$blocktext) = + &Apache::loncommon::blocking_status('boards'); + if ($blocked) { + &Apache::lonenc::check_encrypt(\$ressymb); + if ($mode ne 'board') { + $blocktext.='
'.&send_message_link($ressymb); + } + return $blocktext; + } + my @bgcols = ("#cccccc","#eeeeee"); my $discussiononly=0; if ($mode eq 'board') { $discussiononly=1; } - unless ($ENV{'request.course.id'}) { return ''; } - my $crs='/'.$ENV{'request.course.id'}; - 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 ($env{'request.course.id'}) { return ''; } + my $crs='/'.$env{'request.course.id'}; + my $cid=$env{'request.course.id'}; + if ($env{'request.course.sec'}) { + $crs.='_'.$env{'request.course.sec'}; } - unless ($symb) { return ''; } + $crs=~s/\_/\//g; + my $encsymb=&Apache::lonenc::check_encrypt($ressymb); + my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs) + && ($ressymb=~/\.(problem|exam|quiz|assess|survey|form|task)$/)); + 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,8 +137,8 @@ sub list_discussion { my $userpickkey = $ressymb.'_userpick'; my $toggkey = $ressymb.'_readtoggle'; my $readkey = $ressymb.'_read'; - - 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'}); + $ressymb=$encsymb; + my %dischash = &Apache::lonnet::get('nohist_'.$cid.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$env{'user.domain'},$env{'user.name'}); my %discinfo = (); my $showonlyunread = 0; my $showunmark = 0; @@ -112,16 +147,18 @@ sub list_discussion { my $previous = 0; my $visit = 0; my $newpostsflag = 0; - my @posters = split/\&/,$dischash{$userpickkey}; + my @posters = split(/\&/,$dischash{$userpickkey}); # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts. - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','totposters']); - my $sortposts = $ENV{'form.sortposts'}; - my $rolefilter = $ENV{'form.rolefilter'}; - my $statusfilter = $ENV{'form.statusfilter'}; - my $sectionpick = $ENV{'form.sectionpick'}; - my $totposters = $ENV{'form.totposters'}; - $previous = $ENV{'form.previous'}; + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']); + my $sortposts = $env{'form.sortposts'}; + my $statusfilter = $env{'form.statusfilter'}; + my @sectionpick = split(/,/,$env{'form.sectionpick'}); + my @grouppick = split(/,/,$env{'form.grouppick'}); + my @rolefilter = split(/,/,$env{'form.rolefilter'}); + + my $totposters = $env{'form.totposters'}; + $previous = $env{'form.previous'}; if ($previous > 0) { $prevread = $previous; } elsif (defined($dischash{$lastkey})) { @@ -130,439 +167,128 @@ sub list_discussion { } } + my $cdom = $env{'course.'.$cid.'.domain'}; + my $cnum = $env{'course.'.$cid.'.num'}; + # Get information about students and non-students in course for filtering display of posts my %roleshash = (); my %roleinfo = (); - if ($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/:/,$_; - my ($end,$start) = split/:/,$roleshash{$_}; + my ($classgroups,$studentgroups); + if ($env{'form.rolefilter'}) { + %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); + foreach my $rolekey (keys(%roleshash)) { + my ($role,$uname,$udom,$sec) = split(/:/,$rolekey); + if ($role =~ /^cr/) { + $role = 'cr'; + } + my ($end,$start) = split(/:/,$roleshash{$rolekey}); 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'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + my ($classlist,$keylist) = + &Apache::loncoursedata::get_classlist($cdom,$cnum); my $sec_index = &Apache::loncoursedata::CL_SECTION(); my $status_index = &Apache::loncoursedata::CL_STATUS(); while (my ($student,$data) = each %$classlist) { my ($section,$status) = ($data->[$sec_index], $data->[$status_index]); - push @{$roleinfo{$student}}, 'st:'.$section.':'.$status; + push(@{$roleinfo{$student}}, 'st:'.$section.':'.$status); } + ($classgroups,$studentgroups) = + &Apache::loncoursedata::get_group_memberships($classlist,$keylist, + $cdom,$cnum); } # 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 $seeid; + if (($group ne '') && ($mode eq 'board') && + ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) { + if (&check_group_priv($group,'dgp') eq 'ok') { + $seeid = 1; + } + } else { + $seeid=&Apache::lonnet::allowed('rin',$crs); + } 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; - + my %anonhash=(); + my $anoncnt=0; my $target=''; - unless ($ENV{'browser.interface'} eq 'textual' || - $ENV{'environment.remote'} eq 'off' ) { + unless ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $target='target="LONcom"'; } my $now = time; $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]).' '; - } - } - } - } - } - } - } + &Apache::lonnet::put('nohist_'.$cid.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'}); + &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group); 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', - $ENV{'user.domain'}); + $env{'user.domain'}); my %lt = &Apache::lonlocal::texthash( 'cuse' => 'Current discussion settings', 'allposts' => 'All posts', @@ -579,6 +305,13 @@ sub list_discussion { 'disp' => 'Display', 'nolo' => 'Not new', 'togg' => 'Toggle read/unread', + 'aner' => 'An error occurred opening the manifest file.', + 'difo' => 'Discussion for', + 'aerr' => 'An error occurred opening the export file for posting', + 'aysu' => 'Are you sure you want to delete this post?', + 'dpwn' => 'Deleted posts will no longer be visible to you and other students', + 'bwco' => 'but will continue to be visible to your instructor', + 'depo' => 'Deleted posts will no longer be visible to you or anyone else.', ); my $currdisp = $lt{'allposts'}; @@ -624,157 +357,203 @@ sub list_discussion { if ($newpostsflag) { $chglink .= '&previous='.$prevread; } + $chglink.=&group_args($group); if ($visible) { # Print the discusssion - if ($outputtarget ne 'tex') { + if ($outputtarget eq 'tex') { + $discussion.='{\tiny \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| + + + + + $lt{'difo'} $ressymb\n|; + } else { + $discussion .= $lt{'aner'}.'
'; + } + } else { my $colspan=$maxdepth+1; $discussion.= qq| |; - $discussion.='
'; - $discussion .='
'. - ''; - if ($visible>2) { - $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 my @showposts = (); if ($sortposts eq 'descdate') { - @showposts = (sort { $b <=> $a } keys %alldiscussion); + @showposts = (sort { $b <=> $a } keys(%alldiscussion)); } elsif ($sortposts eq 'thread') { - @showposts = (sort { $a <=> $b } keys %alldiscussion); + @showposts = (sort { $a <=> $b } keys(%alldiscussion)); } elsif ($sortposts eq 'subject') { - foreach (sort keys %subjectsort) { - push @showposts, @{$subjectsort{$_}}; + foreach my $key (sort(keys(%subjectsort))) { + push(@showposts, @{$subjectsort{$key}}); } } elsif ($sortposts eq 'username') { - foreach my $domain (sort keys %usernamesort) { - foreach (sort keys %{$usernamesort{$domain}}) { - push @showposts, @{$usernamesort{$domain}{$_}}; + foreach my $domain (sort(keys(%usernamesort))) { + foreach my $key (sort(keys(%{$usernamesort{$domain}}))) { + push(@showposts, @{$usernamesort{$domain}{$key}}); } } } elsif ($sortposts eq 'lastfirst') { - foreach my $last (sort keys %namesort) { - foreach (sort keys %{$namesort{$last}}) { - push @showposts, @{$namesort{$last}{$_}}; + foreach my $last (sort(keys(%namesort))) { + foreach my $key (sort(keys(%{$namesort{$last}}))) { + push(@showposts, @{$namesort{$last}{$key}}); } } } else { - $sortposts = 'ascdate'; - @showposts = (sort { $a <=> $b } keys %alldiscussion); + @showposts = (sort { $a <=> $b } keys(%alldiscussion)); } - foreach (@showposts) { - unless (($sortposts eq 'thread') || ($sortposts eq 'ascdate' && $ENV{'environment.threadeddiscussion'})) { - $alldiscussion{$_} = $_; + my $currdepth = 0; + my $firstidx = $alldiscussion{$showposts[0]}; + foreach my $post (@showposts) { + unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) { + $alldiscussion{$post} = $post; } - unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) { - if ($outputtarget ne 'tex') { + unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) { + 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') { + my $thisdepth=$depth[$alldiscussion{$post}]; + 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/]*)>/
'. - ''.&mt('Threaded View').'  '. - ''.&mt('Chronological View').'   - '; + $discussion .= &action_links_bar($colspan,$ressymb,$visible, + $newpostsflag,$group, + $prevread,$markondisp); + my $escsymb=&escape($ressymb); + my $numhidden = keys(%notshown); + if ($numhidden > 0) { + my $colspan = $maxdepth+1; + $discussion.="\n".''; - if ($newpostsflag) { - if (!$markondisp) { - $discussion .=''; - } - } else { - $discussion .= ''; - } - $discussion .= '
'. + ''.&mt('Sorting/Filtering options').'  '; - } else { - $discussion .= ''; - } - $discussion .=''.&mt('Export').'?  '.&mt('Mark NEW posts no longer new').'  '; - } else { - $discussion .= '  
'. - ''.&mt('Show all posts').' '.&mt('to display').' '. + $discussion .= &group_args($group); + $discussion .= '">'.&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/]*)>]*)>/ END + if ($sortposts) { + my %sort_types = (); + my %role_types = (); + my %status_types = (); + &sort_filter_names(\%sort_types,\%role_types,\%status_types); + + $discussion .= ''; + } + } if ($dischash{$toggkey}) { - my $storebutton = &mt('Store read/unread changes'); + my $storebutton = &mt('Save read/unread changes'); $discussion.=' -
/; + $discussionitems[$alldiscussion{$post}]=~s/]*)>//; + $discussionitems[$alldiscussion{$post}]=~s/]*)>]*)>/'; + } } } - if ($outputtarget ne 'tex') { + unless ($outputtarget eq 'tex' || $outputtarget eq 'export') { my $colspan=$maxdepth+1; $discussion .= < @@ -806,15 +585,59 @@ END $discussion .= < -
/; my $threadinsert=''; if ($thisdepth > 0) { $threadinsert='
Reply: '.$thisdepth.''; } - $discussionitems[$alldiscussion{$_}]=~s/<\/td>]*)>/$threadinsert<\/td>
/; - $discussionitems[$alldiscussion{$_}]=~s/]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g; - $discussionitems[$alldiscussion{$_}]=~s/(|<\/b>|<\/a>|]+)>)//g; - - #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{$post}]=~s/<\/td>]*)>/$threadinsert<\/td>/; + $discussionitems[$alldiscussion{$post}]=~s/]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g; + $discussionitems[$alldiscussion{$post}]=~s/(|<\/b>|<\/a>|]+)>)//g; + + $discussionitems[$alldiscussion{$post}]='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.$discussionitems[$alldiscussion{$post}]; + $discussion.=$discussionitems[$alldiscussion{$post}]; + } elsif ($outputtarget eq 'export') { + my $postfilename = $alldiscussion{$post}.'-'.$imsitems{$alldiscussion{$post}}{'timestamp'}.'.html'; + if ($manifestok) { + if (($depth[$alldiscussion{$post}] <= $currdepth) && ($alldiscussion{$post} != $firstidx)) { + print $manifestfile ' '."\n"; + } + $currdepth = $depth[$alldiscussion{$post}]; + print $manifestfile "\n". + ''. + ''.$imsitems{$alldiscussion{$post}}{'title'}.''; + $imsresources .= "\n". + ''."\n". + ''."\n". + $imsfiles{$alldiscussion{$post}}{$imsitems{$alldiscussion{$post}}{'currversion'}}."\n". + ''; + } + my $postingfile; + my $postingfilename = $tempexport.'/'.$postfilename; + if ($postingfile = Apache::File->new('>'.$postingfilename)) { + print $postingfile 'Discussion Post'. + $imsitems{$alldiscussion{$post}}{'title'}.' '. + $imsitems{$alldiscussion{$post}}{'sender'}. + $imsitems{$alldiscussion{$post}}{'timestamp'}.'

'. + $imsitems{$alldiscussion{$post}}{'message'}.'
'. + $imsitems{$alldiscussion{$post}}{'attach'}.''."\n"; + close($postingfile); + } else { + $discussion .= $lt{'aerr'}.' '.$alldiscussion{$post}.'
'; + } + $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$post}}{'allattachments'},$tempexport); + } else { + $discussion.='
'. $discussionitems[$alldiscussion{$post}]. + '
  + $lt{'chgt'}?
'.&mt('Sorted by').': '.$sort_types{$sortposts}.'
'; + if (defined($env{'form.totposters'})) { + $discussion .= &mt('Posts by').':'; + if ($totposters > 0) { + foreach my $poster (@posters) { + $discussion .= ' '.$poster.','; + } + $discussion =~ s/,$//; + } else { + $discussion .= &mt('None selected'); + } + } else { + my $filterchoice =''; + if (@sectionpick > 0) { + $filterchoice = ''.&mt('sections').'- '.$env{'form.sectionpick'}; + $filterchoice .= '    '; + } + if (@grouppick > 0) { + $filterchoice = ''.&mt('groups').'- '.$env{'form.grouppick'}; + $filterchoice .= '    '; + } + if (@rolefilter > 0) { + $filterchoice .= ''.&mt('roles').'-'; + foreach my $role (@rolefilter) { + $filterchoice .= ' '.$role_types{$role}.','; + } + $filterchoice =~ s/,$//; + $filterchoice .= '
        '; + } + if ($statusfilter) { + $filterchoice .= ''.&mt('status').'- '.$status_types{$statusfilter}; + } + if ($filterchoice) { + $discussion .= ''.&mt('Filters').': '.$filterchoice; + } + $discussion .= '
'. ''."\n". '
-

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

\n"; + } + 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'; + my $cwd = &getcwd(); + my $imszip = '/home/httpd/'.$imszipfile; + chdir $tempexport; + open(OUTPUT, "zip -r $imszip * 2> /dev/null |"); + close(OUTPUT); + chdir $cwd; + $discussion .= &mt('Download the zip file from [_1]Discussion Posting Archive','').'
'; + if ($copyresult) { + $discussion .= &mt('The following errors occurred during export').' -
'.$copyresult; + } + } + } else { + $discussion .= '
'.&mt('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; my $attachnum = 0; - my $newattachmsg = ''; - my @currnewattach = (); - my @currdelold = (); + my $currnewattach = []; + my $currdelold = []; my $comment = ''; my $subject = ''; - if ($ENV{'form.origpage'}) { + 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 = &unescape($env{'form.subject'}); + $comment = &unescape($env{'form.comment'}); my @keepold = (); - &process_attachments(\@currnewattach,\@currdelold,\@keepold); - if (@currnewattach > 0) { - $attachnum += @currnewattach; + &process_attachments($currnewattach,$currdelold,\@keepold); + if (@{$currnewattach} > 0) { + $attachnum += @{$currnewattach}; + } + } + if (&discussion_open($status)) { + if (($group ne '') && ($mode eq 'board')) { + if (&check_group_priv($group,'pgd') eq 'ok') { + $discussion .= + &postingform_display($mode,$ressymb,$now,$subject, + $comment,$outputtarget,$attachnum, + $currnewattach,$currdelold, + $group); + } + } else { + $discussion.= + &postingform_display($mode,$ressymb,$now,$subject, + $comment,$outputtarget,$attachnum, + $currnewattach,$currdelold); } + } + } else { + $discussion.='