gooddata 1.3.0-java → 1.3.1-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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +2 -0
  3. data/.document +0 -0
  4. data/.yardopts +0 -0
  5. data/CHANGELOG.md +48 -0
  6. data/CLI.md +0 -0
  7. data/CONTRIBUTING.md +19 -12
  8. data/Dockerfile +37 -0
  9. data/Guardfile +0 -0
  10. data/README.md +1 -1
  11. data/Rakefile +17 -1
  12. data/TODO.md +0 -0
  13. data/bin/run_brick.rb +31 -0
  14. data/dependency_decisions.yml +0 -0
  15. data/gooddata.gemspec +1 -0
  16. data/lib/gooddata/bricks/hello_world_brick.rb +21 -0
  17. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +12 -0
  18. data/lib/gooddata/bricks/middleware/logger_middleware.rb +12 -0
  19. data/lib/gooddata/bricks/pipeline.rb +12 -0
  20. data/lib/gooddata/exceptions/filter_maqlization.rb +0 -6
  21. data/lib/gooddata/extensions/class.rb +4 -0
  22. data/lib/gooddata/extensions/enumerable.rb +0 -3
  23. data/lib/gooddata/extensions/extensions.rb +0 -3
  24. data/lib/gooddata/extensions/false.rb +8 -16
  25. data/lib/gooddata/extensions/hash.rb +10 -41
  26. data/lib/gooddata/extensions/integer.rb +9 -3
  27. data/lib/gooddata/extensions/nil.rb +5 -13
  28. data/lib/gooddata/extensions/object.rb +0 -11
  29. data/lib/gooddata/extensions/string.rb +11 -5
  30. data/lib/gooddata/extensions/true.rb +8 -16
  31. data/lib/gooddata/helpers/global_helpers.rb +12 -0
  32. data/lib/gooddata/helpers/global_helpers_params.rb +5 -3
  33. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +6 -0
  34. data/lib/gooddata/lcm/actions/base_action.rb +8 -2
  35. data/lib/gooddata/lcm/actions/collect_multiple_projects_column.rb +46 -0
  36. data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +9 -2
  37. data/lib/gooddata/lcm/actions/execute_schedules.rb +0 -2
  38. data/lib/gooddata/lcm/actions/hello_world.rb +1 -1
  39. data/lib/gooddata/lcm/actions/synchronize_cas.rb +6 -0
  40. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +6 -0
  41. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +70 -107
  42. data/lib/gooddata/lcm/actions/synchronize_users.rb +1 -13
  43. data/lib/gooddata/lcm/brick_logger.rb +26 -0
  44. data/lib/gooddata/lcm/lcm2.rb +46 -7
  45. data/lib/gooddata/lcm/types/base_type.rb +4 -0
  46. data/lib/gooddata/lcm/types/class/class.rb +2 -0
  47. data/lib/gooddata/lcm/types/complex/complex.rb +2 -0
  48. data/lib/gooddata/lcm/types/special/array.rb +2 -0
  49. data/lib/gooddata/mixins/is_folder.rb +0 -0
  50. data/lib/gooddata/mixins/to_json.rb +0 -0
  51. data/lib/gooddata/mixins/uri_getter.rb +0 -0
  52. data/lib/gooddata/models/blueprint/project_blueprint.rb +5 -5
  53. data/lib/gooddata/models/blueprint/to_manifest.rb +0 -2
  54. data/lib/gooddata/models/domain.rb +1 -0
  55. data/lib/gooddata/models/from_wire.rb +0 -2
  56. data/lib/gooddata/models/profile.rb +1 -1
  57. data/lib/gooddata/models/project.rb +5 -0
  58. data/lib/gooddata/models/user_filters/user_filter_builder.rb +49 -32
  59. data/lib/gooddata/models/user_group.rb +3 -0
  60. data/lib/gooddata/rest/README.md +0 -0
  61. data/lib/gooddata/rest/client.rb +4 -4
  62. data/lib/gooddata/rest/object.rb +2 -0
  63. data/lib/gooddata/version.rb +1 -1
  64. data/lib/templates/bricks/brick.rb.erb +0 -0
  65. data/lib/templates/bricks/main.rb.erb +0 -0
  66. data/lib/templates/project/Goodfile.erb +0 -0
  67. data/lib/templates/project/data/commits.csv +0 -0
  68. data/lib/templates/project/data/devs.csv +0 -0
  69. data/lib/templates/project/data/repos.csv +0 -0
  70. data/lib/templates/project/model/model.rb.erb +0 -0
  71. metadata +23 -5
  72. data/lib/gooddata/extensions/big_decimal.rb +0 -17
  73. data/lib/gooddata/extensions/numeric.rb +0 -15
  74. data/lib/gooddata/extensions/symbol.rb +0 -15
