--- loncom/interface/lonfeedback.pm 2002/08/26 12:47:28 1.29
+++ loncom/interface/lonfeedback.pm 2021/12/31 20:34:24 1.387
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Feedback
#
-# $Id: lonfeedback.pm,v 1.29 2002/08/26 12:47:28 www Exp $
+# $Id: lonfeedback.pm,v 1.387 2021/12/31 20:34:24 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -25,24 +25,7 @@
#
# http://www.lon-capa.org/
#
-# (Internal Server Error Handler
-#
-# (Login Screen
-# 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14,
-# 1/14/00,5/29,5/30,6/1,6/29,7/1,11/9 Gerd Kortemeyer)
-#
-# 3/1/1 Gerd Kortemeyer)
-#
-# 3/1,2/3,2/5,2/6,2/8 Gerd Kortemeyer
-# 2/9 Guy Albertelli
-# 2/10 Gerd Kortemeyer
-# 2/13 Guy Albertelli
-# 7/25 Gerd Kortemeyer
-# 7/26 Guy Albertelli
-# 7/26,8/10,10/1,11/5,11/6,12/27,12/29 Gerd Kortemeyer
-# YEAR=2002
-# 1/1,1/16 Gerd Kortemeyer
-#
+###
package Apache::lonfeedback;
@@ -50,171 +33,2999 @@ use strict;
use Apache::Constants qw(:common);
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 HTML::Tidy::libXML;
+use Apache::lonspeller();
+use Apache::longroup;
+use Archive::Zip qw( :ERROR_CODES );
+use LONCAPA qw(:DEFAULT :match);
+
+sub discussion_open {
+ my ($status,$symb)=@_;
+# Advanced roles can always discuss
+ if ($env{'request.role.adv'}) { return 1; }
+# Get discussion closing date
+ my $close=&Apache::lonnet::EXT('resource.0.discussend',$symb);
+# If it is defined and in the future, the instructor wants this discussion to be open
+ if (defined($close) && $close ne '' && $close > time) {
+ return 1;
+ }
+# It was not explicitly open, check if the problem is available.
+# If the problem is not available, close the discussion
+ if (defined($status) &&
+ !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
+ || $status eq 'OPEN')) {
+ return 0;
+ }
+# The problem is available, but check if the instructor explictly closed discussion
+ if (defined($close) && $close ne '' && $close < time) {
+ return 0;
+ }
+ return 1;
+}
-sub mail_screen {
- my ($r,$feedurl,$options) = @_;
- my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
- '','onLoad="window.focus();"');
- $r->print(<
-
-The LearningOnline Network with CAPA
-
-
+
+END
+
+ my ($textareaheader,$textareaclass);
+ if (&Apache::lonhtmlcommon::htmlareabrowser()) {
+ $textareaheader = &Apache::lonhtmlcommon::htmlareaselectactive();
+ $textareaclass = 'class="LC_richDefaultOff"';
+ if ($env{'request.course.id'}) {
+ unless (($env{'course.'.$env{'request.course.id'}.'.allow_limited_html_in_feedback'} =~ /^\s*yes\s*$/i) || ($env{'form.sendmessageonly'})) {
+ undef($textareaclass);
+ }
+ }
+ }
+
+ # Breadcrumbs
+ my $brcrum = [{'href' => '',
+ 'text' => 'Resource Feedback and Discussion'}];
+
+ my %onload = ('onload' => 'window.focus();setposttype();');
+ my %parms=('add_entries' => \%onload);
+ if ($env{'form.modal'} ne 'yes') { $parms{'bread_crumbs'} = $brcrum; }
+ my $start_page=
+ &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,\%parms);
+
+ if ($quote ne '') {
+ $quote = &HTML::Entities::decode($quote);
+ unless (&contains_block_html($quote)) {
+ &newline_to_br(\$quote);
+ }
+ $quote=&Apache::lonhtmlcommon::start_pick_box().
+ &Apache::lonhtmlcommon::row_title(&mt('Quote')).
+ &Apache::lontexconvert::msgtexconverted($quote).
+ &Apache::lonhtmlcommon::row_closure(1).
+ &Apache::lonhtmlcommon::end_pick_box();
+ }
+ my $header='';
+ unless ($env{'form.modal'}) {
+ $header="$restitle
";
+ }
+ $r->print(<$lt{'myqu'}
+$header
+
+
+$latexHelp
+
+
+END
+
+
+ $r->print(&Apache::lonhtmlcommon::row_title(&mt('Subject')));
+ $r->print('
');
+ $r->print(&Apache::lonhtmlcommon::row_closure());
+ $r->print(&Apache::lonhtmlcommon::row_title(&mt('Message')));
+ $r->print('');
+ $r->print(&Apache::lonhtmlcommon::row_closure(1));
+ $r->print(&Apache::lonhtmlcommon::end_pick_box());
+
+ if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {
+ if ($env{'form.origpage'}) {
+ foreach my $attach (@currnewattach) {
+ $r->print(''."\n");
+ }
+ foreach my $oldatt (@currdelold) {
+ $r->print(''."\n");
+ }
+ }
+ if ($env{'form.editdisc'}) {
+ if ($attachmenturls) {
+ &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);
+ $attachnum = scalar(keys(%currattach));
+ foreach my $key (keys(%currattach)) {
+ $r->print(''."\n");
+ }
+ }
+ }
+ } else {
+ $r->print(<
+$lt{'atta'} $attachmaxtext:
+
+
+END
+ }
+ if (exists($env{'form.group'})) {
+ $r->print('');
+ }
+ if (exists($env{'form.ref'})) {
+ $r->print('');
+ }
+ $r->print(<
+
+
+END
+ if ($env{'form.editdisc'} || $env{'form.replydisc'}) {
+ my $now = time;
+ my $ressymb = $symb;
+ &Apache::lonenc::check_encrypt(\$ressymb);
+ my $postidx = '';
+ if ($env{'form.editdisc'}) {
+ $postidx = $idx;
+ }
+ if (@currnewattach > 0) {
+ $attachnum += @currnewattach;
+ }
+ my $blockblog = &Apache::loncommon::blocking_status('blogs');
+ if ($attachnum > 0) {
+ if (@currnewattach > 0) {
+ $newattachmsg .= '
'.&mt('New attachments').'
';
+ if (@currnewattach > 1) {
+ $newattachmsg .= '';
+ foreach my $item (@currnewattach) {
+ $item =~ m#.*/([^/]+)$#;
+ $newattachmsg .= '- '.$1.'
'."\n";
+ }
+ $newattachmsg .= '
'."\n";
+ } else {
+ $currnewattach[0] =~ m#.*/([^/]+)$#;
+ $newattachmsg .= ''.$1.'
'."\n";
+ }
+ }
+ if ($attachmsg) {
+ $r->print("
$lt{'reta'}:$attachmsg
\n");
+ }
+ if ($newattachmsg) {
+ $r->print("$newattachmsg");
+ }
+ }
+ $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver,'',$blockblog));
+ }
+ $r->print(&generate_preview_button().
+ &Apache::loncommon::end_page());
+
+}
+
+sub print_display_options {
+ my ($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl) = @_;
+ &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',
+ $env{'user.domain'});
+
+ my %lt = &Apache::lonlocal::texthash(
+ 'pref' => 'Display Preference',
+ 'curr' => 'Current setting ',
+ 'actn' => 'Action',
+ 'deff' => 'Default for all discussions',
+ 'prca' => 'Preferences can be set for this discussion that determine ....',
+ 'whpo' => 'Which posts are displayed when you display this discussion board or resource, and',
+ 'unwh' => 'Under what circumstances posts are identified as "NEW", and',
+ 'wipa' => 'Whether individual posts can be marked as read/unread',
+ 'allposts' => 'All posts',
+ 'unread' => 'New posts only',
+ 'unmark' => 'Posts not marked read',
+ 'ondisp' => 'Once displayed',
+ 'onmark' => 'Once marked not NEW',
+ 'toggon' => 'Shown',
+ 'toggoff' => 'Not shown',
+ 'disa' => 'Posts displayed?',
+ 'npmr' => 'New posts cease to be identified as "NEW"?',
+ 'dotm' => 'Option to mark each post as read/unread?',
+ 'chgt' => 'Change to ',
+ 'mkdf' => 'Set to ',
+ 'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
+ 'ywbr' => 'You will be returned to the previous page if you click OK.'
+ );
+ my %js_lt = &Apache::lonlocal::texthash(
+ 'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
+ 'ywbr' => 'You will be returned to the previous page if you click OK.'
+ );
+ &js_escape(\%js_lt);
+
+ my $dispchangeA = $lt{'unread'};
+ my $dispchangeB = $lt{'unmark'};
+ my $markchange = $lt{'ondisp'};
+ my $toggchange = $lt{'toggon'};
+ my $currdisp = $lt{'allposts'};
+ my $currmark = $lt{'onmark'};
+ my $discdisp = 'allposts';
+ my $discmark = 'onmark';
+ my $currtogg = $lt{'toggoff'};
+ my $disctogg = 'toggoff';
+
+ if ($dispchgA eq 'allposts') {
+ $dispchangeA = $lt{'allposts'};
+ $currdisp = $lt{'unread'};
+ $discdisp = 'unread';
+ }
+
+ if ($markchg eq 'markonread') {
+ $markchange = $lt{'onmark'};
+ $currmark = $lt{'ondisp'};
+ $discmark = 'ondisp';
+ }
+
+ if ($dispchgB eq 'onlyunread') {
+ $dispchangeB = $lt{'unread'};
+ $currdisp = $lt{'unmark'};
+ $discdisp = 'unmark';
+ }
+ if ($toggchg eq 'toggoff') {
+ $toggchange = $lt{'toggoff'};
+ $currtogg = $lt{'toggon'};
+ $disctogg = 'toggon';
+ }
+
+ my $js = <
+function discdispChk(caller) {
+ var disctogg = '$toggchg'
+ if (caller == 0) {
+ if (document.modifydisp.discdisp[0].checked == true) {
+ if (document.modifydisp.discdisp[1].checked == true) {
+ document.modifydisp.discdisp[1].checked = false
+ }
+ }
+ }
+ if (caller == 1) {
+ if (document.modifydisp.discdisp[1].checked == true) {
+ if (document.modifydisp.discdisp[0].checked == true) {
+ document.modifydisp.discdisp[0].checked = false
+ }
+ if (disctogg == 'toggon') {
+ document.modifydisp.disctogg.checked = true
+ }
+ if (disctogg == 'toggoff') {
+ document.modifydisp.disctogg.checked = false
+ }
+ }
+ }
+ if (caller == 2) {
+ var dispchgB = '$dispchgB'
+ if (disctogg == 'toggoff') {
+ if (document.modifydisp.disctogg.checked == true) {
+ if (dispchgB == 'onlyunmark') {
+ document.modifydisp.discdisp[1].checked = false
+ }
+ }
+ }
+ }
+}
+
+function setDisp() {
+ var prev = "$previous"
+ var chktotal = 0
+ if (document.modifydisp.discdisp[0].checked == true) {
+ document.modifydisp.$dispchgA.value = "$symb"
+ chktotal ++
+ }
+ if (document.modifydisp.discdisp[1].checked == true) {
+ document.modifydisp.$dispchgB.value = "$symb"
+ chktotal ++
+ }
+ if (document.modifydisp.discmark.checked == true) {
+ document.modifydisp.$markchg.value = "$symb"
+ chktotal ++
+ }
+ if (document.modifydisp.disctogg.checked == true) {
+ document.modifydisp.$toggchg.value = "$symb"
+ chktotal ++
+ }
+ if (chktotal > 0) {
+ document.modifydisp.submit()
+ } else {
+ if(confirm("$js_lt{'yhni'}. \\n$js_lt{'ywbr'}")) {
+ if (prev > 0) {
+ location.href = "$feedurl?previous=$previous"
+ } else {
+ location.href = "$feedurl"
+ }
+ }
+ }
+}
+
+END
+
+
+ my $start_page =
+ &Apache::loncommon::start_page('Discussion display options',$js);
+ my $end_page =
+ &Apache::loncommon::end_page();
+ $r->print(<
+$lt{'sdpf'}
$lt{'prca'} - $lt{'whpo'}
- $lt{'unwh'}
- $lt{'wipa'}
+
+END
+ $r->print(&Apache::loncommon::start_data_table());
+ $r->print(<
+ $lt{'pref'}
+ | $lt{'curr'}
+ | $lt{'actn'}?
+
+END
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print(<$lt{'disa'}
+ $lt{$discdisp} |
+
+
+
+ |
+END
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print(<$lt{'npmr'}
+ $lt{$discmark} |
+ |
+END
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print(<$lt{'dotm'}
+ $lt{$disctogg} |
+ |
+END
+ my $save = &mt('Save');
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::end_data_table());
+ $r->print(<
+
+
+
+
+
+
+
+
+END
+ if (exists($env{'form.group'})) {
+ $r->print('');
+ }
+ if (exists($env{'form.ref'})) {
+ $r->print('');
+ }
+ $r->print("
+
+
+
+$end_page
+ ");
+ return;
+}
+
+sub print_sortfilter_options {
+ my ($r,$symb,$previous,$feedurl) = @_;
+
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->send_http_header;
+
+ &Apache::lonenc::check_encrypt(\$symb);
+ my @sections;
+ my $section_sel = '';
+ my $numvisible = 5;
+ my @groups;
+ my $group_sel = '';
+ my $numgroupvis = 5;
+ my %sectioncount = &Apache::loncommon::get_sections();
+ my @courseroles = qw(st ad ep ta in);
+ my $crstype = &Apache::loncommon::course_type();
+ my $ccrole = 'cc';
+ if ($crstype eq 'Community') {
+ $ccrole = 'co';
+ }
+ push(@courseroles,$ccrole);
+
+ 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);
+ if (scalar(@sections) < 4) {
+ $numvisible = scalar(@sections) + 1;
+ }
+ unshift(@sections,'all'); # Put 'all' at the front of the list
+
+ }
+ foreach my $sec (@sections) {
+ $section_sel .= " \n";
+ }
+
+ if (&check_group_priv() eq 'ok') {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
+ @groups = sort {$a cmp $b} keys(%curr_groups);
+ if (scalar(@groups) < 4) {
+ $numgroupvis = scalar(@groups) + 1;
+ }
+ unshift(@groups,'all'); # Put 'all' at the front of the list
+ } else {
+ my @coursegroups = split(/:/,$env{'request.course.groups'});
+ if (@coursegroups > 0) {
+ @coursegroups = sort {$a cmp $b} @coursegroups;
+ @groups = ('all',@coursegroups);
+ if (scalar(@groups) < 4) {
+ $numgroupvis = scalar(@groups) + 1;
+ }
+ } else {
+ @groups = ('all');
+ $numgroupvis = 1;
+ }
+ }
+ foreach my $group (@groups) {
+ $group_sel .= " \n";
+ }
+
+ my $function = &Apache::loncommon::get_users_function();
+ my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
+ $env{'user.domain'});
+ my %lt = &Apache::lonlocal::texthash(
+ 'diop' => 'Display Options',
+ 'curr' => 'Current setting ',
+ 'actn' => 'Action',
+ 'prca' => 'Set options that control the sort order of posts, and/or which posts are displayed.',
+ 'soor' => 'Sort order',
+ 'spur' => 'Specific user roles',
+ 'sprs' => 'Specific role status',
+ 'spse' => 'Specific sections',
+ 'spgr' => 'Specific groups',
+ 'psub' => 'Pick specific users (by name)',
+ 'shal' => 'Show a list of current posters',
+ 'stor' => 'Save changes',
+ );
+
+ my %sort_types = ();
+ my %role_types = ();
+ my %status_types = ();
+ &sort_filter_names(\%sort_types,\%role_types,\%status_types,$crstype);
+
+ my $js = <
+function verifyFilter() {
+ var rolenum = 0
+ for (var i=0; i
-
-$bodytag
-$feedurl
-
+$end_page
+");
+}
+
+sub print_showposters {
+ my ($r,$symb,$previous,$feedurl,$sortposts) = @_;
+
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->send_http_header;
+
+ &Apache::lonenc::check_encrypt(\$symb);
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $group = $env{'form.group'};
+ my $ressymb = &wrap_symb($symb);
+ my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
+ my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+ $cdom,$cnum);
+ my %namesort = ();
+ my %postcounts = ();
+
+ my %lt = &Apache::lonlocal::texthash(
+ sele => 'Select',
+ full => 'Fullname',
+ usdo => 'Username:domain',
+ post => 'Posts',
+ );
+ if ($contrib{'version'}) {
+ for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
+ my $hidden=($contrib{'hidden'}=~/\.$idx\./);
+ my $deleted=($contrib{'deleted'}=~/\.$idx\./);
+ unless ((($hidden) && (!$seehidden)) || ($deleted)) {
+ if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
+ 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}} = ();
+ }
+ my $poster = $contrib{$idx.':sendername'}.':'.$contrib{$idx.':senderdomain'};
+ $postcounts{$poster} ++;
+ if (defined($namesort{$lastname}{$firstname})) {
+ if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) {
+ push(@{$namesort{$lastname}{$firstname}}, $poster);
+ }
+ } else {
+ @{$namesort{$lastname}{$firstname}} = ("$poster");
+ }
+ }
+ }
+ }
+ }
+
+ my $start_page = &Apache::loncommon::start_page('Discussion options');
+ my $table_start =&Apache::loncommon::start_data_table();
+ $r->print(<
+
+ $table_start
+
+ # |
+ $lt{'sele'} |
+ $lt{'full'} ($lt{'usdo'}) |
+ $lt{'post'} |
+
+END
+ my $count = 0;
+ foreach my $last (sort(keys(%namesort))) {
+ foreach my $first (sort(keys(%{$namesort{$last}}))) {
+ foreach my $user (sort(@{$namesort{$last}{$first}})) {
+ my ($uname,$udom) = split(/:/,$user);
+ if (!$uname || !$udom) {
+ next;
+ } else {
+ $count ++;
+ $r->print(&Apache::loncommon::start_data_table_row().
+ ''.$count.' |
+ |
+ '.$last.', '.$first.' ('.$uname.':'.$udom.') |
+ '.$postcounts{$user}.' | '.
+ &Apache::loncommon::end_data_table_row());
+ }
+ }
+ }
+ }
+ $r->print(&Apache::loncommon::end_data_table());
+ my $end_page = &Apache::loncommon::end_page();
+ $r->print(<
+
+
+
+
- |