gooddata 2.1.14-java → 2.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +5 -5
  2. data/.gdc-ii-config.yaml +1 -1
  3. data/.github/workflows/build.yml +66 -0
  4. data/.github/workflows/pre-merge.yml +72 -0
  5. data/.sonar.settings +4 -0
  6. data/.travis.yml +78 -12
  7. data/CHANGELOG.md +62 -0
  8. data/Dockerfile +25 -14
  9. data/LICENSE +4418 -17
  10. data/LICENSE.rb +1 -1
  11. data/README.md +3 -3
  12. data/Rakefile +8 -1
  13. data/SDK_VERSION +1 -1
  14. data/VERSION +1 -1
  15. data/bin/test_projects_cleanup.rb +45 -3
  16. data/ci/mssql/pom.xml +62 -0
  17. data/ci/mysql/pom.xml +57 -0
  18. data/ci/postgresql/pom.xml +57 -0
  19. data/ci/redshift/pom.xml +1 -1
  20. data/dev-gooddata-sso.pub.encrypted +40 -40
  21. data/gdc_fossa_ruby_sdk.yaml +1 -0
  22. data/gooddata.gemspec +10 -6
  23. data/k8s/charts/lcm-bricks/Chart.yaml +1 -1
  24. data/k8s/charts/lcm-bricks/templates/prometheus/alertingRules.yaml +11 -1
  25. data/lcm.rake +2 -2
  26. data/lib/gooddata/bricks/middleware/aws_middleware.rb +35 -9
  27. data/lib/gooddata/cloud_resources/blobstorage/blobstorage_client.rb +98 -0
  28. data/lib/gooddata/cloud_resources/{cloud_resouce_factory.rb → cloud_resource_factory.rb} +8 -0
  29. data/lib/gooddata/cloud_resources/cloud_resources.rb +1 -1
  30. data/lib/gooddata/cloud_resources/mssql/drivers/.gitkeepme +0 -0
  31. data/lib/gooddata/cloud_resources/mssql/mssql_client.rb +122 -0
  32. data/lib/gooddata/cloud_resources/mysql/drivers/.gitkeepme +0 -0
  33. data/lib/gooddata/cloud_resources/mysql/mysql_client.rb +111 -0
  34. data/lib/gooddata/cloud_resources/postgresql/drivers/.gitkeepme +0 -0
  35. data/lib/gooddata/cloud_resources/postgresql/postgresql_client.rb +106 -0
  36. data/lib/gooddata/cloud_resources/snowflake/snowflake_client.rb +18 -1
  37. data/lib/gooddata/commands/scaffold.rb +9 -10
  38. data/lib/gooddata/core/nil_logger.rb +3 -1
  39. data/lib/gooddata/helpers/data_helper.rb +9 -5
  40. data/lib/gooddata/helpers/global_helpers.rb +6 -5
  41. data/lib/gooddata/lcm/actions/associate_clients.rb +8 -2
  42. data/lib/gooddata/lcm/actions/base_action.rb +0 -2
  43. data/lib/gooddata/lcm/actions/collect_meta.rb +3 -1
  44. data/lib/gooddata/lcm/actions/migrate_gdc_date_dimension.rb +3 -2
  45. data/lib/gooddata/lcm/actions/provision_clients.rb +31 -10
  46. data/lib/gooddata/lcm/actions/synchronize_clients.rb +56 -7
  47. data/lib/gooddata/lcm/actions/synchronize_dataset_mappings.rb +64 -0
  48. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +19 -8
  49. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +16 -9
  50. data/lib/gooddata/lcm/actions/synchronize_users.rb +7 -6
  51. data/lib/gooddata/lcm/actions/update_metric_formats.rb +185 -0
  52. data/lib/gooddata/lcm/data/delete_from_lcm_release.sql.erb +5 -0
  53. data/lib/gooddata/lcm/helpers/release_table_helper.rb +42 -8
  54. data/lib/gooddata/lcm/lcm2.rb +5 -2
  55. data/lib/gooddata/lcm/types/base_type.rb +0 -2
  56. data/lib/gooddata/mixins/md_object_query.rb +9 -6
  57. data/lib/gooddata/models/blueprint/project_blueprint.rb +0 -2
  58. data/lib/gooddata/models/client.rb +14 -12
  59. data/lib/gooddata/models/data_source.rb +668 -0
  60. data/lib/gooddata/models/dataset_mapping.rb +36 -0
  61. data/lib/gooddata/models/domain.rb +3 -2
  62. data/lib/gooddata/models/metadata/analytical_dashboard.rb +49 -0
  63. data/lib/gooddata/models/metadata/analytical_visualization_object.rb +30 -0
  64. data/lib/gooddata/models/metadata/label.rb +26 -27
  65. data/lib/gooddata/models/metadata/visualization_object.rb +50 -0
  66. data/lib/gooddata/models/project.rb +66 -19
  67. data/lib/gooddata/models/schedule.rb +13 -1
  68. data/lib/gooddata/models/user_filters/user_filter_builder.rb +58 -54
  69. data/lib/gooddata/models/user_group.rb +0 -1
  70. data/lib/gooddata/rest/connection.rb +6 -4
  71. data/lib/gooddata/rest/phmap.rb +2 -1
  72. data/lib/gooddata.rb +2 -0
  73. data/rubydev_public.gpg.encrypted +51 -51
  74. data/rubydev_secret_keys.gpg.encrypted +109 -109
  75. metadata +51 -27
  76. data/DEPENDENCIES.md +0 -880
  77. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +0 -37
  78. data/lib/gooddata/helpers/data_source_helpers.rb +0 -47
