blazer 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecc87353b5a9b96402e82c59b497929b5544f320d6c9f82316b92d005c18f74d
4
- data.tar.gz: 19b1a0697e3901e25c8b77f2ce769d427849c97f8012240fdce26a74f069c03d
3
+ metadata.gz: 160f3a7275160ebbeb9446cfacbe2c24d7882820f3548e10239cfdf383b3af87
4
+ data.tar.gz: 809bb498a6c00217e10239f87352c3051b3bb95d956910aa8f39a610e6adf58d
5
5
  SHA512:
6
- metadata.gz: c090577a5e80ac9ae9a870e096d1317b78cd7815fb6f9e65a1e59bb41fb779d2cbac6f37ec3cb3854351069d57b52b5937fa7cb1e0a85d73919ee59229501d8a
7
- data.tar.gz: 1590b68605c634a98a3ee4794eae49c5b19b9d683ff453871117983684e70c3b0c3222298e63a312719b9a676aa3d364a56dcc1664c10c2146800736103e4638
6
+ metadata.gz: 81ad8488e41e590d3deba688200ec253f3d1f42c00794ce4c6819aa9c9e765d54b692f1172116a30d098877d80a2c07c38814adef07650ac6d56c1bd605d79cc
7
+ data.tar.gz: 88917858d1aea93202f411f5becd420e49d71b6619fd91cd5580760fbb0a5a8c9bdc8eb0fc604264effd9334ca78d9d111d3bd42067d1b7e1eb5bc8e35562e4e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 3.0.4 (2024-09-04)
2
+
3
+ - Improved CSP support
4
+ - Fixed error with Trilogy and Rails 7.2
5
+
1
6
  ## 3.0.3 (2024-01-10)
2
7
 
3
8
  - Fixed error with Trilogy, non-ASCII column names, and charts
data/README.md CHANGED
@@ -1026,51 +1026,6 @@ override_csp: true
1026
1026
 
1027
1027
  Maps now use Mapbox GL JS v1 instead of Mapbox.js, which affects Mapbox billing.
1028
1028
 
1029
- ### 2.6
1030
-
1031
- Custom adapters now need to specify how to quote variables in queries (there is no longer a default)
1032
-
1033
- ```ruby
1034
- class FooAdapter < Blazer::Adapters::BaseAdapter
1035
- def quoting
1036
- :backslash_escape # single quote strings and convert ' to \' and \ to \\
1037
- # or
1038
- :single_quote_escape # single quote strings and convert ' to ''
1039
- # or
1040
- ->(value) { ... } # custom method
1041
- end
1042
- end
1043
- ```
1044
-
1045
- ### 2.3
1046
-
1047
- To archive queries, create a migration
1048
-
1049
- ```sh
1050
- rails g migration add_status_to_blazer_queries
1051
- ```
1052
-
1053
- with:
1054
-
1055
- ```ruby
1056
- add_column :blazer_queries, :status, :string
1057
- Blazer::Query.update_all(status: "active")
1058
- ```
1059
-
1060
- ### 2.0
1061
-
1062
- To use Slack notifications, create a migration
1063
-
1064
- ```sh
1065
- rails g migration add_slack_channels_to_blazer_checks
1066
- ```
1067
-
1068
- with:
1069
-
1070
- ```ruby
1071
- add_column :blazer_checks, :slack_channels, :text
1072
- ```
1073
-
1074
1029
  ## History
1075
1030
 
