Revision: 1718
          http://mrbs.svn.sourceforge.net/mrbs/?rev=1718&view=rev
Author:   cimorrison
Date:     2010-12-20 16:17:58 +0000 (Mon, 20 Dec 2010)

Log Message:
-----------
Added an "Export as iCalendar" option to the Report page.   Doesn't do Periods 
and doesn't yet do custom fields.

Modified Paths:
--------------
    mrbs/branches/ics_attachments/web/functions_ical.inc
    mrbs/branches/ics_attachments/web/lang.en
    mrbs/branches/ics_attachments/web/mrbs.css.php
    mrbs/branches/ics_attachments/web/report.php

Modified: mrbs/branches/ics_attachments/web/functions_ical.inc
===================================================================
--- mrbs/branches/ics_attachments/web/functions_ical.inc        2010-12-20 
15:50:44 UTC (rev 1717)
+++ mrbs/branches/ics_attachments/web/functions_ical.inc        2010-12-20 
16:17:58 UTC (rev 1718)
@@ -185,7 +185,7 @@
   $results[] = "LOCATION:" . ical_escape_text($data['area_name'] . " - " . 
$data['room_name']);
   $results[] = "SEQUENCE:" . $data['ical_sequence'];
   // If this is an individual member of a series then set the recurrence id
-  if ($data['entry_type'] == ENTRY_RPT_CHANGED)
+  if (!$series && ($data['entry_type'] == ENTRY_RPT_CHANGED))
   {
     $results[] = "RECURRENCE-ID:" . $data['ical_recur_id'];
   }

Modified: mrbs/branches/ics_attachments/web/lang.en
===================================================================
--- mrbs/branches/ics_attachments/web/lang.en   2010-12-20 15:50:44 UTC (rev 
1717)
+++ mrbs/branches/ics_attachments/web/lang.en   2010-12-20 16:17:58 UTC (rev 
1718)
@@ -266,6 +266,7 @@
 $vocab["report_and_summary"]    = "Report and Summary";
 $vocab["report_as_csv"]         = "Report as CSV";
 $vocab["summary_as_csv"]        = "Summary as CSV";
+$vocab["report_as_ical"]        = "Report as iCalendar (.ics file) - excluding 
periods";
 $vocab["summarize_by"]          = "Summarize by";
 $vocab["sum_by_descrip"]        = "Brief description";
 $vocab["sum_by_creator"]        = "Creator";
@@ -285,7 +286,7 @@
 $vocab["both"]                  = "All";
 $vocab["privacy_status"]        = "Privacy status";
 $vocab["search_criteria"]       = "Search criteria";
-$vocab["presentation_options"]  = "Presentation options";
+$vocab["presentation_options"]  = "Output options";
 
 // Used in week.php
 $vocab["weekbefore"]         = "Go To Week Before";

Modified: mrbs/branches/ics_attachments/web/mrbs.css.php
===================================================================
--- mrbs/branches/ics_attachments/web/mrbs.css.php      2010-12-20 15:50:44 UTC 
(rev 1717)
+++ mrbs/branches/ics_attachments/web/mrbs.css.php      2010-12-20 16:17:58 UTC 
(rev 1718)
@@ -532,6 +532,8 @@
 .form_general div {float: left; clear: left; width: 100%}
 .form_general div div {float: none; clear: none; width: auto}
 .form_general div.group {float: left}
+.form_general div.group_container {float: left}
+.form_general .group_container div.group {clear: left}
 .form_general div.group.ampm {width: <?php echo $edit_entry_ampm_width ?>em}
 .edit_area_room div.group {clear: none; width: auto}
 .edit_area_room div.group#private_override div {clear: left}

Modified: mrbs/branches/ics_attachments/web/report.php
===================================================================
--- mrbs/branches/ics_attachments/web/report.php        2010-12-20 15:50:44 UTC 
(rev 1717)
+++ mrbs/branches/ics_attachments/web/report.php        2010-12-20 16:17:58 UTC 
(rev 1718)
@@ -6,9 +6,13 @@
 // Constant definitions for the value of the summarize parameter.   These are 
used
 // for bit-wise comparisons.    For example summarize=3 means produce both
 // a report and a summary; summaraize=5 means produce a report as a CSV file