@@ -5,7 +5,6 @@
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
7
7
  require 'cgi'
8
- require 'active_support/core_ext/hash/compact'
9
8
 
10
9
  require_relative 'profile'
11
10
  require_relative '../extensions/enumerable'
@@ -457,10 +456,12 @@ Available values for setting language are: #{available_languages}."
457
456
  alias_method :add_clients_settings, :update_clients_settings
458
457
 
459
458
  def update_clients(data, options = {})
459
+ results = []
460
460
  data.group_by(&:data_product_id).each do |data_product_id, client_update_data|
461
461
  data_product = data_products(data_product_id)
462
- data_product.update_clients(client_update_data, options)
462
+ results.concat data_product.update_clients(client_update_data, options)
463
463
  end
464
+ results
464
465
  end
465
466
 
466
467
  # Update user in domain
@@ -0,0 +1,49 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ #
4
+ # Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
5
+ # This source code is licensed under the BSD-style license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ require_relative 'analytical_visualization_object'
9
+
10
+ module GoodData
11
+ class AnalyticalDashboard < GoodData::AnalyticalVisualizationObject
12
+ EMPTY_OBJECT = {
13
+ 'analyticalDashboard' => {
14
+ 'content' => {
15
+ 'filterContext' => '',
16
+ 'layout' => {},
17
+ 'widgets' => []
18
+ },
19
+ 'meta' => {
20
+ 'deprecated' => '0',
21
+ 'summary' => '',
22
+ 'title' => ''
23
+ }
24
+ }
25
+ }
26
+
27
+ ASSIGNABLE_MEMBERS = %i[filterContext layout widgets deprecated summary title]
28
+
29
+ class << self
30
+ # Method intended to get all AnalyticalDashboard objects in a specified project
31
+ #
32
+ # @param options [Hash] the options hash
33
+ # @option options [Boolean] :full with true value will pull in full objects. Default is false value
34
+ # @return [Array<GoodData::AnalyticalDashboard>] Return AnalyticalDashboard list
35
+ def all(options = { :client => GoodData.connection, :project => GoodData.project })
36
+ query('analyticalDashboard', AnalyticalDashboard, options)
37
+ end
38
+
39
+ # Create Analytical Dashboard in the specify project
40
+ #
41
+ # @param analytical_dashboard [Hash] the data of object will be created
42
+ # @param options [Hash] The project that the object will be created in
43
+ # @return GoodData::AnalyticalDashboard object
44
+ def create(analytical_dashboard = {}, options = { :client => GoodData.client, :project => GoodData.project })
45
+ GoodData::AnalyticalVisualizationObject.create(analytical_dashboard, AnalyticalDashboard, EMPTY_OBJECT, ASSIGNABLE_MEMBERS, options)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ #
4
+ # Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
5
+ # This source code is licensed under the BSD-style license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ module GoodData
9
+ class AnalyticalVisualizationObject < GoodData::MdObject
10
+ class << self
11
+ # Create a specify object in the specify project
12
+ #
13
+ # @param object_data [Hash] the data of object will be created
14
+ # @param klass [Class] A class used for instantiating the returned data
15
+ # @param empty_data_object [Hash] the empty data of object will be created
16
+ # @param assignable_properties [Hash] the properties allow updating
17
+ # @param options [Hash] The project that the object will be created in
18
+ # @return klass object
19
+ def create(object_data, klass, empty_data_object = {}, assignable_properties = [], options = { :client => GoodData.client, :project => GoodData.project })
20
+ client, project = GoodData.get_client_and_project(GoodData::Helpers.symbolize_keys(options))
21
+
22
+ res = client.create(klass, GoodData::Helpers.deep_dup(GoodData::Helpers.stringify_keys(empty_data_object)), :project => project)
23
+ object_data.each do |k, v|
24
+ res.send("#{k}=", v) if assignable_properties.include? k
25
+ end
26
+ res
27
+ end
28
+ end
29
+ end
30
+ end
@@ -40,22 +40,20 @@ module GoodData
40
40
  end