1076
1031
  View the [changelog](https://github.com/ankane/blazer/blob/master/CHANGELOG.md)
@@ -71,9 +71,9 @@ module Blazer
71
71
  if smart_var_data_source
72
72
  query = smart_var_data_source.smart_variables[var]
73
73
 
74
- if query.is_a? Hash
75
- smart_var = query.map { |k,v| [v, k] }
76
- elsif query.is_a? Array
74
+ if query.is_a?(Hash)
75
+ smart_var = query.map { |k, v| [v, k] }
76
+ elsif query.is_a?(Array)
77
77
  smart_var = query.map { |v| [v, v] }
78
78
  elsif query
79
79
  result = smart_var_data_source.run_statement(query)
@@ -1,6 +1,6 @@
1
1
  <% if @bind_vars.any? %>
2
2
  <% var_params = request.query_parameters %>
3
- <script>
3
+ <%= javascript_tag nonce: true do %>
4
4
  <%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
5
5
  var now = moment.tz(timeZone)
6
6
  var format = "YYYY-MM-DD"
@@ -8,7 +8,7 @@
8
8
  function toDate(time) {
9
9
  return moment.tz(time.format(format), timeZone)
10
10
  }
11
- </script>
11
+ <% end %>
12
12
  <form id="bind" method="get" action="<%= action %>" class="form-inline" style="margin-bottom: 15px;">
13
13
  <% date_vars = ["start_time", "end_time"] %>
14
14
  <% if (date_vars - @bind_vars).empty? %>
@@ -21,11 +21,11 @@
21
21
  <%= label_tag var, var %>
22
22
  <% if (data = @smart_vars[var]) %>
23
23
  <%= select_tag var, options_for_select([[nil, nil]] + data, selected: var_params[var]), style: "margin-right: 20px; width: 200px; display: none;" %>
24
- <script>
24
+ <%= javascript_tag nonce: true do %>
25
25
  $("#<%= var %>").selectize({
26
26
  create: true
27
27
  });
28
- </script>
28
+ <% end %>
29
29
  <% elsif var.end_with?("_at") || var == "start_time" || var == "end_time" %>
30
30
  <%= hidden_field_tag var, var_params[var] %>
31
31
 
@@ -35,7 +35,7 @@
35
35
  </div>
36
36
  </div>
37
37
 
38
- <script>
38
+ <%= javascript_tag nonce: true do %>
39
39
  (function() {
40
40
  var input = $("#<%= var %>")
41
41
  var datePicker = $("#<%= var %>-select")
@@ -57,7 +57,7 @@
57
57
  datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
58
58
  }
59
59
  })()
60
- </script>
60
+ <% end %>
61
61
  <% else %>
62
62
  <%= text_field_tag var, var_params[var], style: "width: 120px; margin-right: 20px;", autofocus: i == 0 && !var.end_with?("_at") && !var_params[var], class: "form-control" %>
63
63
  <% end %>
@@ -75,7 +75,7 @@
75
75
  </div>
76
76
  </div>
77
77
 
78
- <script>
78
+ <%= javascript_tag nonce: true do %>
79
79
  function dateStr(daysAgo) {
80
80
  return now.clone().subtract(daysAgo || 0, "days").format(format)
81
81
  }
@@ -119,7 +119,7 @@
119
119
  $("#reportrange").trigger("apply.daterangepicker", picker)
120
120
  submitIfCompleted($("#start_time").closest("form"))
121
121
  }
122
- </script>
122
+ <% end %>
123
123
  <% end %>
124
124
 
125
125
  <input type="submit" class="btn btn-success" value="Run" style="vertical-align: top;" />
@@ -12,12 +12,12 @@
12
12
  <div class="hide">
13
13
  <%= f.select :query_id, [], {include_blank: true} %>
14
14
  </div>
15
- <script>
15
+ <%= javascript_tag nonce: true do %>
16
16
  <%= blazer_js_var "queries", Blazer::Query.active.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
17
17
  <%= blazer_js_var "items", [@check.query_id].compact %>
18
18
 
19
19
  $("#check_query_id").selectize({options: queries, items: items, highlight: false, maxOptions: 100}).parents(".hide").removeClass("hide");
20
- </script>
20
+ <% end %>
21
21
  </div>
22
22
 
23
23
  <% if @check.respond_to?(:check_type) %>
@@ -28,9 +28,9 @@
28
28
  <% check_options << ["Anomaly (most recent data point)", "anomaly"] if Blazer.anomaly_checks %>
