';
+ ($year eq $todayhash{'year'}))?'_current':'').
+ '" >'.&picklink($day,$day,$month,$year).' '.$output.'';
}
sub plaincell {
- my ($text)=@_;
- my $output='';
- my @items=&order($text);
+ my ($items_ref)=@_;
+ my $output;
+ my @items=&order($items_ref);
foreach my $item (@items) {
- if ($item) {
- my ($courseid,$start,$end,$msg)=split(/\@/,$item,4);
+ if (ref($item)) {
+ my ($courseid,$start,$end,$msg)=@$item;
my $fullmsg=&mt('Calendar Announcement for ').$env{'course.'.$courseid.'.description'}.
'\n'.&Apache::lonlocal::locallocaltime($start);
if ($start!=$end) {
$fullmsg.=' - '.&Apache::lonlocal::locallocaltime($end);
}
- $msg=~s/INTERNAL\://gs;
+ $msg = &display_msg($msg);
$fullmsg.=':\n'.$msg;
$fullmsg=~s/[\n\r]/\\n/gs;
$fullmsg=&HTML::Entities::encode($fullmsg,'<>&"\'');
$fullmsg=~s/&/\\&/g;
+ my $short_msg = substr($msg,0,80).((length($msg) > 80)?'...':'');
+ if (defined($output)) { $output.=' '; }
$output.=''.
- substr($msg,0,80).'... ';
+ $short_msg.'';
}
}
return $output;
}
sub listcell {
- my ($text)=@_;
+ my ($items_ref)=@_;
my $output='';
- my @items=&order($text);
+ my @items=&order($items_ref);
foreach my $item (@items) {
- if ($item) {
- my ($courseid,$start,$end,$msg)=split(/\@/,$item,4);
- $msg=~s/INTERNAL\://gs;
- my $fullmsg=&Apache::lonlocal::locallocaltime($start);
+ if (ref($item)) {
+ my ($courseid,$start,$end,$msg)=@$item;
+ my $fullmsg=&Apache::lonlocal::locallocaltime($start);
if ($start!=$end) {
$fullmsg.=&mt(' to ').
&Apache::lonlocal::locallocaltime($end);
}
- $fullmsg.=': '.
- $msg.'';
+ $fullmsg.=': '.&display_msg($msg).'';
$output.='
'.$fullmsg.'
';
}
}
@@ -240,64 +282,124 @@ sub listcell {
}
sub order {
- my ($text)=@_;
- my @items = split(/___&&&___/,$text);
- sort {
- my (undef,$astart,$aend)=split(/\@/,$a);
- my (undef,$bstart,$bend)=split(/\@/,$b);
+ my ($items)=@_;
+ return sort {
+ my ($astart,$aend)=$a->[1,2];
+ my ($bstart,$bend)=$b->[1,2];
if ($astart != $bstart) {
return $astart <=> $bstart;
}
return $aend <=> $bend;
- } @items;
+ } @$items;
}
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) = @_;
+
+ # if it's not a ref, it's an instructor provided message
+ return $msg if (!ref($msg));
+
+ my $output = $msg->{'datetype'}. ': '.$msg->{'realm'};
+ if (exists($msg->{'url'})) {
+ my $displayurl=&Apache::lonnet::gettitle($msg->{'url'});
+ if ($msg->{'url'}!~/\Q$displayurl\E$/) {
+ $output .= ' - '.$displayurl;
+ }
+ }
+ if (exists($msg->{'symb'})) {
+ my $displaysymb=&Apache::lonnet::gettitle($msg->{'symb'});
+ if ($msg->{'symb'}!~/\Q$displaysymb\E$/) {
+ $output .= ' - '.$displaysymb;
+ }
+ }
+ $output .= ' ('.$msg->{'section'}.') ';
+ return $output;
+}
+
sub showday {
my ($tk,$mode,%allcal)=@_;
my %th=&Apache::loncommon::timehash($tk);
- my ($nextday,$nextmonth)=&nextday(%th);
- my $outp='';
+ my ($nextday,$nextmonth)=&nextday($tk,%th);
+ my @outp;
if ($mode) {
my $oneday=24*3600;
$tk-=$oneday;
$nextday+=$oneday;
}
foreach my $item (keys(%allcal)) {
- my ($course,$startdate,$enddate)=($item=~/^(\w+)\@(\d+)\_(\d+)$/);
- if (($startdate<$nextday) && ($enddate>=$tk)) {
- $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) {
return ($nextday,$nextmonth,&normalcell(
- $th{'day'},$th{'month'},$th{'year'},$outp));
- } elsif ($outp) {
+ $th{'day'},$th{'month'},$th{'year'},\@outp));
+ } elsif (@outp) {
if ($mode==1) {
- return ' '.&plaincell($outp);
+ return ' '.&plaincell(\@outp);
} else {
- return '
'.&listcell($outp).'
';
+ return '
'.&listcell(\@outp).'
';
}
} else {
return '';
}
}
-sub tfont {
- my $text=shift;
- if ($env{'form.pickdate'} eq 'yes') {
- return ''.$text.'';
- } else {
- return $text;
- }
-}
-
sub picklink {
my ($text,$day,$month,$year)=@_;
if ($env{'form.pickdate'} eq 'yes') {
@@ -325,9 +427,58 @@ function dialin(day,month,year) {
ENDDIA
}
+# ----------------------------------------------------- Summarize all calendars
+sub get_all_calendars {
+ my %allcal=();
+ my %courses = &Apache::loncommon::findallcourses();
+ foreach my $course (sort(keys(%courses))) {
+ %allcal=(%allcal,&readcalendar($course));
+ }
+ return %allcal;
+}
+
+sub output_ics_file {
+ my ($r)=@_;
+# RFC 2445 wants CRLF
+ my $crlf="\015\012";
+# Header
+ $r->print("BEGIN:VCALENDAR$crlf");
+ $r->print("VERSION:2.0$crlf");
+ $r->print("PRODID:-//LONCAPA//LONCAPA Calendar Output//EN$crlf");
+ my %allcal=&get_all_calendars();
+ foreach my $event (keys(%allcal)) {
+ my ($courseid,$startdate,$enddate)= split('\0',$event);
+ my $uid=$event;
+ $uid=~s/[\W\_]/-/gs;
+ $uid.='@loncapa';
+ my $summary=&display_msg($allcal{$event});
+ $summary=~s/\s+/ /gs;
+ $summary=$env{'course.'.$courseid.'.description'}.': '.$summary;
+ $r->print("BEGIN:VEVENT$crlf");
+ $r->print("DTSTART:".&Apache::loncommon::utc_string($startdate).$crlf);
+ $r->print("DTEND:".&Apache::loncommon::utc_string($enddate).$crlf);
+ $r->print("SUMMARY:$summary$crlf");
+ $r->print("UID:$uid$crlf");
+ $r->print("END:VEVENT$crlf");
+ }
+# Footer
+ $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)$/) {
+ &Apache::loncommon::content_type($r,'text/calendar');
+ &output_ics_file($r);
+ return OK;
+ }
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK if $r->header_only;
@@ -336,8 +487,7 @@ sub handler {
my $today=time;
%todayhash=&Apache::loncommon::timehash($today);
# ----------------------------------------------------------------- Check marks
- %showedcheck=();
- undef %showedcheck;
+ undef(%showedcheck);
# ---------------------------------------------------------- Get month and year
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['month','year','pickdate','formname','element']);
@@ -353,19 +503,18 @@ sub handler {
'&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 $html=&Apache::lonxml::xmlbegin();
- $r->print(<
-The LearningOnline Network with CAPA
-
-
ENDDOCUMENT
+
if ($pickdatemode) {
# no big header in pickdate mode
- $r->print(&Apache::loncommon::bodytag("Pick a Date",'','',1).
+ $r->print(&Apache::loncommon::start_page("Pick a Date",$js,
+ {'only_body' => 1,}).
&dialscript().
'');
} else {
- $r->print(&Apache::loncommon::bodytag("Announcements and Calendar"));
+ $r->print(&Apache::loncommon::start_page("Announcements and Calendar",
+ $js));
}
# does this user have privileges to post, etc?
my $allowed=0;
@@ -425,12 +576,14 @@ Post announcements to the system login a
Check machines:
SERVERANNOUNCE
# 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 (' current');
}
}
$r->print(
@@ -481,11 +634,7 @@ SERVERANNOUNCE
&editfield($r,$today,$tomorrow,'');
}
# ----------------------------------------------------- Summarize all calendars
- my %allcal=();
- foreach my $course (&Apache::loncommon::findallcourses()) {
- %allcal=(%allcal,&readcalendar($course));
- }
-
+ my %allcal=&get_all_calendars();
# ------------------------------- Initialize table and forward backward buttons
my ($pm,$py,$fm,$fy)=($month-1,$year,$month+1,$year);
if ($pm<1) { ($pm,$py)=(12,$year-1); }
@@ -496,14 +645,49 @@ SERVERANNOUNCE
&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('