41
41
  end
42
42
 
43
- # Gets valid elements using /validElements? API
43
+ # Gets valid elements of a label for a specific paging (:offset and :limit) or get validElements of a specific value (:filter).
44
+ # In the case filter a specific value, because the API /validElements only filter by partial match, we need to filter again at client side for exact match.
44
45
  # @return [Array] Results
45
46
  def get_valid_elements(*args)
46
- results, params = valid_elements(*args)
47
- # TMA-775 - the validElements API can possibly return more matches than requested (usually 1)
48
- # so we do a preliminary first request to check and then increase the limit if needed
49
- if results['validElements']['paging']['total'].to_i != params[:limit]
47
+ if args && !args.empty? && args.first[:filter]
48
+ params = args.first
50
49
  params[:limit] = 100_000
51
50
  results, = valid_elements params
52
- if params[:filter]
53
- results['validElements']['items'] = results['validElements']['items'].reject do |i|
54
- i['element']['title'] != params[:filter]
55
- end
51
+ results['validElements']['items'] = results['validElements']['items'].select do |i|
52
+ i['element']['title'] == params[:filter]
56
53
  end
54
+ else
55
+ results, = valid_elements(*args)
57
56
  end
58
-
59
57
  results
60
58
  end
61
59
 
@@ -74,24 +72,25 @@ module GoodData
74
72
  # @option options [Number] :limit limits the number of values to certain number. Default is 100
75
73
  # @return [Array]
76
74
  def values(options = {})
77
- Enumerator.new do |y|
78
- offset = options[:offset] || 0
79
- page_limit = options[:limit] || 100
80
- loop do
81
- results = get_valid_elements(limit: page_limit, offset: offset)
82
-
83
- elements = results['validElements']
84
- elements['items'].map do |el|
85
- v = el['element']
86
- y << {
87
- :value => v['title'],
88
- :uri => v['uri']
89
- }
90
- end
91
- break if elements['items'].count < page_limit
92
- offset += page_limit
75
+ all_values = []
76
+ offset = options[:offset] || 0
77
+ page_limit = options[:limit] || 100
78
+ loop do
79
+ results = get_valid_elements(limit: page_limit, offset: offset)
80
+
81
+ elements = results['validElements']
82
+ elements['items'].map do |el|
83
+ v = el['element']
84
+ all_values << {
85
+ :value => v['title'],
86
+ :uri => v['uri']
87
+ }
93
88
  end
89
+ break if elements['items'].count < page_limit
90
+
91
+ offset += page_limit
94
92
  end
93
+ all_values
95
94
  end
96
95
 
97
96
  def values_count
@@ -136,7 +135,7 @@ module GoodData
136
135
  if status_url
137
136
  results = client.poll_on_response(status_url) do |body|
138
137
  status = body['taskState'] && body['taskState']['status']
139
- status == 'RUNNING' || status == 'PREPARED'
138
+ status == 'RUNNING' || status == 'PREPARED' || body['uri']
140
139
  end
141
140
  end