29
29
  <%= f.select :check_type, check_options %>
30
30
  </div>
31
- <script>
31
+ <%= javascript_tag nonce: true do %>
32
32
  $("#check_check_type").selectize({}).parent().removeClass("hide");
33
- </script>
33
+ <% end %>
34
34
  </div>
35
35
  <% elsif @check.respond_to?(:invert) %>
36
36
  <div class="form-group">
@@ -38,9 +38,9 @@
38
38
  <div class="hide">
39
39
  <%= f.select :invert, [["Any results (bad data)", false], ["No results (missing data)", true]] %>
40
40
  </div>
41
- <script>
41
+ <%= javascript_tag nonce: true do %>
42
42
  $("#check_invert").selectize({}).parent().removeClass("hide");
43
- </script>
43
+ <% end %>
44
44
  </div>
45
45
  <% end %>
46
46
 
@@ -50,9 +50,9 @@
50
50
  <div class="hide">
51
51
  <%= f.select :schedule, Blazer.check_schedules.map { |v| [v, v] } %>
52
52
  </div>
53
- <script>
53
+ <%= javascript_tag nonce: true do %>
54
54
  $("#check_schedule").selectize({}).parent().removeClass("hide");
55
- </script>
55
+ <% end %>
56
56
  </div>
57
57
  <% end %>
58
58
 
@@ -62,11 +62,11 @@
62
62
  </tbody>
63
63
  </table>
64
64
 
65
- <script>
65
+ <%= javascript_tag nonce: true do %>
66
66
  $("#search").on("keyup", function() {
67
67
  var value = $(this).val().toLowerCase()
68
68
  $("#checks tbody tr").filter( function() {
69
69
  $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
70
70
  })
71
71
  }).focus()
72
- </script>
72
+ <% end %>
@@ -30,7 +30,7 @@
30
30
  </p>
31
31
  <% end %>
32
32
 
33
- <script>
33
+ <%= javascript_tag nonce: true do %>
34
34
  <%= blazer_js_var "queries", Blazer::Query.active.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
35
35
  <%= blazer_js_var "dashboardQueries", @queries || @dashboard.dashboard_queries.order(:position).map(&:query) %>
36
36
 
@@ -79,4 +79,4 @@
79
79
  app.queries.splice(e.newIndex, 0, app.queries.splice(e.oldIndex, 1)[0])
80
80
  }
81
81
  })
82
- </script>
82
+ <% end %>
@@ -38,7 +38,7 @@
38
38
  <p class="text-muted">Loading...</p>
39
39
  </div>
40
40
  </div>
41
- <script>
41
+ <%= javascript_tag nonce: true do %>
42
42
  <% data = {statement: query.statement, query_id: query.id, data_source: query.data_source, variables: variable_params(query), only_chart: true} %>
43
43
  <% data.merge!(cohort_period: params[:cohort_period]) if params[:cohort_period] %>
44
44
  <%= blazer_js_var "data", data %>
@@ -49,5 +49,5 @@
49
49
  }, function (message) {
50
50
  $("#chart-<%= i %>").addClass("query-error").html(message)
51
51
  });
52
- </script>
52
+ <% end %>
53
53
  <% end %>
@@ -68,7 +68,7 @@
68
68
  </div>
69
69
  </div>
70
70
 
71
- <script>
71
+ <%= javascript_tag nonce: true do %>
72
72
  <%= blazer_js_var "variableParams", @variable_params %>
73
73
  <%= blazer_js_var "previewStatement", Blazer.data_sources.to_h { |k, v| [k, (v.preview_statement rescue "")] } %>
74
74
 
@@ -252,4 +252,4 @@
252
252
  })
253
253
  app.config.compilerOptions.whitespace = "preserve"
254
254
  app.mount("#app")
255
- </script>
255
+ <% end %>
@@ -56,7 +56,7 @@
56
56
  <p v-if="more" class="text-muted">Loading...</p>
57
57
  </div>
58
58
 