@@ -1,5 +1,11 @@
1
- class Integer
2
- def to_b
3
- self == 1
1
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
2
+ # This source code is licensed under the BSD-style license found in the
3
+ # LICENSE file in the root directory of this source tree.
4
+
5
+ module IntegerExtensions
6
+ refine Integer do
7
+ def to_b
8
+ self == 1
9
+ end
4
10
  end
5
11
  end
@@ -1,19 +1,11 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
4
 
7
- class NilClass
8
- # +nil+ is not duplicable:
9
- #
10
- # nil.duplicable? # => false
11
- # nil.dup # => TypeError: can't dup NilClass
12
- def duplicable?
13
- false
14
- end
15
-
16
- def to_b
17
- false
5
+ module NilExtensions
6
+ refine NilClass do
7
+ def to_b
8
+ false
9
+ end
18
10
  end
19
11
  end
@@ -1,9 +1,6 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
-
7
4
  class Object
8
5
  class << self
9
6
  def set_const(name, val)
@@ -12,14 +9,6 @@ class Object
12
9
  end
13
10
  end
14
11
 
15
- def blank?
16
- respond_to?(:empty?) ? empty? : !self
17
- end
18
-
19
- def duplicable?
20
- true
21
- end
22
-
23
12
  def set_const(name, val)
24
13
  send(:remove_const, name) if const_defined?(name)
25
14
  send(:const_set, name, val)
@@ -1,7 +1,13 @@
1
- class String
2
- def to_b
3
- return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
4
- return false if self == false || blank? || self =~ (/(false|f|no|n|0)$/i)
5
- raise ArgumentError, "invalid value for Boolean: \"#{self}\""
1
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
2
+ # This source code is licensed under the BSD-style license found in the
3
+ # LICENSE file in the root directory of this source tree.
4
+
5
+ module StringExtensions
6
+ refine String do
7
+ def to_b
8
+ return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
9
+ return false if self == false || blank? || self =~ (/(false|f|no|n|0)$/i)
10
+ raise ArgumentError, "invalid value for Boolean: \"#{self}\""
11
+ end
6
12
  end
7
13
  end
@@ -1,23 +1,15 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
4
 
7
- class TrueClass
8
- # +true+ is not duplicable:
9
- #
10
- # true.duplicable? # => false
11
- # true.dup # => TypeError: can't dup TrueClass
12
- def duplicable?
13
- false
14
- end
15
-
16
- def to_b
17
- true
18
- end
5
+ module TrueExtensions
6
+ refine TrueClass do
7
+ def to_b
8
+ true
9
+ end
19
10
 
20
- def to_i
21
- 1
11
+ def to_i
12
+ 1
13
+ end
22
14
  end
23
15
  end
@@ -9,9 +9,21 @@ require 'pathname'
9
9
  require 'hashie'
10
10
  require 'openssl'
11
11
 
12
+ require 'active_support/core_ext/object/duplicable'
13
+
12
14
  require_relative '../extensions/object'
13
15
  require_relative 'global_helpers_params'
14
16
 
17
+ require 'gooddata/extensions/true'
18
+ require 'gooddata/extensions/false'
19
+ require 'gooddata/extensions/integer'
20
+ require 'gooddata/extensions/nil'
21
+
22
+ using TrueExtensions
23
+ using FalseExtensions
24
+ using IntegerExtensions
25
+ using NilExtensions
26
+
15
27
  module GoodData
16
28
  module Helpers
17
29
  extend Hashie::Extensions::StringifyKeys::ClassMethods
@@ -1,14 +1,16 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
4
+ require 'active_support/core_ext/hash/slice'
5
+
6
+ require 'gooddata/extensions/hash'
7
+
8
+ using HashExtensions
6
9
 
7
10
  module GoodData
8
11
  module Helpers
9
12
  ENCODED_PARAMS_KEY = 'gd_encoded_params'
10
13
  ENCODED_HIDDEN_PARAMS_KEY = 'gd_encoded_hidden_params'
11
-
12
14
  class << self