142
141
 
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ #
4
+ # Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
5
+ # This source code is licensed under the BSD-style license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ require_relative 'analytical_visualization_object'
9
+
10
+ module GoodData
11
+ class VisualizationObject < GoodData::AnalyticalVisualizationObject
12
+ EMPTY_OBJECT = {
13
+ 'visualizationObject' => {
14
+ 'content' => {
15
+ 'buckets' => [],
16
+ 'properties' => '',
17
+ 'visualizationClass' => {}
18
+ },
19
+ 'links' => {},
20
+ 'meta' => {
21
+ 'deprecated' => '0',
22
+ 'summary' => '',
23
+ 'title' => ''
24
+ }
25
+ }
26
+ }
27
+
28
+ ASSIGNABLE_MEMBERS = %i[buckets properties visualizationClass deprecated summary title]
29
+
30
+ class << self
31
+ # Method intended to get all VisualizationObject objects in a specified project
32
+ #
33
+ # @param options [Hash] the options hash
34
+ # @option options [Boolean] :full with true value to pull full objects
35
+ # @return [Array<GoodData::VisualizationObject>] Return VisualizationObject list
36
+ def all(options = { :client => GoodData.connection, :project => GoodData.project })
37
+ query('visualizationObject', VisualizationObject, options)
38
+ end
39
+
40
+ # Create Visualization Object in the specify project
41
+ #
42
+ # @param visualization_object [Hash] the data of object will be created
43
+ # @param options [Hash] The project that the object will be created in
44
+ # @return GoodData::VisualizationObject object
45
+ def create(visualization_object = {}, options = { :client => GoodData.client, :project => GoodData.project })
46
+ GoodData::AnalyticalVisualizationObject.create(visualization_object, VisualizationObject, EMPTY_OBJECT, ASSIGNABLE_MEMBERS, options)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  #
3
- # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
3
+ # Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
4
4
  # This source code is licensed under the BSD-style license found in the
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
@@ -13,7 +13,6 @@ require 'zip'
13
13
  require 'net/smtp'
14
14
 
15
15
  require 'active_support/core_ext/hash/except'
16
- require 'active_support/core_ext/hash/compact'
17
16
  require 'active_support/core_ext/hash/slice'
18
17
 
19
18
  require_relative '../exceptions/no_project_error'
@@ -31,6 +30,7 @@ require_relative 'process'
31
30
  require_relative 'project_log_formatter'
32
31
  require_relative 'project_role'
33
32
  require_relative 'blueprint/blueprint'
33
+ require_relative 'dataset_mapping'
34
34
 
35
35
  require_relative 'metadata/scheduled_mail'
36
36
  require_relative 'metadata/scheduled_mail/dashboard_attachment'
@@ -38,7 +38,8 @@ require_relative 'metadata/scheduled_mail/report_attachment'
38
38
 
39
39
  module GoodData
40
40
  class Project < Rest::Resource
41
- USERSPROJECTS_PATH = '/gdc/account/profile/%s/projects'
41
+ USER_ACCOUNT_PATH = '/gdc/account/profile/'
42
+ USERSPROJECTS_PATH = USER_ACCOUNT_PATH + '%s/projects'
42
43
  PROJECTS_PATH = '/gdc/projects'
43
44
  PROJECT_PATH = '/gdc/projects/%s'
44
45
  SLIS_PATH = '/ldm/singleloadinterface'
@@ -255,6 +256,22 @@ module GoodData
255
256
  transfer_schedules(from_project, to_project)
256
257
  end
257
258
 
259
+ def get_dataset_mapping(from_project)
260
+ GoodData::DatasetMapping.get(:client => from_project.client, :project => from_project)
261
+ end
262
+
263
+ def update_dataset_mapping(model_mapping_json, to_project)
264
+ dataset_mapping = GoodData::DatasetMapping.new(model_mapping_json)
265
+ res = dataset_mapping.save(:client => to_project.client, :project => to_project)
266
+ status = res&.dig('datasetMappings', 'items').nil? ? "Failed" : "OK"
267
+ count = "OK".eql?(status) ? res['datasetMappings']['items'].length : 0
268
+ {
269
+ to: to_project.pid,
270
+ count: count,
271
+ status: status
272
+ }
273
+ end
274
+
258
275
  # @param from_project The source project