59
- <script>
59
+ <%= javascript_tag nonce: true do %>
60
60
  <%= blazer_js_var "dashboards", @dashboards %>
61
61
  <%= blazer_js_var "queries", @queries %>
62
62
  <%= blazer_js_var "more", @more %>
@@ -166,4 +166,4 @@
166
166
  })
167
167
  app.config.compilerOptions.whitespace = "preserve"
168
168
  app.mount("#queries")
169
- </script>
169
+ <% end %>
@@ -75,21 +75,21 @@
75
75
  <% if @markers.any? %>
76
76
  <% map_id = SecureRandom.hex %>
77
77
  <%= content_tag :div, nil, id: map_id, style: "height: #{@only_chart ? 300 : 500}px;" %>
78
- <script>
78
+ <%= javascript_tag nonce: true do %>
79
79
  <%= blazer_js_var "mapboxAccessToken", Blazer.mapbox_access_token %>
80
80
  <%= blazer_js_var "markers", @markers %>
81
81
  <%= blazer_js_var "mapId", map_id %>
82
82
  new Mapkick.Map(mapId, markers, {accessToken: mapboxAccessToken, tooltips: {hover: false, html: true}});
83
- </script>
83
+ <% end %>
84
84
  <% elsif @geojson.any? %>
85
85
  <% map_id = SecureRandom.hex %>
86
86
  <%= content_tag :div, nil, id: map_id, style: "height: #{@only_chart ? 300 : 500}px;" %>
87
- <script>
87
+ <%= javascript_tag nonce: true do %>
88
88
  <%= blazer_js_var "mapboxAccessToken", Blazer.mapbox_access_token %>
89
89
  <%= blazer_js_var "geojson", @geojson %>
90
90
  <%= blazer_js_var "mapId", map_id %>
91
91
  new Mapkick.AreaMap(mapId, geojson, {accessToken: mapboxAccessToken, tooltips: {hover: false, html: true}});
92
- </script>
92
+ <% end %>
93
93
  <% elsif chart_type == "line" %>
94
94
  <% chart_data = @columns[1..-1].each_with_index.map{ |k, i| {name: blazer_series_name(k), data: @rows.map{ |r| [r[0], r[i + 1]] }, library: series_library[i]} } %>
95
95
  <%= line_chart chart_data, **chart_options %>
@@ -28,7 +28,7 @@
28
28
  </table>
29
29
  <% end %>
30
30
 
31
- <script>
31
+ <%= javascript_tag nonce: true do %>
32
32
  $("#search").on("keyup", function() {
33
33
  var value = $(this).val().toLowerCase()
34
34
  $(".schema-table").filter(function() {
@@ -52,4 +52,4 @@
52
52
  $(this).toggle(found)
53
53
  })
54
54
  }).focus()
55
- </script>
55
+ <% end %>
@@ -46,7 +46,7 @@
46
46
  <p class="text-muted">Loading...</p>
47
47
  </div>
48
48
 
