Skip to content

Commit

Permalink
Merge pull request #3700 from meeting-room-booking-system/3692-batch-…
Browse files Browse the repository at this point in the history
…exporting-bookings-as-ics-format

3692 batch exporting bookings as ics format
  • Loading branch information
campbell-m authored Jul 20, 2024
2 parents 9673264 + 8a89a82 commit 8f7306f
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 11 deletions.
65 changes: 65 additions & 0 deletions web/js/search.js.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,71 @@
<?php // Get the types and feed those into dataTables ?>
tableOptions.columnDefs = getTypes(table);

tableOptions.buttons = [
{
<?php // The first button is assumed to be the colvis button ?>
extend: 'colvis'
},
{
<?php
// Add in an extra button to export the results as an iCalendar (.ics) file.
?>
text: '<?php echo escape_js(get_vocab('export_as_ics')) ?>',
action: function (e, dt, node, config) {
<?php // Get the form data, which will already include a CSRF token ?>
var data = $('#search_form').serializeArray();
<?php // Add in a parameter to tell the server we want an iCalendar export ?>
data.push({name: 'ics', value: 1});
$.post({
url: window.location.href,
data: data,
success: function(blob, status, xhr) {
<?php
// See https://stackoverflow.com/questions/16086162/handle-file-download-from-ajax-post
?>
var contentType = xhr.getResponseHeader('Content-Type');
var contentTypeRegex = /^[^;]*/;
var matches = contentType.match(contentTypeRegex);
var type = (matches === null) ? '' : matches[0];
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}

if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(new Blob([blob], {type: type}));

if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location.href = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location.href = downloadUrl;
}

setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
});
}
}
]

makeDataTable('#search_results', tableOptions, {"leftColumns": 1});
}

Expand Down
1 change: 1 addition & 0 deletions web/lang/lang.en
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ $vocab["entry"] = "Entry";
$vocab["search_button"] = "Search";
$vocab["search_for"] = "Search for";
$vocab["from"] = "From";
$vocab["export_as_ics"] = ".ics";

// Used in report.php
$vocab["report_on"] = "Report on Meetings";
Expand Down
37 changes: 26 additions & 11 deletions web/search.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function output_row($row, $returl)
{
global $is_ajax, $json_data, $view;

$vars = array('id' => $row['entry_id'],
$vars = array('id' => $row['id'],
'returl' => $returl);

$query = http_build_query($vars, '', '&');
Expand Down Expand Up @@ -125,7 +125,7 @@ function output_row($row, $returl)
$search_pos = get_form_var('search_pos', 'int');
$total = get_form_var('total', 'int');
$datatable = get_form_var('datatable', 'int'); // Will only be set if we're using DataTables
// Get the start day/month/year and make them the current day/month/year
$ics = get_form_var('ics', 'bool', false);
$from_date = get_form_var('from_date', 'string');

// If we're going to be doing something then check the CSRF token
Expand Down Expand Up @@ -166,7 +166,7 @@ function output_row($row, $returl)
}
}

if (!$is_ajax) {
if (!($is_ajax || $ics)) {
$context = array(
'view' => $view,
'view_all' => $view_all,
Expand Down Expand Up @@ -336,7 +336,7 @@ function output_row($row, $returl)
$total = db()->query1($sql, $sql_params);
}

if (($total <= 0) && !$is_ajax)
if (($total <= 0) && !($is_ajax || $ics))
{
echo "<p id=\"nothing_found\">" . get_vocab("nothing_found") . "</p>\n";
print_footer();
Expand All @@ -355,21 +355,22 @@ function output_row($row, $returl)
// If we're Ajax capable and this is not an Ajax request then don't output
// the table body, because that's going to be sent later in response to
// an Ajax request - so we don't need to do the query
if (!$ajax_capable || $is_ajax)
if (!$ajax_capable || $is_ajax || $ics)
{
// Now we set up the "real" query
$sql = "SELECT E.id AS entry_id, E.create_by, E.name, E.description, E.start_time,
E.room_id, R.area_id, A.enable_periods
$sql = "SELECT E.*, " .
db()->syntax_timestamp_to_unix("E.timestamp") . " AS last_updated, " .
"A.area_name, R.room_name, R.area_id, A.enable_periods
FROM " . _tbl('entry') . " E
LEFT JOIN " . _tbl('room') . " R
ON E.room_id = R.id
LEFT JOIN " . _tbl('area') . " A
ON R.area_id = A.id
WHERE $sql_pred
ORDER BY E.start_time asc";
// If it's an Ajax query we want everything. Otherwise we use LIMIT to just get
// If it's an Ajax query or an ics export we want everything. Otherwise we use LIMIT to just get
// the stuff we want.
if (!$is_ajax)
if (!($is_ajax || $ics))
{
$sql .= " " . db()->syntax_limit($search["count"], $search_pos);
}
Expand All @@ -379,12 +380,12 @@ function output_row($row, $returl)
$num_records = $result->count();
}

if (!$ajax_capable)
if (!($ajax_capable || $ics))
{
echo generate_search_nav_html($search_pos, $total, $num_records, $search_str);
}

if (!$is_ajax)
if (!($is_ajax || $ics))
{
echo "<div id=\"search_output\" class=\"datatable_container\">\n";
echo "<table id=\"search_results\" class=\"admin_table display\"";
Expand All @@ -409,6 +410,20 @@ function output_row($row, $returl)
echo "<tbody>\n";
}

if ($ics)
{
$filename = "$search_filename.ics";
$content_type = "application/ics; charset=" . get_charset() . "; name=\"$filename\"";
http_headers(array(
"Content-Type: $content_type",
"Content-Disposition: attachment; filename=\"$filename\"")
);
// We set $keep_private to FALSE here because we excluded all private
// events in the SQL query
export_icalendar($result, false);
exit;
}

// If we're Ajax capable and this is not an Ajax request then don't output
// the table body, because that's going to be sent later in response to
// an Ajax request
Expand Down
1 change: 1 addition & 0 deletions web/systemdefaults.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -1860,6 +1860,7 @@

// Default file names
$report_filename = "report";
$search_filename = "search";
$summary_filename = "summary";

// CSV format
Expand Down

0 comments on commit 8f7306f

Please sign in to comment.