259
276
  # @param to_project The target project
260
277
  # @param options Optional parameters
@@ -336,26 +353,22 @@ module GoodData
336
353
 
337
354
  def get_data_source_alias(data_source_id, client, aliases)
338
355
  unless aliases[data_source_id]
339
- data_source = GoodData::Helpers.get_data_source_by_id(data_source_id, client)
340
- if data_source&.dig('dataSource', 'alias')
356
+ data_source = GoodData::DataSource.from_id(data_source_id, client: client)
357
+ if data_source&.alias
341
358
  aliases[data_source_id] = {
342
- :type => get_data_source_type(data_source),
343
- :alias => data_source['dataSource']['alias']
359
+ :type => data_source.type,
360
+ :alias => data_source.alias
344
361
  }
345
362
  end
346
363
  end
347
364
  aliases[data_source_id]
348
365
  end
349
366
 
350
- def get_data_source_type(data_source_data)
351
- data_source_data&.dig('dataSource', 'connectionInfo') ? data_source_data['dataSource']['connectionInfo'].first[0].upcase : ""
352
- end
353
-
354
367
  def replace_process_data_source_ids(process_data, client, aliases)
355
368
  component = process_data.dig(:process, :component)
356
369
  if component&.dig(:configLocation, :dataSourceConfig)
357
370
  the_alias = aliases[component[:configLocation][:dataSourceConfig][:id]]
358
- process_data[:process][:component][:configLocation][:dataSourceConfig][:id] = GoodData::Helpers.verify_data_source_alias(the_alias, client)
371
+ process_data[:process][:component][:configLocation][:dataSourceConfig][:id] = verify_data_source_alias(the_alias, client)
359
372
  end
360
373
  process_data[:process][:dataSources] = replace_data_source_ids(process_data[:process][:dataSources], client, aliases)
361
374
  process_data
@@ -365,13 +378,35 @@ module GoodData
365
378
  array_data_sources = []
366
379
  if data_sources && !data_sources.empty?
367
380
  data_sources.map do |data_source|
368
- new_id = GoodData::Helpers.verify_data_source_alias(aliases[data_source[:id]], client)
381
+ new_id = verify_data_source_alias(aliases[data_source[:id]], client)
369
382
  array_data_sources.push(:id => new_id)
370
383
  end
371
384
  end
372
385
  array_data_sources
373
386
  end
374
387
 
388
+ # Verify whether the data source exists in the domain using its alias
389
+ #
390
+ # @param [String] ds_alias The data source's alias
391
+ # @param [Object] client The Rest Client object
392
+ # @return [String] Id of the data source or failed with the reason
393
+ def verify_data_source_alias(ds_alias, client)
394
+ domain = client.connection.server.url
395
+ fail "The data source alias is empty, check your data source configuration." unless ds_alias
396
+
397
+ uri = "/gdc/dataload/dataSources/internal/availableAlias?alias=#{ds_alias[:alias]}"
398
+ res = client.get(uri)
399
+ fail "Unable to get information about the Data Source '#{ds_alias[:alias]}' in the domain '#{domain}'" unless res
400
+ fail "Unable to find the #{ds_alias[:type]} Data Source '#{ds_alias[:alias]}' in the domain '#{domain}'" if res['availableAlias']['available']
401
+
402
+ ds_type = res['availableAlias']['existingDataSource']['type']
403
+ if ds_type && ds_type != ds_alias[:type]
404
+ fail "Wrong Data Source type - the '#{ds_type}' type is expected but the Data Source '#{ds_alias[:alias]}' in the domain '#{domain}' has the '#{ds_alias[:type]}' type"
405
+ else
406
+ res['availableAlias']['existingDataSource']['id']
407
+ end
408
+ end
409
+
375
410
  def transfer_user_groups(from_project, to_project)
376
411
  from_project.user_groups.map do |ug|
377
412
  # migrate groups
@@ -438,7 +473,9 @@ module GoodData
438
473
  local_stuff = local_schedules.map do |s|
439
474
  v = s.to_hash
440
475
  after_schedule = local_schedules.find { |s2| s.trigger_id == s2.obj_id }