13
15
  # Encodes parameters for passing them to GD execution platform.
14
16
  # Core types are kept and complex types (arrays, structures, etc) are
@@ -6,6 +6,12 @@
6
6
 
7
7
  require_relative 'base_action'
8
8
 
9
+ using TrueExtensions
10
+ using FalseExtensions
11
+ using IntegerExtensions
12
+ using StringExtensions
13
+ using NilExtensions
14
+
9
15
  module GoodData
10
16
  module LCM2
11
17
  # Applies custom MAQL DDL to all client projects so customized
@@ -1,8 +1,14 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
4
+ require 'gooddata/extensions/class'
5
+ require 'gooddata/extensions/true'
6
+ require 'gooddata/extensions/false'
7
+ require 'gooddata/extensions/integer'
8
+ require 'gooddata/extensions/string'
9
+ require 'gooddata/extensions/nil'
10
+
11
+ require 'active_support/core_ext/hash/compact'
6
12
 
7
13
  require_relative '../dsl/dsl'
8
14
  require_relative '../helpers/helpers'
@@ -0,0 +1,46 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+ require_relative 'base_action'
7
+
8
+ module GoodData
9
+ module LCM2
10
+ class CollectMultipleProjectsColumn < BaseAction
11
+ DESCRIPTION = 'Collect multiple_projects_column to be used in user actions'
12
+
13
+ PARAMS = define_params(self) do
14
+ description 'Client Used for Connecting to GD'
15
+ param :gdc_gd_client, instance_of(Type::GdClientType), required: true
16
+
17
+ description 'Identifier of column that identifies the relation to the projects in an user action input'
18
+ param :multiple_projects_column, instance_of(Type::StringType), required: false
19
+
20
+ description 'Synchronization Mode for user action (e.g. sync_one_project_based_on_pid)'
21
+ param :sync_mode, instance_of(Type::StringType), required: false
22
+
23
+ description 'Logger'
24
+ param :gdc_logger, instance_of(Type::GdLogger), required: true
25
+ end
26
+
27
+ CLIENT_ID_MODES = %w(
28
+ sync_domain_client_workspaces
29
+ sync_one_project_based_on_custom_id
30
+ sync_multiple_projects_based_on_custom_id
31
+ )
32
+
33
+ class << self
34
+ def call(params)
35
+ column = params.multiple_projects_column
36
+ column = CLIENT_ID_MODES.include?(params.sync_mode) ? 'client_id' : 'project_id' unless column
37
+
38
+ {
39
+ results: [{ multiple_projects_column: column }],
40
+ params: { multiple_projects_column: column }
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -16,6 +16,9 @@ module GoodData
16
16
  'deletion of filters for a user that is to be removed.'
17
17
  param :users_brick_config, instance_of(Type::UsersBrickConfig), required: true
18
18
 
19
+ description 'Column That Contains Target Project IDs'
20
+ param :multiple_projects_column, instance_of(Type::StringType), required: true
21
+
19
22
  description 'Input Source'
20
23
  param :input_source, instance_of(Type::HashType), required: false
21
24
  end
@@ -36,11 +39,15 @@ module GoodData
36
39
  headers: true,
37
40
  return_headers: false,
38
41
  encoding: 'utf-8') do |row|
39
- users_brick_users << { login: row[login_column] }
42
+ users_brick_users << {
43
+ login: row[login_column],
44
+ pid: row[params.multiple_projects_column]
45
+ }
40
46
  end
41
47
 
