--- loncom/interface/lonannounce.pm 2006/07/03 15:30:52 1.59 +++ loncom/interface/lonannounce.pm 2013/05/27 00:19:32 1.87 @@ -1,7 +1,7 @@ # The LearningOnline Network # Announce # -# $Id: lonannounce.pm,v 1.59 2006/07/03 15:30:52 www Exp $ +# $Id: lonannounce.pm,v 1.87 2013/05/27 00:19:32 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,12 +37,15 @@ use Apache::lonnavmaps(); use Apache::lonrss(); use Apache::lonnet; use HTML::Entities(); +use LONCAPA qw(:match); +use DateTime; +use DateTime::TimeZone; my %todayhash; my %showedcheck; sub editfield { - my ($r,$start,$end,$text)=@_; + my ($r,$start,$end,$text,$crstype)=@_; # Deal with date forms my $startdateform = &Apache::lonhtmlcommon::date_setter('anno', 'startdate', @@ -50,22 +53,29 @@ sub editfield { my $enddateform = &Apache::lonhtmlcommon::date_setter('anno', 'enddate', $end); - my $help=&Apache::loncommon::help_open_menu('Calendar Add Announcement','Calendar_Add_Announcement',274,'Communication Tools'); - my %lt=&Apache::lonlocal::texthash('post' => 'Post Announcement', + #my $help=&Apache::loncommon::help_open_menu('Calendar Add Announcement','Calendar_Add_Announcement',274,'Communication Tools'); + my $help=&Apache::loncommon::help_open_topic('Calendar_Add_Announcement'); + + my %lt=&Apache::lonlocal::texthash('annon' => 'Course Announcements', + 'post' => 'Post Announcement', 'start' => 'Starting date', 'end' => 'Ending date', 'incrss' => 'Include in course RSS newsfeed'); + if ($crstype eq 'Community') { + $lt{'annon'} = &mt('Community Announcements'); + $lt{'incrss'} = &mt('Include in community RSS newsfeed'); + } $r->print(< +

$lt{'annon'} $help

+
$lt{'start'}:$startdateform
$lt{'end'}:$enddateform

-

+