441
- v[:after] = s.trigger_id && after_schedule && after_schedule.name
476
+ after_process_schedule = from_project_processes.find { |p| after_schedule && p.obj_id == after_schedule.process_id }
477
+ v[:after] = s.trigger_id && after_process_schedule && after_schedule && after_schedule.name
478
+ v[:trigger_execution_status] = s.trigger_execution_status
442
479
  v[:remote_schedule] = s
443
480
  v[:params] = v[:params].except("EXECUTABLE", "PROCESS_ID")
444
481
  v.compact
@@ -507,6 +544,7 @@ module GoodData
507
544
  schedule.params = (schedule_spec[:params] || {})
508
545
  schedule.cron = schedule_spec[:cron] if schedule_spec[:cron]
509
546
  schedule.after = schedule_cache[schedule_spec[:after]] if schedule_spec[:after]
547
+ schedule.trigger_execution_status = schedule_cache[schedule_spec[:trigger_execution_status]] if schedule_spec[:after]
510
548
  schedule.hidden_params = schedule_spec[:hidden_params] || {}
511
549
  if process_spec.type != :dataload
512
550
  schedule.executable = schedule_spec[:executable] || (process_spec.type == :ruby ? 'main.rb' : 'main.grf')
@@ -567,7 +605,8 @@ module GoodData
567
605
  hidden_params: schedule_spec[:hidden_params],
568
606
  name: schedule_spec[:name],
569
607
  reschedule: schedule_spec[:reschedule],
570
- state: schedule_spec[:state]
608
+ state: schedule_spec[:state],
609
+ trigger_execution_status: schedule_spec[:trigger_execution_status]
571
610
  }
572
611
  end
573
612
  end
@@ -1716,7 +1755,7 @@ module GoodData
1716
1755
  end
1717
1756
  end
1718
1757
  diff_results = diff_results.map do |u|
1719
- u[:login_uri] = "/gdc/account/profile/" + u[:login]
1758
+ u[:login_uri] = USER_ACCOUNT_PATH + u[:login]
1720
1759
  u
1721
1760
  end
1722
1761
  return diff_results if options[:dry_run]
@@ -1952,17 +1991,17 @@ module GoodData
1952
1991
 
1953
1992
  def resolve_roles(login, desired_roles, options = {})
1954
1993
  user = if login.is_a?(String) && login.include?('@')
1955
- '/gdc/account/profile/' + login
1994
+ USER_ACCOUNT_PATH + login
1956
1995
  elsif login.is_a?(String)
1957
1996
  login
1958
1997
  elsif login.is_a?(Hash) && login[:login]
1959
- '/gdc/account/profile/' + login[:login]
1998
+ USER_ACCOUNT_PATH + login[:login]
1960
1999
  elsif login.is_a?(Hash) && login[:uri]
1961
2000
  login[:uri]
1962
2001
  elsif login.respond_to?(:uri) && login.uri
1963
2002
  login.uri
1964
2003
  elsif login.respond_to?(:login) && login.login
1965
- '/gdc/account/profile/' + login.login
2004
+ USER_ACCOUNT_PATH + login.login
1966
2005
  else
1967
2006
  fail "Unsupported user specification #{login}"
1968
2007
  end
@@ -2000,6 +2039,14 @@ module GoodData
2000
2039
  GoodData::Project.transfer_etl(client, self, target)
2001
2040
  end
2002
2041
 
2042
+ def dataset_mapping
2043
+ GoodData::Project.get_dataset_mapping(self)
2044
+ end
2045
+
2046
+ def update_dataset_mapping(model_mapping_json)
2047
+ GoodData::Project.update_dataset_mapping(model_mapping_json, self)
2048
+ end
2049
+
2003
2050
  def transfer_processes(target)
2004
2051
  GoodData::Project.transfer_processes(self, target)
2005
2052
  end
@@ -101,6 +101,7 @@ module GoodData
101
101
 
102
102
  schedule.name = options[:name]
103
103
  schedule.set_trigger(trigger)
104
+ schedule.trigger_execution_status = options[:trigger_execution_status]
104
105
  schedule.params = default_opts[:params].merge(options[:params] || {})
105
106
  schedule.hidden_params = options[:hidden_params] || {}
106
107
  schedule.timezone = options[:timezone] || default_opts[:timezone]
