gooddata 2.1.14-java → 2.2.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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