1: package Apache::lonwhatsnew;
2:
3: use strict;
4: use lib qw(/home/httpd/lib/perl);
5: use Apache::lonnet;
6: use Apache::loncommon;
7: use Apache::lonhtmlcommon;
8: use Apache::lonlocal;
9: use Apache::loncoursedata;
10: use Apache::lonnavmaps;
11: use Apache::Constants qw(:common :http);
12: use Time::Local;
13:
14: #----------------------------
15: # handler
16: #
17: #----------------------------
18:
19: sub handler {
20: my $r = shift;
21: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['command']);
22:
23: my $command = $ENV{'form.command'};
24:
25: if ($command eq '') {
26: $command = "info";
27: }
28:
29: $r->print(&display_header());
30: if (! (($ENV{'request.course.fn'}) && (&Apache::lonnet::allowed('vsa',$ENV{'request.course.id'})))) {
31: # Not in a course, or not allowed to modify parms
32: $ENV{'user.error.msg'}="/adm/whatsnew:vsa:0:0:Cannot display student activity";
33: return HTTP_NOT_ACCEPTABLE;
34: }
35:
36: &display_main_box($r,$command);
37: }
38:
39: #------------------------------
40: # display_main_box
41: #
42: # Display all the elements within the main box
43: #------------------------------
44:
45: sub display_main_box {
46: my ($r,$command) = @_;
47: my $domain=&Apache::loncommon::determinedomain();
48: my $tabbg=&Apache::loncommon::designparm('coordinator.tabbg',$domain);
49: $r->print(<<END_OF_BLOCK);
50: <br />
51: <br />
52: <table width="100%" border="0" cellpadding="0" cellspacing="0">
53: <tr>
54: <td width="100%" bgcolor="#000000">
55: <table width="100%" border="0" cellpadding="1" cellspacing="0">
56: <tr>
57: <td width="100%" bgcolor="#000000">
58: <table width="100%" border="0" cellpadding="0" cellspacing="1" bgcolor="#ffffff">
59: <tr>
60: <td colspan="2" width="100%" bgcolor="$tabbg">
61: <table width="100%" border="0" cellpadding="5" cellspacing="0">
62: <tr>
63: <td width="100%">
64: <table width="100%" border="0" cellpadding="0" cellspacing="0">
65: <tr>
66: <td>
67: <font face="arial,verdana" size="3"><b>Course Action Items</b></font></td>
68: </td>
69: <td align="right">
70: </td>
71: </tr>
72: </table>
73: </td>
74: </tr>
75: </table>
76: </td>
77: </tr>
78: <tr>
79: <td width="100" valign="top" bgcolor="#dddddd" height="100%">
80: <table width="100" border="0" cellpadding="0" cellspacing="0" height="100%">
81: <tr>
82: <td valign="top" height="100%">
83: END_OF_BLOCK
84: &display_nav_box($r,$command);
85: $r->print('</td></tr></table></td>');
86: $r->print('<td width="100%" bgcolor="#ffffff"><table width="100%" border="0" cellpadding="5" cellspacing="0"><tr><td width="100%">');
87:
88: if ($command eq 'config') {
89: &display_config_box($r);
90: } else {
91: &display_actions_box($r);
92: }
93: $r->print(<<END_OF_BLOCK);
94: </td>
95: </tr>
96: </table>
97: </td>
98: </tr>
99: </table>
100: </td>
101: </tr>
102: </table>
103: </td>
104: </tr>
105: </table>
106: </td>
107: </tr>
108: </table><br />
109: </body>
110: </html>
111: END_OF_BLOCK
112: }
113:
114: #------------------------------
115: # display_nav_box
116: #
117: # Display the navigation box
118: #------------------------------
119:
120: sub display_nav_box {
121: my ($r,$command) = @_;
122: $r->print('<table width="100" border="0" cellpadding="3" cellspacing="0">'."\n");
123: if ($command eq "info") {
124: $r->print('<tr><td bgcolor="#ffffff">');
125: $r->print('<small><b>Action Items</b></small><br />');
126: $r->print('</td></tr>');
127: } else {
128: $r->print('<tr><td>');
129: $r->print('<small><a href="/adm/whatsnew?command=info">Current Action Items</a></small><br />');
130: $r->print('</td></tr>');
131: }
132: $r->print('<tr><td> </td></tr>');
133: if ($command eq "config") {
134: $r->print('<tr><td bgcolor="#ffffff">');
135: $r->print('<small><b>Display options</b></small><br />');
136: $r->print('</td></tr>');
137: } else {
138: $r->print('<tr><td>');
139: $r->print('<small><a href="/adm/whatsnew?command=config">Display options</a></small><br />');
140: $r->print('</td></tr>');
141: }
142: $r->print('</table>');
143: }
144:
145: #-------------------------------
146: # display_header
147: #
148: # Display the header information and set
149: # up the HTML
150: #-------------------------------
151:
152: sub display_header{
153: my $bodytag=&Apache::loncommon::bodytag('Course Action Items');
154: return(<<ENDHEAD);
155: <html>
156: <head>
157: <title>Course Action Items</title>
158: </head>
159: $bodytag
160: ENDHEAD
161: }
162:
163: #-------------------------------
164: # display_actions_box
165: #
166: # Display the action items
167: #
168: #-------------------------------
169:
170: sub display_actions_box() {
171: my $r = shift;
172:
173: my $rowColor1 = "#ffffff";
174: my $rowColor2 = "#eeeeee";
175: my $rowColor;
176:
177: my %unread = ();
178: my %ungraded = ();
179: my %bombed = ();
180: my @newmsgs = ();
181: my @critmsgs = ();
182: my @newdiscussions = ();
183: my @tograde = ();
184: my @bombs = ();
185:
186: my $domain=&Apache::loncommon::determinedomain();
187: my $function;
188: if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) {
189: $function='coordinator';
190: }
191: if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) {
192: $function='admin';
193: }
194:
195: my $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain);
196: my $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain);
197:
198: &getitems(\%unread,\%ungraded,\%bombed,\@newdiscussions,\@tograde,\@bombs);
199: my ($msgcount,$critmsgcount) = &getmail(\@newmsgs,\@critmsgs);
200:
201: unless ($ENV{'request.course.id'}) {
202: $r->print('<br /><b><center>You are accessing an invalid course</center></b><br /><br />');
203: return;
204: }
205:
206: $r->print('<b>Course Action Items</b><br /><hr width="100%" /><table border="0" width="100%" cellpadding="2" cellspacing="4" bgcolor="#ffffff"><tr><td align="left" valign="top" width="45%">');
207:
208: ## UNREAD COURSE DISCUSSION POSTS ##
209: $r->print(<<"END");
210: <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
211: <tr><td>
212: <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
213: <tr>
214: <td bgcolor="$tabbg"><b>Unread course discussion posts:</b></td>
215: </tr>
216: <tr>
217: <td bgcolor="#ffffff">
218: <table cellpadding="2" cellspacing="0" border="0" width="100%">
219: END
220:
221: if (@newdiscussions > 0) {
222: # @newdiscussions = sort { &cmp_title($a,$b) } @newdiscussions;
223: my $rowNum = 0;
224: foreach my $ressymb (@newdiscussions) {
225: my $forum_title = $unread{$ressymb}{'title'};
226: my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb);
227: my $feedurl = &Apache::lonnet::clutter($url);
228: # backward compatibility (bulletin boards used to be 'wrapped')
229: if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
230: $feedurl=~s|^/adm/wrapper||;
231: }
232: my $unreadnum = keys %{$unread{$ressymb}};
233: $unreadnum = $unreadnum - 2;
234: if ($unreadnum > 0) {
235: if ($rowNum %2 == 1) {
236: $rowColor = $rowColor1;
237: } else {
238: $rowColor = $rowColor2;
239: }
240: $r->print('<tr><td bgcolor="'.$rowColor.'"><small><a href="'.$feedurl.'?symb='.$unread{$ressymb}{symb}.'">'.$forum_title.':</a> </td><td bgcolor="'.$rowColor.'" align="right">'.$unreadnum.' </td></tr>');
241: $rowNum ++;
242: }
243: }
244: } else {
245: $r->print('<tr><td bgcolor="#ffffff"><br><center> <i><b><small>No unread posts in course discussions</small></b></i><br><br></td></tr>');
246: }
247: $r->print('</table></td></tr></table></td></tr></table><br />');
248:
249: ## UNGRADED ITEMS ##
250: $r->print(<<END);
251: <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
252: <tr><td>
253: <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
254: <tr>
255: <td bgcolor="$tabbg"><b>Problems requiring handgrading:</b></td></tr>
256: <tr>
257: <td bgcolor="#ffffff">
258: <table cellpadding="2" cellspacing="0" border="0" width="100%">
259: END
260:
261: if (@tograde > 0) {
262: $r->print('<tr><th bgcolor="#cccccc">Problem Name</th><th>Number ungraded</th></tr>');
263: my $rowNum = 0;
264: foreach my $res (@tograde) {
265: if ($rowNum %2 == 1) {
266: $rowColor = $rowColor1;
267: } else {
268: $rowColor = $rowColor2;
269: }
270:
271: $r->print('<tr bgcolor="'.$rowColor.'"><td>'.$ungraded{$res}{title}.'</td><td>'.$ungraded{$res}{count}.'</td></tr>');
272: $rowNum ++;
273: }
274: } else {
275: $r->print('<tr><td bgcolor="#ffffff"><br><center><i><b><small> No problems require handgrading </small><br><br></b></i></td></tr>');
276: }
277: $r->print('</table></td></tr></table></td></tr></table><br />');
278: $r->print('</td><td width="5%"> </td><td align="left" valign="top" width-"50%">');
279:
280: ## MESSAGES ##
281: $r->print(<<END);
282: <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
283: <tr>
284: <td>
285: <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
286: <tr>
287: <td bgcolor="$tabbg"><b>New course messages</b></td>
288: </tr>
289: <tr>
290: <td bgcolor="#ffffff">
291: <table width="100%" cellspacing="0" cellpadding="0" border="0">
292: END
293: if ($msgcount > 0) {
294: my $rowNum = 0;
295: my $mailcount = 1;
296: foreach my $msg (@newmsgs) {
297: if ($rowNum %2 == 1) {
298: $rowColor = $rowColor1;
299: } else {
300: $rowColor = $rowColor2;
301: }
302: $r->print('<tr><td bgcolor="'.$rowColor.'" valign="top"><small>'.$mailcount.'. <small></td><td valign="top"><small><a href="/adm/mail?">'.$msg->{'shortsub'}.'</a> </small></td><td valign="top"><small> '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' </small></td><td valign="top"><small>'.$msg->{'sendtime'}.'</small></td></tr>');
303: $rowNum ++;
304: $mailcount ++;
305: }
306: } else {
307: $r->print('<tr><td bgcolor="#ffffff" width="100%"><center><br /><b><i><small>No new course messages</small></i></b><br /><br /></center></td></tr>');
308: }
309:
310: $r->print('</table></td></tr></table></td></tr></table><br />');
311:
312: $r->print(<<END);
313: <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
314: <tr>
315: <td>
316: <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
317: <tr>
318: <td bgcolor="$tabbg"><b>New critical messages in course</b></td>
319: </tr>
320: <tr> <td bgcolor="#ffffff">
321: <table width="100%" cellspacing="0" cellpadding="0" border="0">
322: END
323:
324: if ($critmsgcount > 0) {
325: my $rowNum = 0;
326: my $mailcount = 1;
327: foreach my $msg (@critmsgs) {
328: if ($rowNum %2 == 1) {
329: $rowColor = $rowColor1;
330: } else {
331: $rowColor = $rowColor2;
332: }
333: $r->print('<tr><td bgcolor="'.$rowColor.'" valign="top"><small>'.$mailcount.'. <small></td><td valign="top"><small><a href="/adm/mail?">'.$msg->{'shortsub'}.'</a> </small></td><td valign="top"><small> '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' </small></td><td valign="top"><small>'.$msg->{'sendtime'}.'</small></td></tr>');
334: $rowNum ++;
335: $mailcount ++;
336: }
337: } else {
338: $r->print('<tr><td bgcolor="#ffffff" width="100%"><center><br /><b><i><small>No unread critical messages in course</small></i></b><br /><br /></center></td></tr>');
339: }
340:
341: $r->print('</table></td></tr></table></td></tr></table><br />');
342:
343: ## BOMBS ##
344: $r->print(<<END);
345: <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
346: <tr>
347: <td>
348: <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
349: <tr>
350: <td bgcolor="$tabbg"><b>Problems with errors</b></td>
351: </tr>
352: <tr>
353: <td bgcolor="#ffffff">
354: <table width="100%" cellspacing="0" cellpadding="0" border="0">
355: END
356: my $bombnum = 0;
357: if (@bombs > 0) {
358: # @bombs = sort { &cmp_title($a,$b) } @bombs;
359: foreach my $bomb (@bombs) {
360: if ($bombnum %2 == 1) {
361: $rowColor = $rowColor1;
362: } else {
363: $rowColor = $rowColor2;
364: }
365: $r->print('<tr bgcolor="'.$rowColor.'"><td>'.$bombed{$bomb}{errorlink}.'</td></tr>');
366: $bombnum ++;
367: }
368: } else {
369: $r->print('<tr><td bgcolor="#ffffff"><br /><center><b><i><small>No problems with errors</small></i></b></center><br /></td></tr>');
370: }
371: $r->print('</table></td></tr></td></tr></table>');
372: $r->print('
373: </table>
374: </td>
375: </tr>
376: </table>');
377: $r->print('</td></tr></table>');
378: }
379:
380: sub getitems {
381: my ($unread,$ungraded,$bombed,$newdiscussions,$tograde,$bombs) = @_;
382: my $navmap = Apache::lonnavmaps::navmap->new();
383: my @allres=$navmap->retrieveResources();
384: my %discussiontime = &Apache::lonnet::dump('discussiontimes',
385: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
386: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
387: my %lastread = &Apache::lonnet::dump('nohist_'.$ENV{'request.course.id'}.'_discuss',$ENV{'user.domain'},$ENV{'user.name'},'lastread');
388: my %lastreadtime = ();
389: my @discussions = ();
390: my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
391:
392: foreach (keys %lastread) {
393: my $key = $_;
394: $key =~ s/_lastread$//;
395: $lastreadtime{$key} = $lastread{$_};
396: }
397: foreach my $resource (@allres) {
398: my $result = '';
399: my $applies = 0;
400: my $symb = $resource->symb();
401: %{$$bombed{$symb}} = ();
402: %{$$ungraded{$symb}} = ();
403: my $title = $resource->compTitle();
404: my $ressymb = $symb;
405: if ($ressymb =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) {
406: $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
407: unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
408: $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper/|;
409: }
410: }
411:
412: # Check for unread discussion postings
413: if (defined($discussiontime{$ressymb})) {
414: push(@discussions,$ressymb);
415: my $prevread = 0;
416: my $unreadcount = 0;
417: %{$$unread{$ressymb}} = ();
418: $$unread{$ressymb}{'title'} = $title;
419: $$unread{$ressymb}{'symb'} = $symb;
420: if (defined($lastreadtime{$ressymb})) {
421: $prevread = $lastreadtime{$ressymb};
422: }
423: my %contrib = &Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
424: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
425: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
426: if ($contrib{'version'}) {
427: for (my $id=1;$id<=$contrib{'version'};$id++) {
428: unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
429: if ($prevread <$contrib{$id.':timestamp'}) {
430: $$unread{$ressymb}{$unreadcount} = $id.': '.$contrib{$id.':subject'};
431: $unreadcount ++;
432: push(@{$newdiscussions}, $ressymb);
433: }
434: }
435: }
436: }
437: }
438:
439: # Check for ungraded problems
440: if ($resource->is_problem()) {
441: my $ctr = 0;
442: my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
443: my ($partlist,$handgrade,$responseType) = &Apache::grades::response_type($url,$symb);
444: foreach my $student (keys(%$classlist)) {
445: my ($uname,$udom) = split/:/,$student;
446: my %status=&Apache::grades::student_gradeStatus($url,$symb,$udom,$uname,$partlist);
447: my $submitted = 0;
448: my $graded = 0;
449: foreach (keys(%status)) {
450: $submitted = 1 if ($status{$_} ne 'nothing');
451: $graded = 1 if ($status{$_} !~ /^correct/);
452: my ($foo,$partid,$foo1) = split(/\./,$_);
453: if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
454: $submitted = 0;
455: }
456: }
457: next if (!$submitted || !$graded);
458: $ctr ++;
459: }
460: if ($ctr) {
461: $$ungraded{$symb}{count} = $ctr;
462: $$ungraded{$symb}{title} = $title;
463: push(@{$tograde}, $symb);
464: }
465: }
466:
467: # Check for bombs
468: if ($resource->getErrors()) {
469: my $errors = $resource->getErrors();
470: my @bombs = split(/,/, $errors);
471: my $errorcount = scalar(@bombs);
472: my $errorlink = '<a href="/adm/email?display='.
473: &Apache::lonnet::escape($$bombs[0]).'">';
474: $$bombed{$symb}{errorcount} = $errorcount;
475: $$bombed{$symb}{errorlink} = $errorlink;
476: push(@{$bombs}, $symb);
477: }
478: }
479: # Compile maxtries and degree of difficulty.
480: }
481:
482: sub getmail {
483: my ($newmsgs,$critmsgs) = @_;
484: # Check for unread mail in course
485: my $msgcount = 0;
486: my @msgids = sort split(/\&/,&Apache::lonnet::reply
487: ('keys:'.$ENV{'user.domain'}.':'.
488: $ENV{'user.name'}.':nohist_email',
489: $ENV{'user.home'}));
490: foreach my $msgid (@msgids) {
491: my ($sendtime,$shortsubj,$fromname,$fromdom,$fromcid,$status)=
492: &Apache::lonmsg::unpackmsgid($msgid);
493: if ($fromcid eq $ENV{'request.course.id'}) {
494: if (defined($sendtime) && $sendtime!~/error/) {
495: my $numsendtime = $sendtime;
496: $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
497: if ($status eq 'new') {
498: $$msgcount ++;
499: push(@{$newmsgs}, {
500: msgid => $msgid,
501: sendtime => $sendtime,
502: shortsub => &Apache::lonnet::unescape($shortsubj),
503: from => $fromname,
504: fromdom => $fromdom
505: });
506: }
507: }
508: }
509: }
510:
511: # Check for critical messages in course
512: my %what=&Apache::lonnet::dump('critical');
513: my $result = '';
514: my $critmsgcount = 0;
515: foreach my $msgid (sort keys %what) {
516: my ($sendtime,$shortsubj,$fromname,$fromdom,$fromcid,$status)=
517: &Apache::lonmsg::unpackmsgid($_);
518: if ($fromcid eq $ENV{'request.course.id'}) {
519: if (defined($sendtime) && $sendtime!~/error/) {
520: my $numsendtime = $sendtime;
521: $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
522: $critmsgcount ++;
523: push(@{$critmsgs}, {
524: msgid => $msgid,
525: sendtime => $sendtime,
526: shortsub => &Apache::lonnet::unescape($shortsubj),
527: from => $fromname,
528: fromdom => $fromdom
529: });
530: }
531: }
532: }
533: return ($msgcount,$critmsgcount);
534: }
535:
536: sub cmp_title {
537: my ($atitle,$btitle) = (lc($_[0]->compTitle),lc($_[1]->compTitle));
538: $atitle=~s/^\s*//;
539: $btitle=~s/^\s*//;
540: return $atitle cmp $btitle;
541: }
542:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>