-define('REPORT',  01);
-define('SUMMARY', 02);
-define('CSV',     04);
+define('REPORT',      0x01);
+define('SUMMARY',     0x02);
+// a series of constants defining the ouput format.   These are in the same
+// bit series as the output contents above, though not all combinations are 
sensible
+define('OUTPUT_HTML', 0x04);
+define('OUTPUT_CSV',  0x08);
+define('OUTPUT_ICAL', 0x10);
 
 // Constants for booking privacy matching
 define('PRIVATE_NO',   0);
@@ -26,7 +30,6 @@
 define('APPROVED_BOTH', 2);  // Can be anything other than 0 or 1
 
 
-
 function date_time_string($t)
 {
   global $twentyfourhour_format;
@@ -273,7 +276,7 @@
   
     echo "<div class=\"report_entry_name\">\n";
     // Brief Description (title), linked to view_entry:
-    echo "<a href=\"view_entry.php?id=".$row['entry_id']."\">" . 
htmlspecialchars($row['name']) . "</a>\n";
+    echo "<a href=\"view_entry.php?id=".$row['id']."\">" . 
htmlspecialchars($row['name']) . "</a>\n";
     echo "</div>\n";
   }
   echo $output_as_csv ? '' : "<div class=\"report_entry_when\">\n";
@@ -679,10 +682,12 @@
 
 if (empty($summarize))
 {
-  $summarize = REPORT;
+  $summarize = REPORT + OUTPUT_HTML;
 }
 
-$output_as_csv = $summarize & CSV;
+$output_as_html = (!isset($summarize)) || ($summarize & OUTPUT_HTML);
+$output_as_csv = $summarize & OUTPUT_CSV;
+$output_as_ical = $summarize & OUTPUT_ICAL;
 
 // Get information about custom fields
 $fields = sql_field_info($tbl_entry);
@@ -722,8 +727,14 @@
   header("Content-Type: text/csv; charset=" . get_charset());
   header("Content-Disposition: attachment; filename=\"$filename\"");
 }
-else
+elseif ($output_as_ical)
 {
+  require_once "functions_ical.inc";
+  header("Content-Type: application/ics;  charset=" . get_charset(). "; 
name=\"" . $mail_settings['ics_filename'] . ".ics\"");
+  header("Content-Disposition: attachment; filename=\"" . 
$mail_settings['ics_filename'] . ".ics\"");
+}
+else // assumed to be $output_as_html
+{
   print_header($day, $month, $year, $area, isset($room) ? $room : "");
 }
 
@@ -781,9 +792,10 @@
 $private_somewhere = some_area('private_enabled') || 
some_area('private_mandatory');
 $approval_somewhere = some_area('approval_enabled');
 $confirmation_somewhere = some_area('confirmation_enabled');