42
48
  {
43
- results: users_brick_users,
49
+ # TODO; TMA-989 return the real results when print of results is fixed for large sets
50
+ results: [{ status: 'ok' }],
44
51
  params: {
45
52
  users_brick_users: users_brick_users
46
53
  }
@@ -1,5 +1,3 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
@@ -13,7 +13,7 @@ module GoodData
13
13
 
14
14
  PARAMS = define_params(self) do
15
15
  description 'Message to be printed'
16
- param :message, instance_of(Type::StringType), required: true
16
+ param :message, instance_of(Type::StringType), required: false
17
17
 
18
18
  description 'Number of Iterations'
19
19
  param :iterations, instance_of(Type::IntegerType), required: false, default: 1
@@ -6,6 +6,12 @@
6
6
 
7
7
  require_relative 'base_action'
8
8
 
9
+ using TrueExtensions
10
+ using FalseExtensions
11
+ using IntegerExtensions
12
+ using StringExtensions
13
+ using NilExtensions
14
+
9
15
  module GoodData
10
16
  module LCM2
11
17
  class SynchronizeComputedAttributes < BaseAction
@@ -6,6 +6,12 @@
6
6
 
7
7
  require_relative 'base_action'
8
8
 
9
+ using TrueExtensions
10
+ using FalseExtensions
11
+ using IntegerExtensions
12
+ using StringExtensions
13
+ using NilExtensions
14
+
9
15
  module GoodData
10
16
  module LCM2
11
17
  class SynchronizeLdm < BaseAction
@@ -6,6 +6,12 @@
6
6
 
7
7
  require_relative 'base_action'
8
8
 
9
+ using TrueExtensions
10
+ using FalseExtensions
11
+ using IntegerExtensions
12
+ using StringExtensions
13
+ using NilExtensions
14
+
9
15
  module GoodData
10
16
  module LCM2
11
17
  class SynchronizeUserFilters < BaseAction
@@ -64,7 +70,7 @@ module GoodData
64
70
  param :gdc_project_id, instance_of(Type::StringType), required: false
65
71
 
66
72
  description 'User brick users'
67
- param :users_brick_users, instance_of(Type::ObjectType), required: false
73
+ param :users_brick_users, instance_of(Type::ObjectType), required: false, default: []
68
74
 
69
75
  description 'Makes the brick run without altering user filters'
70
76
  param :dry_run, instance_of(Type::StringType), required: false, default: false
@@ -91,36 +97,19 @@ module GoodData
91
97
  fail "Either project or project_id has to be specified in params" unless project
92
98
  data_product = params.data_product
93
99
 
94
- data_source = GoodData::Helpers::DataSource.new(params.input_source)
95
-
96
100
  config = params.filters_config
97
101
  fail 'User filters brick requires configuration how the filter should be setup. For this use the param "filters_config"' if config.blank?
98
102
  symbolized_config = GoodData::Helpers.deep_dup(config)
99
103
  symbolized_config = GoodData::Helpers.symbolize_keys(symbolized_config)
100
104
  symbolized_config[:labels] = symbolized_config[:labels].map { |l| GoodData::Helpers.symbolize_keys(l) }
101
- headers_in_options = params.csv_headers == 'false' || true
105
+ multiple_projects_column = params.multiple_projects_column
102
106
 
103
107
  mode = params.sync_mode
104
108
  unless MODES.include?(mode)
105
109
  fail "The parameter \"sync_mode\" has to have one of the values #{MODES.map(&:to_s).join(', ')} or has to be empty."
106
110
  end
107
- filters = []
108
-
109
- csv_with_headers = if GoodData::UserFilterBuilder.row_based?(symbolized_config)
110
- false
111
- else
112
- headers_in_options
113
- end
114
111
 
115
- multiple_projects_column = params.multiple_projects_column
116
- unless multiple_projects_column
117
- client_modes = %w(sync_domain_client_workspaces sync_one_project_based_on_custom_id sync_multiple_projects_based_on_custom_id)
118
- multiple_projects_column = if client_modes.include?(mode)
119
- 'client_id'
120
- else
121
- 'project_id'
122
- end
123
- end
112
+ user_filters = load_data(params, symbolized_config)
124
113
 
125
114
  run_params = {
126
115
  restrict_if_missing_all_values: params.restrict_if_missing_all_values == 'true',
@@ -133,85 +122,27 @@ module GoodData
133
122
 
134
123
  puts "Synchronizing in mode \"#{mode}\""
135
124
  case mode
136
- when 'sync_project'
137
- without_check(PARAMS, params) do
138
- CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
139
- filters << row
140
- end
141
- end
142
- filters_to_load = GoodData::UserFilterBuilder.get_filters(filters, symbolized_config)
143
- puts "Synchronizing #{filters_to_load.count} filters"
144
- project.add_data_permissions(filters_to_load, run_params)
145
- when 'sync_one_project_based_on_pid'
146
- without_check(PARAMS, params) do
147
- CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
148
- filters << row if row[multiple_projects_column] == project.pid
149
- end
150
- end
151
- filters_to_load = GoodData::UserFilterBuilder.get_filters(filters, symbolized_config)
152
- puts "Synchronizing #{filters_to_load.count} filters"
153
- project.add_data_permissions(filters_to_load, run_params)
154
- when 'sync_multiple_projects_based_on_pid'
155
- without_check(PARAMS, params) do
156
- CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
157
- filters << row.to_hash
158
- end
159
- end
160
- if filters.empty?
161
- fail 'The filter set can not be empty when using sync_multiple_projects_* mode as the filters contain \
162
- the project ids in which the permissions should be changed'
163
- end
164
- filters.group_by { |u| u[multiple_projects_column] }.flat_map do |project_id, new_filters|
165
- fail "Project id cannot be empty" if project_id.blank?
166
- project = client.projects(project_id)
167
- filters_to_load = GoodData::UserFilterBuilder.get_filters(new_filters, symbolized_config)
168
- puts "Synchronizing #{filters_to_load.count} filters in project #{project.pid}"
169
- project.add_data_permissions(filters_to_load, run_params)
125
+ when 'sync_project', 'sync_one_project_based_on_pid', 'sync_one_project_based_on_custom_id'
126
+ if mode == 'sync_one_project_based_on_pid'
127
+ filter = project.pid
128
+ elsif mode == 'sync_one_project_based_on_custom_id'
129
+ filter = UserBricksHelper.resolve_client_id(domain, project, params.data_product)
170
130
  end
171
- when 'sync_one_project_based_on_custom_id'
172
- filter_value = UserBricksHelper.resolve_client_id(domain, project, data_product)
173
-
174
- filepath = without_check(PARAMS, params) do
175
- File.open(data_source.realize(params), 'r:UTF-8')
176
- end
177
- CSV.foreach(filepath, headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
178
- client_id = row[multiple_projects_column].to_s
179
- filters << row if client_id == filter_value
180
- end
181
-
182
- if filters.empty?
183
- params.gdc_logger.warn "Project \"#{project.pid}\" does not match with any client ids in input source (both GOODOT_CUSTOM_PROJECT_ID and SEGMENT/CLIENT). \
184
- Unable to get the value to filter users."
185
- end
186
-
187
- filters_to_load = GoodData::UserFilterBuilder.get_filters(filters, symbolized_config)
188
- puts "Synchronizing #{filters_to_load.count} filters"
189
- project.add_data_permissions(filters_to_load, run_params)
190
- when 'sync_multiple_projects_based_on_custom_id'
191
- without_check(PARAMS, params) do
192
- CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
193
- filters << row.to_hash
131
+ user_filters = user_filters.select { |f| f[:pid] == filter } if filter
132
+ sync_user_filters(project, user_filters, run_params, symbolized_config)
133
+ when 'sync_multiple_projects_based_on_pid', 'sync_multiple_projects_based_on_custom_id'
134
+ users_by_project = run_params[:users_brick_input].group_by { |u| u[:pid] }
135
+ user_filters.group_by { |u| u[:pid] }.flat_map.pmap do |id, new_filters|
136
+ users = users_by_project[id]
137
+ fail "The #{multiple_projects_column} cannot be empty" if id.blank?
138
+ if mode == 'sync_multiple_projects_based_on_custom_id'
139
+ current_project = domain.clients(id, data_product).project
140
+ elsif mode == 'sync_multiple_projects_based_on_pid'
141
+ current_project = client.projects(id)
194
142
  end
195
- end
196
- if filters.empty?
197
- fail 'The filter set can not be empty when using sync_multiple_projects_* mode as the filters contain \
198
- the project ids in which the permissions should be changed'
199
- end
200
- filters.group_by { |u| u[multiple_projects_column] }.flat_map do |client_id, new_filters|
201
- fail "Client id cannot be empty" if client_id.blank?
202
- project = domain.clients(client_id, data_product).project
203
- fail "Client #{client_id} does not have project." unless project
204
- filters_to_load = GoodData::UserFilterBuilder.get_filters(new_filters, symbolized_config)
205
- puts "Synchronizing #{filters_to_load.count} filters in project #{project.pid} of client #{client_id}"
206
- project.add_data_permissions(filters_to_load, run_params)
143
+ sync_user_filters(current_project, new_filters, run_params.merge(users_brick_input: users), symbolized_config)
207
144
  end
208
145
  when 'sync_domain_client_workspaces'
209
- without_check(PARAMS, params) do
210
- CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
211
- filters << row.to_hash
212
- end
213
- end
214
-
215
146
  domain_clients = domain.clients(:all, data_product)
216
147
  if params.segments
217
148
  segment_uris = params.segments.map(&:uri)
@@ -220,20 +151,20 @@ module GoodData
220
151
 
221
152
  working_client_ids = []
222
153
 
154
+ users_by_project = run_params[:users_brick_input].group_by { |u| u[:pid] }
223
155
  results = []
224
- filters.group_by { |u| u[multiple_projects_column] }.flat_map do |client_id, new_filters|
156
+ user_filters.group_by { |u| u[multiple_projects_column] }.flat_map.pmap do |client_id, new_filters|
157
+ users = users_by_project[client_id]
225
158
  fail "Client id cannot be empty" if client_id.blank?
226
159
  c = domain.clients(client_id, data_product)
227
160
  if params.segments && !segment_uris.include?(c.segment_uri)
228
161
  puts "Client #{client_id} is outside segments_filter #{params.segments}"
229
162
  next
230
163
  end
231
- project = c.project
232
- fail "Client #{client_id} does not have project." unless project
164
+ current_project = c.project
165
+ fail "Client #{client_id} does not have project." unless current_project
233
166
  working_client_ids << client_id
234
- filters_to_load = GoodData::UserFilterBuilder.get_filters(new_filters, symbolized_config)
235
- puts "Synchronizing #{filters_to_load.count} filters in project #{project.pid} of client #{client_id}"
236
- partial_results = project.add_data_permissions(filters_to_load, run_params)
167
+ partial_results = sync_user_filters(current_project, new_filters, run_params.merge(users_brick_input: users), symbolized_config)
237
168
  results.concat(partial_results[:results])
238
169
  end
239
170
 
@@ -241,22 +172,23 @@ module GoodData
241
172
  domain_clients.each do |c|
242
173
  next if working_client_ids.include?(c.client_id)
243
174
  begin
244
- project = c.project
175
+ current_project = c.project
245
176
  rescue => e
246
177
  puts "Error when accessing project of client #{c.client_id}. Error: #{e}"
247
178
  next
248
179
  end
249
- unless project
180
+ unless current_project
250
181
  puts "Client #{c.client_id} has no project."
251
182
  next
252
183
  end
253
- if project.deleted?
254
- puts "Project #{project.pid} of client #{c.client_id} is deleted."
184
+ if current_project.deleted?
185
+ puts "Project #{current_project.pid} of client #{c.client_id} is deleted."
255
186
  next
256
187
  end
257
188
 
258
- puts "Delete all filters in project #{project.pid} of client #{c.client_id}"
259
- delete_results = project.add_data_permissions([], run_params)
189
+ puts "Delete all filters in project #{current_project.pid} of client #{c.client_id}"
190
+ users = users_by_project[c.client_id]
191
+ delete_results = current_project.add_data_permissions([], run_params.merge(users_brick_input: users))
260
192
  results.concat(delete_results[:results])
261
193
  end
262
194
  end
@@ -266,6 +198,37 @@ module GoodData
266
198
  }
267
199
  end
268
200
  end
201
+
202
+ def sync_user_filters(project, filters, params, filters_config)
203
+ # Do not change this line -> can cause paralelisation errors in jRuby viz TMA-963
204
+ project.add_data_permissions(GoodData::UserFilterBuilder.get_filters(filters, filters_config), params)
205
+ end
206
+
207
+ def load_data(params, symbolized_config)
208
+ filters = []
209
+ headers_in_options = params.csv_headers == 'false' || true
210
+ csv_with_headers = if GoodData::UserFilterBuilder.row_based?(symbolized_config)
211
+ false
212
+ else
213
+ headers_in_options
214
+ end
215
+
216
+ multiple_projects_column = params.multiple_projects_column
217
+ data_source = GoodData::Helpers::DataSource.new(params.input_source)
218
+
219
+ without_check(PARAMS, params) do
220
+ CSV.foreach(File.open(data_source.realize(params), 'r:UTF-8'), headers: csv_with_headers, return_headers: false, encoding: 'utf-8') do |row|
221
+ filters << row.to_hash.merge(pid: row[multiple_projects_column])
222
+ end
223
+ end
224
+
225
+ if filters.empty? && %w(sync_multiple_projects_based_on_pid sync_multiple_projects_based_on_custom_id).include?(params.sync_mode)
226
+ fail 'The filter set can not be empty when using sync_multiple_projects_* mode as the filters contain \
227
+ the project ids in which the permissions should be changed'
228
+ end
229
+
230
+ filters
231
+ end
269
232
  end
270
233
  end
271
234
  end