@@ -468,6 +469,7 @@ module GoodData
468
469
  hidden_params: hidden_params,
469
470
  cron: cron,
470
471
  trigger_id: trigger_id,
472
+ trigger_execution_status: trigger_execution_status,
471
473
  timezone: timezone,
472
474
  uri: uri,
473
475
  reschedule: reschedule,
@@ -486,6 +488,16 @@ module GoodData
486
488
  self
487
489
  end
488
490
 
491
+ def trigger_execution_status
492
+ json['schedule']['triggerExecutionStatus']
493
+ end
494
+
495
+ def trigger_execution_status=(trigger_execution_status)
496
+ json['schedule']['triggerExecutionStatus'] = trigger_execution_status
497
+ @dirty = true
498
+ self # rubocop:disable Lint/Void
499
+ end
500
+
489
501
  def name
490
502
  json['schedule']['name']
491
503
  end
@@ -530,7 +542,7 @@ module GoodData
530
542
  'hiddenParams' => GoodData::Helpers.encode_hidden_params(hidden_params)
531
543
  }
532
544
  }
533
-
545
+ res['schedule']['triggerExecutionStatus'] = trigger_execution_status if trigger_execution_status
534
546
  res['schedule']['reschedule'] = reschedule if reschedule
535
547
 
536
548
  res
@@ -7,7 +7,6 @@
7
7
  require_relative '../project_log_formatter'
8
8
 
9
9
  require 'active_support/core_ext/hash/indifferent_access'
10
- require 'active_support/core_ext/hash/compact'
11
10
 
12
11
  require 'gooddata/extensions/true'
13
12
  require 'gooddata/extensions/false'
@@ -204,7 +203,7 @@ module GoodData
204
203
  # so it precaches the values and still be able to function for larger ones even
205
204
  # though that would mean tons of requests
206
205
  def self.get_small_labels(labels_cache)
207
- labels_cache.values.select { |label| label && label.values_count && label.values_count < 100_000 }
206
+ labels_cache.values.select { |label| label &.values_count &. < 100_000 }
208
207
  end
209
208
 
210
209
  # Creates a MAQL expression(s) based on the filter defintion.
@@ -422,68 +421,73 @@ module GoodData
422
421
  results: create_results + delete_results }
423
422
  end
424
423
 