49
- <script>
49
+ <%= javascript_tag nonce: true do %>
50
50
  function showRun(data) {
51
51
  $("#results").html(data)
52
52
  $("#results table").stupidtable(stupidtableCustomSettings).stickyTableHeaders({fixedOffset: 60})
@@ -59,14 +59,14 @@
59
59
  <%= blazer_js_var "data", @run_data %>
60
60
 
61
61
  runQuery(data, showRun, showError)
62
- </script>
62
+ <% end %>
63
63
  <% end %>
64
64
 
65
- <script>
65
+ <%= javascript_tag nonce: true do %>
66
66
  // do not highlight really long queries
67
67
  // this can lead to performance issues
68
68
  var code = $("#code code")
69
69
  if (code.text().length < 10000) {
70
70
  hljs.highlightElement(code.get(0))
71
71
  }
72
- </script>
72
+ <% end %>
@@ -45,11 +45,11 @@
45
45
  </tbody>
46
46
  </table>
47
47
 
48
- <script>
48
+ <%= javascript_tag nonce: true do %>
49
49
  $("#search").on("keyup", function() {
50
50
  var value = $(this).val().toLowerCase()
51
51
  $("#uploads tbody tr").filter( function() {
52
52
  $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
53
53
  })
54
54
  }).focus()
55
- </script>
55
+ <% end %>
@@ -7,14 +7,14 @@
7
7
  <%= favicon_link_tag "blazer/favicon.png" %>
8
8
  <% if defined?(Propshaft::Railtie) %>
9
9
  <%= stylesheet_link_tag "blazer/bootstrap-propshaft", "blazer/bootstrap", "blazer/selectize", "blazer/github", "blazer/daterangepicker", "blazer/application" %>
10
- <%= javascript_include_tag "blazer/jquery", "blazer/rails-ujs", "blazer/stupidtable", "blazer/stupidtable-custom-settings", "blazer/jquery.stickytableheaders", "blazer/selectize", "blazer/highlight.min", "blazer/moment", "blazer/moment-timezone-with-data", "blazer/daterangepicker", "blazer/chart.umd", "blazer/chartjs-adapter-date-fns.bundle", "blazer/chartkick", "blazer/mapkick.bundle", "blazer/ace/ace", "blazer/ace/ext-language_tools", "blazer/ace/theme-twilight", "blazer/ace/mode-sql", "blazer/ace/snippets/text", "blazer/ace/snippets/sql", "blazer/Sortable", "blazer/bootstrap", "blazer/vue.global.prod", "blazer/routes", "blazer/queries", "blazer/fuzzysearch", "blazer/application" %>
10
+ <%= javascript_include_tag "blazer/jquery", "blazer/rails-ujs", "blazer/stupidtable", "blazer/stupidtable-custom-settings", "blazer/jquery.stickytableheaders", "blazer/selectize", "blazer/highlight.min", "blazer/moment", "blazer/moment-timezone-with-data", "blazer/daterangepicker", "blazer/chart.umd", "blazer/chartjs-adapter-date-fns.bundle", "blazer/chartkick", "blazer/mapkick.bundle", "blazer/ace/ace", "blazer/ace/ext-language_tools", "blazer/ace/theme-twilight", "blazer/ace/mode-sql", "blazer/ace/snippets/text", "blazer/ace/snippets/sql", "blazer/Sortable", "blazer/bootstrap", "blazer/vue.global.prod", "blazer/routes", "blazer/queries", "blazer/fuzzysearch", "blazer/application", nonce: true %>
11
11
  <% else %>
12
12
  <%= stylesheet_link_tag "blazer/application" %>
13
- <%= javascript_include_tag "blazer/application" %>
13
+ <%= javascript_include_tag "blazer/application", nonce: true %>
14
14
  <% end %>
15
- <script>
15
+ <%= javascript_tag nonce: true do %>
16
16
  <%= blazer_js_var "rootPath", root_path %>
17
- </script>
17
+ <% end %>
18
18
  <%= csrf_meta_tags %>
19
19
  </head>
20
20
  <body>
@@ -33,7 +33,7 @@ module Blazer
33
33
  # use token so we fetch cached results after query is run
34
34
  client_request_token: request_token,
35
35
  query_execution_context: {
36
- database: database,
36
+ database: database
37
37
  }
38
38
  }
39
39
 
@@ -45,7 +45,7 @@ module Blazer
45
45
  port: uri.port,
46
46
  username: uri.user,
47
47
  password: uri.password,
48
- database: uri.path.sub(/\A\//, ""),
48
+ database: uri.path.delete_prefix("/"),
49
49
  mode: uri.scheme.to_sym
50
50
  )
51
51
  end
@@ -39,10 +39,10 @@ module Blazer
39
39
  def client
40
40
  @client ||= begin
41
41
  uri = URI.parse(settings["url"])