+$times_somewhere = (sql_query1("SELECT COUNT(*) FROM $tbl_area WHERE 
enable_periods=0") > 0);
 
 // Upper part: The form.
-if (!$output_as_csv)
+if ($output_as_html)
 {
   ?>
   <div class="screenonly">
@@ -948,17 +960,30 @@
         <legend><?php echo get_vocab("presentation_options");?></legend>  
         <div id="div_summarize">
           <label><?php echo get_vocab("include");?>:</label>
-          <div class="group">
-            <?php
-            // Radio buttons to choose the value of the summarize parameter
-            // Set up an array mapping the button value to the description
-            $buttons = array(REPORT         => "report_only",
-                             SUMMARY        => "summary_only",
-                             REPORT+SUMMARY => "report_and_summary",
-                             REPORT+CSV     => "report_as_csv",
-                             SUMMARY+CSV    => "summary_as_csv");
+          <?php
+          // Radio buttons to choose the value of the summarize parameter
+          // Set up an array of arrays mapping the button value to the 
description
+          // Each outer array represents a different group of buttons
+          $buttons = array();
+          // The HTML output buttons
+          $buttons[] = array(REPORT + OUTPUT_HTML           => "report_only",
+                             SUMMARY + OUTPUT_HTML          => "summary_only",
+                             REPORT + SUMMARY + OUTPUT_HTML => 
"report_and_summary");
+          // The CSV output buttons
+          $buttons[] = array(REPORT + OUTPUT_CSV            => "report_as_csv",
+                             SUMMARY + OUTPUT_CSV           => 
"summary_as_csv");
+          // The iCal output button
+          if ($times_somewhere) // We can't do iCalendars for periods yet
+          {
+            $buttons[] = array(REPORT + OUTPUT_ICAL           => 
"report_as_ical");
+          }
+          
+          echo "<div class=\"group_container\">\n";
+          foreach ($buttons as $button_group)
+          {
+            echo "<div class=\"group\">\n";
             // Output each radio button
-            foreach ($buttons as $value => $token)
+            foreach ($button_group as $value => $token)
             {
               echo "<label>";
               echo "<input class=\"radio\" type=\"radio\" name=\"summarize\" 
value=\"$value\"";          
@@ -966,8 +991,10 @@
               echo ">" . get_vocab($token);
               echo "</label>\n";
             }
-            ?>
-          </div>
+            echo "</div>\n";
+          }
+          echo "</div>\n";
+          ?>
         </div>
       
         <div id="div_sortby"> 
@@ -1046,21 +1073,31 @@
   $report_end = mktime(0, 0, 0, $To_month+0, $To_day+1, $To_year+0);
   
   // Construct the SQL query
-  $sql = "SELECT E.id AS entry_id, E.start_time, E.end_time, E.name, 
E.description, "
-       . "E.type, E.create_by, E.status, "
+  $sql = "SELECT E.*, "
        .  sql_syntax_timestamp_to_unix("E.timestamp") . " AS last_updated, "
        . "A.area_name, R.room_name, "
        . "A.approval_enabled, A.confirmation_enabled";
-  // Get any custom fields
-  foreach ($custom_fields as $custom_field => $value)
+  if ($output_as_ical)
   {
-    $sql .= ", E.$custom_field";
+    // If we're producing an iCalendar then we'll also need the repeat
+    // information in order to construct the recurrence rule
+    $sql .= ", T.rep_type, T.end_date, T.rep_opt, T.rep_num_weeks";
   }
-
-  $sql .= " FROM $tbl_entry E, $tbl_area A, $tbl_room R"
-        . " WHERE E.room_id = R.id AND R.area_id = A.id"
+  $sql .= " FROM $tbl_area A, $tbl_room R, $tbl_entry E";
+  if ($output_as_ical)
+  {
+    // We do a LEFT JOIN because we still want the single entries, ie the ones
+    // that won't have a match in the repeat table
+    $sql .= " LEFT JOIN $tbl_repeat T ON E.repeat_id=T.id";
+  }
+  $sql .= " WHERE E.room_id=R.id AND R.area_id=A.id"
         . " AND E.start_time < $report_end AND E.end_time > $report_start";
-
+  if ($output_as_ical)
+  {
+    // We can't export periods in an iCalendar yet
+    $sql .= " AND A.enable_periods=0";
+  }
+  
   if (!empty($areamatch))
   {
     // sql_syntax_caseless_contains() does the SQL escaping
@@ -1187,9 +1224,15 @@
                      (A.private_override='none' AND (E.status&" . 
STATUS_PRIVATE . "=0)))";
     }
   }
-   
-  if ( $sortby == "r" )
+  
+  if ($summarize & OUTPUT_ICAL)
   {
+    // If we're producing an iCalendar then we'll want the entries ordered by
+    // repeat_id and then recurrence_id
+    $sql .= " ORDER BY repeat_id, ical_recur_id";
+  }
+  elseif ($sortby == "r")
+  {
     // Order by Area, Room, Start date/time
     $sql .= " ORDER BY area_name, sort_key, start_time";
   }
@@ -1216,7 +1259,7 @@
   {
     $last_area_room = "";
     $last_date = "";
-    if (!$output_as_csv)
+    if ($output_as_html)
     {
       echo "<p class=\"report_entries\">" . $nmatch . " "
       . ($nmatch == 1 ? get_vocab("entry_found") : get_vocab("entries_found"))
@@ -1228,12 +1271,91 @@
     {
       csv_report_header($display);
     }
+    
+    if ($output_as_ical)
+    {
+      // If we're producing an iCalendar then initialize an array to hold the 
events
+      // and a variable to keep track of the last repeat id we've seen
+      $ical_events = array();
+      $last_repeat_id = 0;
+    }
 
     for ($i = 0; ($row = sql_row_keyed($res, $i)); $i++)
     {
       if ($summarize & REPORT)
       {
-        reporton($row, $last_area_room, $last_date, $sortby, $display);
+        if ($output_as_ical)
+        {
+          $text_body = array();
+          $html_body = array();
+          // If this is an individual entry, then construct an event
+          if ($row['repeat_id'] == 0)
+          {
+            $text_body['content'] = $row['description'];
+            $ical_events[] = create_ical_event("REQUEST", $row, $text_body, 
$html_body, NULL, FALSE);
+          }
+          // Otherwise it's a series
+          else
+          {
+            // if it's a series that we haven't seen yet, then construct an 
event
+            if ($row['repeat_id'] != $last_repeat_id)
+            {
+              $last_repeat_id = $row['repeat_id'];
+              // We need to set the repeat start and end dates because we've 
only been
+              // asked to export dates in the report range.  The end date will 
be the
+              // report end date.  The start date of the series will be the 
recurrence-id
+              // of the first entry in the series, which is this one thanks to 
the
+              // SQL query which ordered the entries by recurrence-id.
+              $start_row = $row;  // Make a copy of the data because we are 
going to tweak it.
+              $start_row['end_date'] = $report_end;
+              $duration = $start_row['end_time'] - $start_row['start_time'];
+              $start_row['start_time'] = strtotime($row['ical_recur_id']);
+              $start_row['end_time'] = $start_row['start_time'] + $duration;
+              // However, if this is a series member that has been changed, 
then we 
+              // cannot trust the rest of the data (eg the description).   We 
will
+              // use this data for now in case we don't get anything better, 
but we
+              // will make a note that we really need an unchanged member of 
the series, 
+              // which will have the correct data for the series which we can 
use to
+              // replace this event.
+              if ($row['entry_type'] == ENTRY_RPT_CHANGED)
+              {
+                // Record the index number of the event that needs to be 
replaced.
+                // As we have not yet added that event to the array, it will be
+                // the current length of the array.
+                $replace_index = count($ical_events);
+              }
+              $text_body['content'] = $start_row['description'];
+              $ical_events[] = create_ical_event("REQUEST", $start_row, 
$text_body, $html_body, NULL, TRUE);
+            }
+            // And if it's a series member that has been altered
+            if ($row['entry_type'] == ENTRY_RPT_CHANGED)
+            {
+              $text_body['content'] = $row['description'];
+              $ical_events[] = create_ical_event("REQUEST", $row, $text_body, 
$html_body, NULL, FALSE);
+            }
+            // Otherwise it must be an original member, in which case check
+            // to see if we were looking out for one
+            elseif (isset($replace_index))
+            {
+              // Use this row to define the sequence as it has got all the 
original
+              // data, except that we need to change the start and end times, 
keeping
+              // the original duration.   We get the start time from the 
recurrence
+              // id of the first member of the series, which we saved earlier 
on.
+              $duration = $row['end_time'] - $row['start_time'];
+              $row['start_time'] = $start_row['start_time'];
+              $row['end_time'] = $row['start_time'] + $duration;
+              $row['end_date'] = $report_end;
+              $text_body['content'] = $row['description'];
+              $ical_events[$replace_index] = create_ical_event("REQUEST", 
$row, $text_body, $html_body, NULL, TRUE);
+              // Clear the $replace_index now that we've found an original 
entry
+              unset ($replace_index);
+            }
+          }
+        }
+        else
+        {
+          reporton($row, $last_area_room, $last_date, $sortby, $display);
+        }
       }
 
       if ($summarize & SUMMARY)
@@ -1246,6 +1368,15 @@
           );
       }
     }
+    
+    if ($output_as_ical)
+    {
+      // Build the iCalendar from the array of events and output it
+      $icalendar = create_icalendar("REQUEST", $ical_events);
+      echo $icalendar;
+      exit;
+    }
+    
     if ($summarize & SUMMARY)
     {
       do_summary($count, $hours, $room_hash, $name_hash);
@@ -1253,7 +1384,7 @@
   }
 }
 
-if (!$output_as_csv)
+if ($output_as_html)
 {
   require_once "trailer.inc";
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits

Reply via email to