ENDFORM } @@ -73,21 +83,42 @@ sub readcalendar { my $courseid=shift; my $coursenum=$env{'course.'.$courseid.'.num'}; my $coursedom=$env{'course.'.$courseid.'.domain'}; + if ($coursenum eq '' || $coursedom eq '') { + my %courseinfo=&Apache::lonnet::coursedescription($courseid); + if ($coursenum eq '' && exists($courseinfo{'num'})) { + $coursenum = $courseinfo{'num'}; + } + if ($coursedom eq '' && exists($courseinfo{'domain'})) { + $coursedom = $courseinfo{'domain'}; + } + } + my %thiscal=&Apache::lonnet::dump('calendar',$coursedom,$coursenum); my %returnhash=(); foreach my $item (keys(%thiscal)) { unless (($item=~/^error\:/) || ($thiscal{$item}=~/^error\:/)) { - $returnhash{$courseid.'@'.$item}=$thiscal{$item}; + my ($start,$end)=split('_',$item); + $returnhash{join("\0",$courseid,$start,$end)}=$thiscal{$item}; } } - my $can_see_hidden = $env{'request.role.adv'}; - my $navmap;# = Apache::lonnavmaps::navmap->new(); - my %resourcedata= - &Apache::lonnet::dump('resourcedata',$coursedom,$coursenum); - foreach my $thiskey (sort keys %resourcedata) { - if ($resourcedata{$thiskey.'.type'}=~/^date/) { + my $can_see_hidden = ($env{'request.role.adv'} && + ($courseid eq $env{'request.course.id'})); + + my $navmap; + if ($courseid eq $env{'request.course.id'}) { + $navmap = Apache::lonnavmaps::navmap->new(); + } + + my $resourcedata= + &Apache::lonnet::get_courseresdata($coursenum,$coursedom); + if (ref($resourcedata) ne 'HASH') { + return %returnhash; + } + foreach my $thiskey (keys(%$resourcedata)) { + if ($resourcedata->{$thiskey.'.type'}=~/^date/) { my ($course,$middle,$part,$name)= - ($thiskey=~/^(\w+)\.(?:(.+)\.)*([\w\s]+)\.(\w+)$/); + ($thiskey=~/^(\Q$courseid\E)\.(?:(.+)\.)*([\w\s]+)\.(\w+)$/); + my %data = ( 'section' => &mt('All Students')); if ($middle=~/^\[(.*)\]\./) { my $sec=$1; @@ -113,7 +144,9 @@ sub readcalendar { } if (!$can_see_hidden) { my $res = $navmap->getResourceByUrl($map_url); - if ($res && $res->randomout()) { next; } + if ($res && $res->randomout()) { + next; + } } $data{'realm'}=&mt('Folder/Map'); $data{'url'} = $map_url; @@ -123,7 +156,9 @@ sub readcalendar { } if (!$can_see_hidden) { my $res = $navmap->getBySymb($middle); - if ($res && $res->randomout()) { next; } + if ($res && $res->randomout()) { + next; + } } $data{'realm'} = &mt('Resource'); $data{'symb'} = $middle; @@ -134,7 +169,7 @@ sub readcalendar { # see if accidentally answerdate is before duedate my $answerkey=$thiskey; $answerkey=~s/duedate$/answerdate/; - if ($resourcedata{$thiskey}>$resourcedata{$answerkey}) { + if ($resourcedata->{$thiskey}>$resourcedata->{$answerkey}) { $data{'datetype'} = &mt('Due and Answer Available'); } } @@ -149,14 +184,15 @@ sub readcalendar { # see if accidentally answerdate is before duedate my $duekey=$thiskey; $duekey=~s/answerdate$/duedate/; - if ($resourcedata{$duekey}>$resourcedata{$thiskey}) { + if ($resourcedata->{$duekey}>$resourcedata->{$thiskey}) { # forget it next; } $data{'datetype'}=&mt('Answer Available'); } - $returnhash{$courseid.'@'.$resourcedata{$thiskey}.'_'. - $resourcedata{$thiskey}}=\%data; + $returnhash{join("\0",$courseid, + $resourcedata->{$thiskey}, + $resourcedata->{$thiskey})}=\%data; } } return %returnhash; @@ -192,7 +228,7 @@ sub normalcell { && ($env{'form.pickdate'} ne 'yes') && (!$internalflag)) { $output.=''; + $end.'" />'; $showedcheck{$start.'_'.$end}=1; } } @@ -265,11 +301,59 @@ sub order { } sub nextday { - my %th=@_; - $th{'day'}++; + my ($tk,%th)=@_; + my ($incmonth,$incyear); + if ($th{'day'} > 27) { + if ($th{'month'} == 2) { + if ($th{'day'} == 29) { + $incmonth = 1; + } elsif ($th{'day'} == 28) { + if (!&is_leap_year($tk)) { + $incmonth = 1; + } + } + } elsif (($th{'month'} == 4) || ($th{'month'} == 6) || + ($th{'month'} == 9) || ($th{'month'} == 11)) { + if ($th{'day'} == 30) { + $incmonth = 1; + } + } elsif ($th{'day'} == 31) { + if ($th{'month'} == 12) { + $incyear = 1; + } else { + $incmonth = 1; + } + } + if ($incyear) { + $th{'day'} = 1; + $th{'month'} = 1; + $th{'year'}++; + } elsif ($incmonth) { + $th{'day'} = 1; + $th{'month'}++; + } else { + $th{'day'}++; + } + } else { + $th{'day'}++; + } return (&Apache::loncommon::maketime(%th),$th{'month'}); } +sub is_leap_year { + my ($thistime) = @_; + my ($is_leap,$timezone,$dt); + $timezone = &Apache::lonlocal::gettimezone(); + eval { + $dt = DateTime->from_epoch(epoch => $thistime) + ->set_time_zone($timezone); + }; + if (!$@) { + $is_leap = $dt->is_leap_year; + } + return $is_leap; +} + sub display_msg { my ($msg) = @_; @@ -296,7 +380,7 @@ sub display_msg { sub showday { my ($tk,$mode,%allcal)=@_; my %th=&Apache::loncommon::timehash($tk); - my ($nextday,$nextmonth)=&nextday(%th); + my ($nextday,$nextmonth)=&nextday($tk,%th); my @outp; if ($mode) { my $oneday=24*3600; @@ -304,9 +388,9 @@ sub showday { $nextday+=$oneday; } foreach my $item (keys(%allcal)) { - my ($course,$startdate,$enddate)=($item=~/^(\w+)\@(\d+)\_(\d+)$/); - if (($startdate<$nextday) && ($enddate>=$tk)) { - push(@outp,[$course,$startdate,$enddate,$allcal{$item}]); + my ($courseid,$startdate,$enddate)= split("\0",$item); + if (($startdate<$nextday) && ($enddate>=$tk)) { + push(@outp,[$courseid,$startdate,$enddate,$allcal{$item}]); } } unless ($mode) { @@ -335,7 +419,8 @@ sub picklink { sub dialscript { return (< + ENDDIA } # ----------------------------------------------------- Summarize all calendars sub get_all_calendars { my %allcal=(); - foreach my $course (sort(&Apache::loncommon::findallcourses())) { + my %courses = &Apache::loncommon::findallcourses(); + foreach my $course (sort(keys(%courses))) { %allcal=(%allcal,&readcalendar($course)); } return %allcal; @@ -369,7 +456,7 @@ sub output_ics_file { $r->print("PRODID:-//LONCAPA//LONCAPA Calendar Output//EN$crlf"); my %allcal=&get_all_calendars(); foreach my $event (keys(%allcal)) { - my ($courseid,$startdate,$enddate)=($event=~/^(\w+)\@(\d+)\_(\d+)$/); + my ($courseid,$startdate,$enddate)= split('\0',$event); my $uid=$event; $uid=~s/[\W\_]/-/gs; $uid.='@loncapa'; @@ -387,6 +474,13 @@ sub output_ics_file { $r->print("END:VCALENDAR$crlf"); } +sub show_timezone { + my $tzone = &Apache::lonlocal::gettimezone(); + my $dt = DateTime->now(); + my $tz = DateTime::TimeZone->new( name => $tzone ); + return &mt('([_1] time zone)',$tz->short_name_for_datetime($dt)); +} + sub handler { my $r = shift; if ($r->uri=~/\.(ics|ical)$/) { @@ -414,19 +508,23 @@ sub handler { # ---------------------------------------------- See if we are in pickdate mode my $pickdatemode=($env{'form.pickdate'} eq 'yes'); - my $pickinfo='&pickdate=yes&formname='.$env{'form.formname'}. - '&element='.$env{'form.element'}; + my $pickinfo='&pickdate=yes&formname='.$env{'form.formname'}. + '&element='.$env{'form.element'}; # --------------------------------------------- Find out first day of the month - my %firstday=&Apache::loncommon::timehash( - &Apache::loncommon::maketime( 'day' => 1, 'month'=> $month, - 'year' => $year, 'hours' => 0, - 'minutes' => 0, 'seconds' => 0, - 'dlsav' => -1 )); + my $tk = &Apache::loncommon::maketime( 'day' => 1, + 'month'=> $month, + 'year' => $year, + 'hour' => 0, + 'minute' => 0, + 'second' => 0); + my %firstday = &Apache::loncommon::timehash($tk); my $weekday=$firstday{'weekday'}; + # ------------------------------------------------------------ Print the screen my $js = < + ENDDOCUMENT @@ -447,8 +546,8 @@ ENDDOCUMENT &dialscript(). ''); } else { - $r->print(&Apache::loncommon::start_page("Announcements and Calendar", - $js)); + my $brcrum = [{href=>"/adm/announcements",text=>"Announcements and Calendar"}]; + $r->print(&Apache::loncommon::start_page("Communication",$js,{'bread_crumbs' => $brcrum})); } # does this user have privileges to post, etc? my $allowed=0; @@ -470,38 +569,55 @@ ENDDOCUMENT } # ------------------------------------------------------------ Process commands if ($serverpost) { - if ($env{'form.serveraction'}) { - foreach my $key (keys(%env)) { - if ($key=~/^form\.postto\_(\w+)/) { - $r->print( - '
Posting '.$1.': '.&Apache::lonnet::postannounce - ($1,$env{'form.serverannnounce'})); - } - } - } - $r->print(< -

Post Server Announcements

-Post announcements to the system login and roles screen
-(leave blank to delete announcement)
-
-Check machines:
-SERVERANNOUNCE + if ($env{'form.serveraction'}) { + my $rc; + my $message; + foreach my $key (keys(%env)) { + if ($key=~/^form\.postto\_(\w+[\w\-]*)/) { + $rc = &Apache::lonnet::postannounce + ($1,$env{'form.serverannnounce'}); + if ($rc eq 'ok') { + $message .= + &Apache::lonhtmlcommon::confirm_success( + &mt('Announcement posted to [_1]',$1)) + .'
'; + } else { + $message .= + &Apache::lonhtmlcommon::confirm_success( + &mt('Posting announcement to [_1] failed: [_2]' + ,$1,$rc), 1) + .'
'; + } + } + } + $r->print(&Apache::loncommon::confirmwrapper($message)); + } + $r->print('' + .'

'.&mt('Post Server Announcements').'

' + .&mt('Post announcements to the system login and roles screen').'
' + .''.&mt('(leave blank to delete announcement)').'
' + .'
' + .&mt('Check machines:').'
' + ); # list servers - foreach my $host (sort(keys(%Apache::lonnet::hostname))) { - if (&Apache::lonnet::allowed('psa',$Apache::lonnet::hostdom{$host})) { - $r->print ('
'. - $host.' '.$Apache::lonnet::hostname{$host}.' '. - 'current'); + my %hostname = &Apache::lonnet::all_hostnames(); + foreach my $host (sort(keys(%hostname))) { + if (&Apache::lonnet::allowed('psa', + &Apache::lonnet::host_domain($host))) { + $r->print (''. + &mt('Current Announcement').'
'); } } $r->print( - '

'); + '

'); } if ($allowed) { my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'}; my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + my $crstype = &Apache::loncommon::course_type(); # ----------------------------------------------------- Store new submitted one if ($env{'form.action'} eq 'new') { my $startdate = @@ -519,7 +635,13 @@ SERVERANNOUNCE $startdate.'_'.$enddate => $env{'form.msg'} },$coursedom,$coursenum); if ($env{'form.rsspost'}) { - &Apache::lonrss::addentry($coursenum,$coursedom,'Course_Announcements', + my $feed; + if ($crstype eq 'Community') { + $feed = 'Community_Announcements'; + } else { + $feed = 'Course_Announcements'; + } + &Apache::lonrss::addentry($coursenum,$coursedom,$feed, &mt('Event from [_1] to [_2]', &Apache::lonlocal::locallocaltime($startdate), &Apache::lonlocal::locallocaltime($enddate)), @@ -541,7 +663,7 @@ SERVERANNOUNCE $tomorrowhash{'day'}++; my $tomorrow=&Apache::loncommon::maketime(%tomorrowhash); - &editfield($r,$today,$tomorrow,''); + &editfield($r,$today,$tomorrow,'',$crstype); } # ----------------------------------------------------- Summarize all calendars my %allcal=&get_all_calendars(); @@ -550,18 +672,21 @@ SERVERANNOUNCE if ($pm<1) { ($pm,$py)=(12,$year-1); } if ($fm>12){ ($fm,$fy)=(1,$year+1); } - $r->print('

'.('',&mt('January'),&mt('February'),&mt('March'), + $r->print('

'.&mt('Calendar').'

' + .'

'.('',&mt('January'),&mt('February'),&mt('March'), &mt('April'),&mt('May'), &mt('June'),&mt('July'),&mt('August'), &mt('September'),&mt('October'), &mt('November'),&mt('December'))[$month].' '. - $year.'

'); + $year.' '.&show_timezone().''); # Reached the end of times, give up if (($year<1970) || ($year>2037)) { - $r->print('

No calendar available for this date.

'. - 'Current Month'. - &Apache::loncommon::end_page()); + $r->print('

' + .&mt('No calendar available for this date.') + .'

' + .''.&mt('Current Month').'' + .&Apache::loncommon::end_page()); return OK; } @@ -569,62 +694,100 @@ SERVERANNOUNCE if ($env{'form.pickdate'} eq 'yes') { $class .= " LC_calendar_pickdate"; } +# ------------------------------------------------ Determine first day of a week + my $datelocale = &Apache::lonlocal::getdatelocale(); + my $days_in_week = 7; + my $startweek = 0; + if (ref($datelocale)) { + $startweek = $datelocale->first_day_of_week(); + if ($startweek == $days_in_week) { $startweek = 0; } + } + my @days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); + my @localdays; + if ($startweek == 0) { + @localdays = @days; + } else { + my $endday = $days_in_week - $startweek; + for (my $i=0; $i<$days_in_week; $i++) { + if ($i < $endday) { + $localdays[$i] = $days[$i+$startweek]; + } else { + $localdays[$i] = $days[$i-$endday]; + } + } + } + +# ----------------------------------------------------------- Weekday in locale + my $loc_weekday = $weekday - $startweek; + if ($loc_weekday < 0) { + $loc_weekday += $days_in_week; + } + $r->print( - ''.&mt('Previous Month').' '. - ''.&mt('Next Month').''. '   '.&mt('Current Month').'

'. - ' - - - - - - -'); + '&year='.$todayhash{'year'}. + ($pickdatemode?$pickinfo:'').'">'.&mt('Current Month').'
'. + '
'.&mt('Sun').''.&mt('Mon').''.&mt('Tue').''.&mt('Wed').''.&mt('Thu').''.&mt('Fri').''.&mt('Sat').'
'); + for (my $i=0; $i<@localdays; $i++) { + $r->print(''); + } + $r->print(''); - my $tk=&Apache::loncommon::maketime(%firstday); my $outp; my $nm; # ---------------------------------------------------------------- Actual table $r->print(''); - for (my $i=0;$i<$weekday;$i++) { $r->print(&emptycell); } - for (my $i=$weekday;$i<=6;$i++) { + for (my $i=0;$i<$loc_weekday;$i++) { $r->print(&emptycell); } + for (my $i=$loc_weekday;$i<=6;$i++) { ($tk,$nm,$outp)=&showday($tk,0,%allcal); $r->print($outp); } $r->print(''); + my $lastrow = 0; + my $lastday = 0; for (my $k=0;$k<=4;$k++) { - $r->print(''); - for (my $i=0;$i<=6;$i++) { - ($tk,$nm,$outp)=&showday($tk,0,%allcal); - if ($month!=$nm) { $outp=&emptycell; } - $r->print($outp); + if (!$lastrow) { + $r->print(''); + for (my $i=0;$i<=6;$i++) { + if ($lastday) { + $outp = &emptycell(); + } else { + my $currtk = $tk; + ($tk,$nm,$outp)=&showday($tk,0,%allcal); + if ($month!=$nm) { $lastday = 1; } + } + $r->print($outp); + } + if ($lastday) { + $lastrow = 1; + } + $r->print(''); } - $r->print(''); } # ------------------------------------------------------------------- End table - $r->print('
'.&mt($localdays[$i]).'
'); + $r->print(''); # ----------------------------------------------------------------- Check marks undef(%showedcheck); # --------------------------------------------------------------- Remove button - if ($allowed) { $r->print(''. + if ($allowed) { $r->print('
'. &Apache::loncommon::help_open_topic('Calendar_Remove_Announcement').''); } $r->print('

'. - ''.&mt('Previous Month').' '. - ''.&mt('Next Month').''. '   '.&mt('Current Month').'

'. - ($pickdatemode?'
':'').&Apache::loncommon::end_page()); - $r->print(''.&mt('Download your Calendar as iCalendar File').''); + ($pickdatemode?'':''). + ''.&mt('Download your Calendar as iCalendar File').''. + &Apache::loncommon::end_page()); return OK; } 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.