# -------------------------------- # subroutine report_builder_export # -------------------------------- # initiated from report_builder include "templates.statistics.report_elements.util.table.get_sort_type"; include "templates.statistics.report_elements.util.set_filter_expression"; include "templates.statistics.report_elements.util.table.aggr_method_is_average"; include "templates.statistics.report_elements.util.table.get_average_denom_field"; include "templates.statistics.report_elements.util.table.get_average_denom_col_number"; include "templates.shared.util.convert_to_valid_node_name"; include "templates.shared.util.check_webserver_mode"; include "templates.shared.util.get_loganalysisinfo_dir"; subroutine(report_builder_export, ( # export_to_file is true if invoked from the user_agent (result is saved in a file) # export to_file is false if invoked from command_line (result is displayed in output stream) bool export_to_file = false; if (internal.task_originator eq "user_agent") then ( export_to_file = true; ); string profile_name = internal.profile_name; string profile_path = "profiles." . profile_name; string report_name = internal.report.report_name; node report_node = profile_path . ".statistics.reports." . report_name; string report_label = node_value(subnode_by_name(report_node, "label")); debug_message("EXPORT report name: " . report_name . "\n"); string report_element = internal.export.report_element; # if no report_element is defined then export the first report_element if (report_element eq "") then ( report_element = node_name(subnode_by_number(report_node . ".report_elements", 0)); ); debug_message("EXPORT report element: " . report_element . "\n"); node report_element_node = report_node . ".report_elements." . report_element; string report_element_type = node_value(subnode_by_name(report_element_node, "type")); debug_message("report element type: " . report_element_type . "\n\n"); # get report element label string report_element_label; if (subnode_exists(report_element_node, "label")) then ( report_element_label = node_value(subnode_by_name(report_element_node, "label")); ) else ( report_element_label = report_label; ); # ----------------------------------------------------------------------------------------------------- # SET PROGRESS FOR REPORT ELEMENT STEP (volatile.report_element_number = 0, +1 for each report element) # ----------------------------------------------------------------------------------------------------- # Required for C++ progress handling only! volatile.report_element_number = 0; if (export_to_file) then ( templates.shared.doctype; '\n'; '\n'; '' . lang_stats.export.label . '\n'; expand(templates.shared.content_type); '\n'; '\n'; '\n'; '\n'; '\n'; '\n'; '
\n'; '
\n'; '\n'; '\n'; '\n'; '\n'; '
\n'; '
\n'; ); # if export_to_file # ---------- # Set filter # ---------- set_filter_expression(report_name, report_element); # ----------------------------------------- # Query the database for the report-element # ----------------------------------------- if (node_exists("volatile.query_result")) then ( delete_node("volatile.query_result"); ); # debug_message("report element node: " . report_element_node . "\n"); query_db_for_view(report_element_node, "volatile.query_result"); string query_header = ("volatile.query_result.header"); string query_data = ("volatile.query_result.data"); # debug_message("query header: \n" . node_as_string(query_header) . "\n\n"); # debug_message("query data: \n" . node_as_string(query_data) . "\n\n"); # ----------------------------------------------- # Sort the query as in the report element display # ----------------------------------------------- string sort_field = ""; string sort_direction = ""; string sort_type; string sort_method; if (node_exists(report_element_node . ".sort_by") and (node_value(report_element_node . ".sort_by") ne "")) then ( sort_field = node_value(report_element_node . ".sort_by"); sort_direction = (if node_exists(report_element_node . ".sort_direction") then $(report_element_node . ".sort_direction") else "descending"); sort_type = get_sort_type(profile_name, sort_field); sort_method = "field:" . sort_field . "," . sort_type . "," . sort_direction; sort(query_data, sort_method); ); # -------------- # number of rows # -------------- int number_of_rows; # Note, due the huge amount a log_detail report doesn't show all records in the query_data node # The number of rows in log data depends of the current set ending_row, if set to 50, the 50 rows # will be in the query data. number_of_rows = num_subnodes(query_data); # debug_message("EXPORT number of rows query_data: " . number_of_rows); node row; node column; string main_field_node_name; string column_label; string column_type; string column_field_name; string column_field_type; string column_display_format_type; string column_value; int last_column_number = num_subnodes(query_header) - 1; int column_number; bool aggregation_method_is_average; string average_denominator_field; int average_denominator_column_number; bool contains_delimiter; bool contains_double_quote; string csv_contents = ""; # ------------- # csv_delimiter # ------------- string csv_delimiter = ","; if (node_exists(profile_path . ".statistics.miscellaneous.csv_delimiter")) then ( string dat = node_value(profile_path . ".statistics.miscellaneous.csv_delimiter"); if (dat ne "") then ( csv_delimiter = dat; ); ); int csv_delimiter_int = char_to_ascii(csv_delimiter); string csv_delimiter_in_hex = format(csv_delimiter_int, '%X'); csv_delimiter_in_hex = "%" . csv_delimiter_in_hex; debug_message("#### CSV delimiter: " . csv_delimiter . "\n"); debug_message("#### CSV delimiter in hex: " . csv_delimiter_in_hex . "\n"); # ---------- # CSV header # ---------- column_number = 0; foreach column query_header ( column_label = node_value(subnode_by_name(column, "header_label")); column_label = capitalize(expand(column_label)); if (column_number != last_column_number) then ( csv_contents .= column_label . csv_delimiter; ) else ( csv_contents .= column_label . "\n"; ); column_number++; ); # foreach column query_header # -------- # CSV data # -------- for (int row_number = 1; row_number <= number_of_rows; row_number++) ( # Get the query row node for this table row row = subnode_by_number(query_data, row_number - 1); # Loop through all table columns (query_header columns), and generate HTML columns column_number = 0; foreach column query_header ( column_type = node_value(subnode_by_name(column, "type")); column_field_name = node_value(subnode_by_name(column, "field_name")); column_field_type = node_value(subnode_by_name(column, "data_type")); column_value = node_value(subnode_by_name(row, column_field_name)); # ------------------ # Handle Aggregation # ------------------ if (column_type eq "number") then ( # ------------------ # Handle Aggregation # ------------------ # If aggregation method (read property from database field!) is of type average then get the # average_denominator_field and divide the columnvalue through the value of the average_denominator_field. aggregation_method_is_average = aggr_method_is_average(column_field_name, profile_name); if (aggregation_method_is_average) then ( average_denominator_field = get_average_denom_field(column_field_name, profile_name); column_value = column_value / node_value(subnode_by_name(row, average_denominator_field)); ); ); # ------------------------ # Decode __HexEsc__ values # ------------------------ if (contains(column_value, "__HexEsc__")) then ( column_value = replace_all(column_value, "__HexEsc__", "%"); ); # ---------------------------------- # Escape delimiter and double quotes # ---------------------------------- # debug_message("#### #### export value before escape: " . column_value . "\n"); contains_delimiter = contains(column_value, csv_delimiter_in_hex); contains_double_quote = contains(column_value, "%22"); if (contains_delimiter or contains_double_quote) then ( # enclose column_value with double quotes! column_value = '"' . column_value . '"'; # debug_message("#### #### escaped export value: " . column_value . "\n"); ); # ---------------- # Write csv string # ---------------- csv_contents .= column_value; if (column_number != last_column_number) then ( csv_contents .= csv_delimiter; ) else ( csv_contents .= "\n"; ); column_number++; ); # foreach column query_header ); # for rows if (export_to_file) then ( # ---------------------- # Get CSV directory path # ---------------------- string divider = "/"; string user_node_name = "none"; bool webserver_mode = check_webserver_mode(); if (node_exists("volatile.authenticated_user_node_path")) then ( user_node_name = node_name(volatile.authenticated_user_node_path); ); string csv_directory_path; string csv_sub_directory_path = "csv_export" . divider . user_node_name . divider . profile_name; if (webserver_mode) then ( string log_analysis_info_directory = get_loganalysisinfo_dir(); debug_message("#### log_analysis_info_directory: " . log_analysis_info_directory . "\n"); csv_directory_path = log_analysis_info_directory . "WebServerRoot" . divider . csv_sub_directory_path; ) else ( # cgi-mode csv_directory_path = node_value("preferences.server.temporary_directory_pathname"); if (!ends_with(csv_directory_path, divider)) then ( csv_directory_path .= divider; ); csv_directory_path .= csv_sub_directory_path; ); debug_message("#### csv_directory_path: " . csv_directory_path . "\n"); # ----------------- # Get csv_file_name # ----------------- # Make file names maximal 32 characters string report_part_of_file_name; string csv_filename; # int date_time_stamp_in_sec = now(); # debug_message("#### date_time_stamp_in_sec: " . date_time_stamp_in_sec . "\n"); if (report_name eq report_element) then ( # csv_filename = report_element . "_" . date_time_stamp_in_sec . ".csv"; report_part_of_file_name = report_element; ) else ( # csv_filename = report_name . "_" . report_element . "_" . date_time_stamp_in_sec . ".csv"; report_part_of_file_name = report_name . "_" . report_element; ); if (length(report_part_of_file_name) > 24) then ( report_part_of_file_name = substr(report_part_of_file_name, 0, 24); ); string csv_directory_path_with_filename; int count = 1; string file_number; bool is_unique_file_name = false; while (!is_unique_file_name) ( if (count > 99) then ( file_number = count; ) else if (count > 9) then ( file_number = "0" . count; ) else ( file_number = "00" . count; ); csv_filename = report_part_of_file_name . "_" . file_number . ".csv"; csv_directory_path_with_filename = csv_directory_path . "/" . csv_filename; if (!file_exists(csv_directory_path_with_filename)) then ( is_unique_file_name = true; ); count++; ); # debug_message("#### csv_filename: " . csv_filename . "\n"); # ---------- # Write file # ---------- csv_contents = convert_escapes(csv_contents); # If charset conversion is enabled, do the conversion now if (node_exists("profiles." . profile_name . ".output.convert_export_charset") and node_value("profiles." . profile_name . ".output.convert_export_charset")) then ( debug_message("Converted CSV export from " . output.convert_export_from_charset . " to " . output.convert_export_to_charset . "\n"); csv_contents = convert_charset(csv_contents, output.convert_export_from_charset, output.convert_export_to_charset); debug_message("Done converting CSV export\n"); ); write_file(csv_directory_path_with_filename, csv_contents); # ----------------- # Set download link # ----------------- string csv_export_path = "csv_export/" . user_node_name . "/" . profile_name . "/" . csv_filename; string download_href; if (webserver_mode) then ( # Note, this includes cgi-mode in case that # preferences.server.temporary_directory_url and # preferences.server.temporary_directory_pathname is empty! # This is the new cgi-mode! download_href = 'href=' . fileref(csv_export_path); ) else ( # cgi-mode (old, see above for new cgi-mode) string temporary_directory_url = node_value("preferences.server.temporary_directory_url"); if (!ends_with(temporary_directory_url, "/")) then ( temporary_directory_url .= "/"; ); download_href = 'href="' . temporary_directory_url . csv_export_path . '"'; ); debug_message("#### download_href: " . download_href . "\n"); '
\n'; '

' . lang_stats.export.data_exported_info . '

\n'; '

' . lang_stats.export.download_button . '

\n'; '
\n'; '
\n'; '\n'; '\n'; ) # if export_to_file else ( # --------------------- # Display output_stream # --------------------- # Save CSV data in a node, the value of the node becomes the output_stream in report_setup.cvf string csv_data_node_name = node_value("internal.export.csv_data_node_name"); ("IPC." . csv_data_node_name) = convert_escapes(csv_contents); save_node("IPC." . csv_data_node_name); ); ));