42
- query = uri.query ? CGI::parse(uri.query) : {}
42
+ query = uri.query ? CGI.parse(uri.query) : {}
43
43
  Presto::Client.new(
44
44
  server: "#{uri.host}:#{uri.port}",
45
- catalog: uri.path.to_s.sub(/\A\//, ""),
45
+ catalog: uri.path.to_s.delete_prefix("/"),
46
46
  schema: query["schema"] || "public",
47
47
  user: uri.user,
48
48
  http_debug: false
@@ -29,13 +29,22 @@ module Blazer
29
29
  end
30
30
 
31
31
  columns = result.columns
32
- result.rows.each do |untyped_row|
33
- rows << (result.column_types.empty? ? untyped_row : columns.each_with_index.map { |c, i| untyped_row[i] && result.column_types[c] ? result.column_types[c].send(:cast_value, untyped_row[i]) : untyped_row[i] })
32
+ rows = result.rows
33
+
34
+ # cast values
35
+ if result.column_types.any?
36
+ types = columns.map { |c| result.column_types[c] }
37
+ rows =
38
+ rows.map do |row|
39
+ row.map.with_index do |v, i|
40
+ v && (t = types[i]) ? t.send(:cast_value, v) : v
41
+ end
42
+ end
34
43
  end
35
44
 
36
45
  # fix for non-ASCII column names and charts
37
46
  if adapter_name == "Trilogy"
38
- columns.map! { |k| k.dup.force_encoding(Encoding::UTF_8) }
47
+ columns = columns.map { |k| k.dup.force_encoding(Encoding::UTF_8) }
39
48
  end
40
49
  rescue => e
41
50
  error = e.message.sub(/.+ERROR: /, "")
@@ -141,7 +150,7 @@ module Blazer
141
150
  def cohort_analysis_statement(statement, period:, days:)
142
151
  raise "Cohort analysis not supported" unless supports_cohort_analysis?
143
152
 
144
- cohort_column = statement =~ /\bcohort_time\b/ ? "cohort_time" : "conversion_time"
153
+ cohort_column = statement.match?(/\bcohort_time\b/) ? "cohort_time" : "conversion_time"
145
154
  tzname = Blazer.time_zone.tzinfo.name
146
155
 
147
156
  if mysql?
@@ -107,7 +107,7 @@ module Blazer
107
107
  end
108
108
 
109
109
  unless result
110
- comment = "blazer"
110
+ comment = "blazer".dup
111
111
  if options[:user].respond_to?(:id)
112
112
  comment << ",user_id:#{options[:user].id}"
113
113
  end
data/lib/blazer/result.rb CHANGED
@@ -131,7 +131,7 @@ module Blazer
131
131
 
132
132
  if chart_type == "line"
133
133
  columns[1..-1].each_with_index.each do |k, i|
134
- series << {name: k, data: rows.map{ |r| [r[0], r[i + 1]] }}
134
+ series << {name: k, data: rows.map { |r| [r[0], r[i + 1]] }}
135
135
  end
136
136
  else
137
137
  rows.group_by { |r| v = r[1]; (smart_values[columns[1]] || {})[v.to_s] || v }.each_with_index.map do |(name, v), i|
@@ -33,9 +33,9 @@ module Blazer
33
33
  end
34
34
 
35
35
  unless value.is_a?(ActiveSupport::TimeWithZone)
36
- if value =~ /\A\d+\z/
36
+ if value.match?(/\A\d+\z/)
37
37
  value = value.to_i
38
- elsif value =~ /\A\d+\.\d+\z/
38
+ elsif value.match?(/\A\d+\.\d+\z/)
39
39
  value = value.to_f
40
40
  end
41
41
  end
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "3.0.3"
2
+ VERSION = "3.0.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2024-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -251,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
251
  - !ruby/object:Gem::Version
252
252
  version: '0'
253
253
  requirements: []
254
- rubygems_version: 3.5.3
254
+ rubygems_version: 3.5.11
255
255
  signing_key:
256
256
  specification_version: 4
257
257
  summary: Explore your data with SQL. Easily create charts and dashboards, and share