425
- create_results = to_create.each_slice(100).flat_map do |batch|
426
- batch.pmapcat do |related_uri, group|
427
- group.each(&:save)
428
- res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
429
- items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
430
-
431
- payload = {
432
- 'userFilters' => {
433
- 'items' => [{
434
- 'user' => related_uri,
435
- 'userFilters' => items.concat(group.map(&:uri))
436
- }]
424
+ if to_create.empty?
425
+ create_results = []
426
+ else
427
+ create_results = to_create.each_slice(100).flat_map do |batch|
428
+ batch.pmapcat do |related_uri, group|
429
+ group.each(&:save)
430
+ res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
431
+ items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
432
+
433
+ payload = {
434
+ 'userFilters' => {
435
+ 'items' => [{
436
+ 'user' => related_uri,
437
+ 'userFilters' => items.concat(group.map(&:uri))
438
+ }]
439
+ }
437
440
  }
438
- }
439
- res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
441
+ res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
440
442
 
441
- # turn the errors from hashes into array of hashes
442
- update_result = res['userFiltersUpdateResult'].flat_map do |k, v|
443
- v.map { |r| { status: k.to_sym, user: r, type: :create } }
444
- end
443
+ # turn the errors from hashes into array of hashes
444
+ update_result = res['userFiltersUpdateResult'].flat_map do |k, v|
445
+ v.map { |r| { status: k.to_sym, user: r, type: :create } }
446
+ end
445
447
 
446
- update_result.map do |result|
447
- result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result
448
+ update_result.map do |result|
449
+ result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result
450
+ end
448
451
  end
449
452
  end
453
+ project_log_formatter.log_user_filter_results(create_results, to_create)
454
+ create_errors = create_results.select { |r| r[:status] == :failed }
455
+ fail "Creating MUFs resulted in errors: #{create_errors}" if create_errors.any?
450
456
  end
451
457
 
452
- project_log_formatter.log_user_filter_results(create_results, to_create)
453
- create_errors = create_results.select { |r| r[:status] == :failed }
454
- fail "Creating MUFs resulted in errors: #{create_errors}" if create_errors.any?
455
-
456
- delete_results = unless options[:do_not_touch_filters_that_are_not_mentioned]
457
- to_delete.each_slice(100).flat_map do |batch|
458
- batch.flat_map do |related_uri, group|
459
- results = []
460
- if related_uri
461
- res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
462
- items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
463
- payload = {
464
- 'userFilters' => {
465
- 'items' => [
466
- {
467
- 'user' => related_uri,
468
- 'userFilters' => items - group.map(&:uri)
469
- }
470
- ]
471
- }
472
- }
473
- res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
474
- results.concat(res['userFiltersUpdateResult']
458
+ if to_delete.empty?
459
+ delete_results = []
460
+ elsif !options[:do_not_touch_filters_that_are_not_mentioned]
461
+ delete_results = to_delete.each_slice(100).flat_map do |batch|
462
+ batch.flat_map do |related_uri, group|
463
+ results = []
464
+ if related_uri
465
+ res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
466
+ items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
467
+ payload = {
468
+ 'userFilters' => {
469
+ 'items' => [
470
+ {
471
+ 'user' => related_uri,
472
+ 'userFilters' => items - group.map(&:uri)
473
+ }
474
+ ]
475
+ }
476
+ }
477
+ res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
478
+ results.concat(res['userFiltersUpdateResult']
475
479
  .flat_map { |k, v| v.map { |r| { status: k.to_sym, user: r, type: :delete } } }
476
480
  .map { |result| result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result })
477
- end
478
- group.peach(&:delete)
479
- results
480
- end
481
- end
482
- end
481
+ end
482
+ group.peach(&:delete)
483
+ results
484
+ end
483
485
 
484
- project_log_formatter.log_user_filter_results(delete_results, to_delete)
485
- delete_errors = delete_results.select { |r| r[:status] == :failed } if delete_results
486
- fail "Deleting MUFs resulted in errors: #{delete_errors}" if delete_errors && delete_errors.any?
486
+ project_log_formatter.log_user_filter_results(delete_results, to_delete)
487
+ delete_errors = delete_results.select { |r| r[:status] == :failed } if delete_results
488
+ fail "Deleting MUFs resulted in errors: #{delete_errors}" if delete_errors&.any?
489
+ end
490
+ end
487
491
 
488
492
  { created: to_create, deleted: to_delete, results: create_results + (delete_results || []) }
489
493
  end
@@ -13,7 +13,6 @@ require_relative '../mixins/rest_resource'
13
13
  require_relative '../mixins/uri_getter'
14
14
 
15
15
  require 'active_support/core_ext/hash/except'
16
- require 'active_support/core_ext/hash/compact'
17
16
 
18
17
  module GoodData
19
18
  # Representation of User Group
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  #
3
- # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
3
+ # Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
4
4
  # This source code is licensed under the BSD-style license found in the
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
@@ -26,6 +26,8 @@ module GoodData
26
26
  class Connection
27
27
  include MonitorMixin
28
28
 
29
+ HTTPS_PROTOCOL = 'https://'
30
+ HTTP_PROTOCOL = 'http://'
29
31
  DEFAULT_URL = 'https://secure.gooddata.com'
30
32
  LOGIN_PATH = '/gdc/account/login'
31
33
  TOKEN_PATH = '/gdc/account/token'
@@ -712,12 +714,12 @@ ERR
712
714
 
713
715
  def fix_server_url(server)
714
716
  server = server.chomp('/')
715
- if server.start_with? 'http://'
716
- server = server.sub 'http://', 'https://'
717
+ if server.start_with? HTTP_PROTOCOL
718
+ server = server.sub HTTP_PROTOCOL, HTTPS_PROTOCOL
717
719
  GoodData.logger.warn 'You specified the HTTP protocol in your server string. It has been autofixed to HTTPS.'
718
720
  end
719
721
 
720
- server = 'https://' + server unless server.start_with? 'https://'
722
+ server = HTTPS_PROTOCOL + server unless server.start_with? HTTPS_PROTOCOL
721
723
  server
722
724
  end
723
725
  end