Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3692 batch exporting bookings as ics format #3700

Merged
merged 10 commits into from
Jul 20, 2024
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
Loading