gooddata 0.6.20 → 0.6.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/DEPENDENCIES.md +816 -0
  4. data/LICENSE +1 -1
  5. data/LICENSE.rb +5 -0
  6. data/Rakefile +74 -22
  7. data/dependency_decisions.yml +102 -0
  8. data/gooddata.gemspec +39 -38
  9. data/lib/gooddata.rb +4 -0
  10. data/lib/gooddata/app/app.rb +4 -0
  11. data/lib/gooddata/bricks/base_downloader.rb +5 -1
  12. data/lib/gooddata/bricks/brick.rb +4 -0
  13. data/lib/gooddata/bricks/bricks.rb +5 -0
  14. data/lib/gooddata/bricks/middleware/aws_middleware.rb +5 -0
  15. data/lib/gooddata/bricks/middleware/base_middleware.rb +5 -0
  16. data/lib/gooddata/bricks/middleware/bench_middleware.rb +5 -0
  17. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +5 -0
  18. data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +6 -0
  19. data/lib/gooddata/bricks/middleware/fs_download_middleware.rb +6 -0
  20. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +6 -0
  21. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +6 -0
  22. data/lib/gooddata/bricks/middleware/logger_middleware.rb +5 -0
  23. data/lib/gooddata/bricks/middleware/middleware.rb +5 -0
  24. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +4 -0
  25. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +5 -0
  26. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +5 -0
  27. data/lib/gooddata/bricks/middleware/undot_params_middleware.rb +4 -0
  28. data/lib/gooddata/bricks/pipeline.rb +4 -0
  29. data/lib/gooddata/bricks/utils.rb +4 -0
  30. data/lib/gooddata/cli/cli.rb +4 -0
  31. data/lib/gooddata/cli/commands/api_cmd.rb +4 -0
  32. data/lib/gooddata/cli/commands/auth_cmd.rb +4 -0
  33. data/lib/gooddata/cli/commands/console_cmd.rb +4 -0
  34. data/lib/gooddata/cli/commands/domain_cmd.rb +4 -0
  35. data/lib/gooddata/cli/commands/process_cmd.rb +4 -0
  36. data/lib/gooddata/cli/commands/project_cmd.rb +4 -0
  37. data/lib/gooddata/cli/commands/projects_cmd.rb +4 -0
  38. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +4 -0
  39. data/lib/gooddata/cli/commands/scaffold_cmd.rb +4 -0
  40. data/lib/gooddata/cli/commands/user_cmd.rb +4 -0
  41. data/lib/gooddata/cli/hooks.rb +4 -0
  42. data/lib/gooddata/cli/shared.rb +4 -0
  43. data/lib/gooddata/cli/terminal.rb +4 -0
  44. data/lib/gooddata/client.rb +4 -0
  45. data/lib/gooddata/commands/api.rb +4 -0
  46. data/lib/gooddata/commands/auth.rb +4 -0
  47. data/lib/gooddata/commands/base.rb +4 -0
  48. data/lib/gooddata/commands/commands.rb +5 -0
  49. data/lib/gooddata/commands/datasets.rb +5 -1
  50. data/lib/gooddata/commands/datawarehouse.rb +4 -0
  51. data/lib/gooddata/commands/domain.rb +4 -0
  52. data/lib/gooddata/commands/process.rb +4 -0
  53. data/lib/gooddata/commands/project.rb +7 -9
  54. data/lib/gooddata/commands/projects.rb +4 -0
  55. data/lib/gooddata/commands/role.rb +4 -0
  56. data/lib/gooddata/commands/runners.rb +4 -0
  57. data/lib/gooddata/commands/scaffold.rb +4 -0
  58. data/lib/gooddata/commands/user.rb +4 -0
  59. data/lib/gooddata/connection.rb +83 -0
  60. data/lib/gooddata/core/core.rb +4 -0
  61. data/lib/gooddata/core/logging.rb +4 -0
  62. data/lib/gooddata/core/nil_logger.rb +4 -0
  63. data/lib/gooddata/core/project.rb +4 -0
  64. data/lib/gooddata/core/rest.rb +14 -16
  65. data/lib/gooddata/core/user.rb +4 -0
  66. data/lib/gooddata/data/data.rb +4 -0
  67. data/lib/gooddata/data/guesser.rb +4 -0
  68. data/lib/gooddata/exceptions/attr_element_not_found.rb +4 -0
  69. data/lib/gooddata/exceptions/command_failed.rb +4 -0
  70. data/lib/gooddata/exceptions/exceptions.rb +4 -0
  71. data/lib/gooddata/exceptions/execution_limit_exceeded.rb +4 -0
  72. data/lib/gooddata/exceptions/filter_maqlization.rb +16 -0
  73. data/lib/gooddata/exceptions/malformed_user.rb +15 -0
  74. data/lib/gooddata/exceptions/no_project_error.rb +4 -0
  75. data/lib/gooddata/exceptions/object_migration.rb +28 -0
  76. data/lib/gooddata/exceptions/project_not_found.rb +5 -0
  77. data/lib/gooddata/exceptions/uncomputable_report.rb +5 -0
  78. data/lib/gooddata/exceptions/user_in_different_domain.rb +4 -0
  79. data/lib/gooddata/exceptions/validation_error.rb +4 -0
  80. data/lib/gooddata/extensions/big_decimal.rb +4 -0
  81. data/lib/gooddata/extensions/enumerable.rb +4 -0
  82. data/lib/gooddata/extensions/extensions.rb +4 -0
  83. data/lib/gooddata/extensions/false.rb +4 -0
  84. data/lib/gooddata/extensions/hash.rb +4 -0
  85. data/lib/gooddata/extensions/nil.rb +4 -0
  86. data/lib/gooddata/extensions/numeric.rb +4 -0
  87. data/lib/gooddata/extensions/object.rb +4 -0
  88. data/lib/gooddata/extensions/symbol.rb +4 -0
  89. data/lib/gooddata/extensions/true.rb +4 -0
  90. data/lib/gooddata/extract.rb +4 -0
  91. data/lib/gooddata/goodzilla/goodzilla.rb +87 -77
  92. data/lib/gooddata/helpers/auth_helpers.rb +6 -2
  93. data/lib/gooddata/helpers/csv_helper.rb +4 -0
  94. data/lib/gooddata/helpers/data_helper.rb +4 -0
  95. data/lib/gooddata/helpers/global_helpers.rb +35 -6
  96. data/lib/gooddata/helpers/global_helpers_params.rb +34 -7
  97. data/lib/gooddata/helpers/helpers.rb +4 -0
  98. data/lib/gooddata/mixins/author.rb +4 -0
  99. data/lib/gooddata/mixins/content_getter.rb +4 -0
  100. data/lib/gooddata/mixins/content_property_reader.rb +4 -0
  101. data/lib/gooddata/mixins/content_property_writer.rb +4 -0
  102. data/lib/gooddata/mixins/contributor.rb +4 -0
  103. data/lib/gooddata/mixins/data_getter.rb +4 -0
  104. data/lib/gooddata/mixins/data_property_reader.rb +4 -0
  105. data/lib/gooddata/mixins/data_property_writer.rb +4 -0
  106. data/lib/gooddata/mixins/inspector.rb +4 -0
  107. data/lib/gooddata/mixins/is_attribute.rb +4 -0
  108. data/lib/gooddata/mixins/is_dimension.rb +4 -0
  109. data/lib/gooddata/mixins/is_fact.rb +4 -0
  110. data/lib/gooddata/mixins/is_label.rb +4 -0
  111. data/lib/gooddata/mixins/links.rb +4 -0
  112. data/lib/gooddata/mixins/md_finders.rb +4 -0
  113. data/lib/gooddata/mixins/md_id_to_uri.rb +4 -0
  114. data/lib/gooddata/mixins/md_json.rb +4 -0
  115. data/lib/gooddata/mixins/md_lock.rb +4 -0
  116. data/lib/gooddata/mixins/md_object_id.rb +5 -1
  117. data/lib/gooddata/mixins/md_object_indexer.rb +4 -0
  118. data/lib/gooddata/mixins/md_object_query.rb +4 -0
  119. data/lib/gooddata/mixins/md_relations.rb +4 -0
  120. data/lib/gooddata/mixins/meta_getter.rb +4 -0
  121. data/lib/gooddata/mixins/meta_property_reader.rb +4 -0
  122. data/lib/gooddata/mixins/meta_property_writer.rb +4 -0
  123. data/lib/gooddata/mixins/mixins.rb +4 -0
  124. data/lib/gooddata/mixins/not_attribute.rb +4 -0
  125. data/lib/gooddata/mixins/not_exportable.rb +4 -0
  126. data/lib/gooddata/mixins/not_fact.rb +4 -0
  127. data/lib/gooddata/mixins/not_label.rb +4 -0
  128. data/lib/gooddata/mixins/not_metric.rb +6 -0
  129. data/lib/gooddata/mixins/obj_id.rb +4 -0
  130. data/lib/gooddata/mixins/rest_getters.rb +4 -0
  131. data/lib/gooddata/mixins/rest_resource.rb +4 -0
  132. data/lib/gooddata/mixins/root_key_getter.rb +4 -0
  133. data/lib/gooddata/mixins/root_key_setter.rb +4 -0
  134. data/lib/gooddata/mixins/timestamps.rb +4 -0
  135. data/lib/gooddata/models/blueprint/anchor_field.rb +4 -0
  136. data/lib/gooddata/models/blueprint/attribute_field.rb +4 -0
  137. data/lib/gooddata/models/blueprint/blueprint.rb +4 -0
  138. data/lib/gooddata/models/blueprint/blueprint_field.rb +4 -0
  139. data/lib/gooddata/models/blueprint/dashboard_builder.rb +4 -0
  140. data/lib/gooddata/models/blueprint/dataset_blueprint.rb +6 -0
  141. data/lib/gooddata/models/blueprint/date_dimension.rb +4 -0
  142. data/lib/gooddata/models/blueprint/fact_field.rb +4 -0
  143. data/lib/gooddata/models/blueprint/label_field.rb +4 -0
  144. data/lib/gooddata/models/blueprint/project_blueprint.rb +6 -0
  145. data/lib/gooddata/models/blueprint/project_builder.rb +4 -0
  146. data/lib/gooddata/models/blueprint/reference_field.rb +4 -0
  147. data/lib/gooddata/models/blueprint/schema_blueprint.rb +4 -0
  148. data/lib/gooddata/models/blueprint/schema_builder.rb +4 -0
  149. data/lib/gooddata/models/blueprint/to_manifest.rb +17 -1
  150. data/lib/gooddata/models/blueprint/to_wire.rb +4 -0
  151. data/lib/gooddata/models/datawarehouse.rb +5 -0
  152. data/lib/gooddata/models/domain.rb +25 -7
  153. data/lib/gooddata/models/execution.rb +4 -0
  154. data/lib/gooddata/models/execution_detail.rb +4 -0
  155. data/lib/gooddata/models/from_wire.rb +4 -0
  156. data/lib/gooddata/models/invitation.rb +4 -0
  157. data/lib/gooddata/models/links.rb +4 -0
  158. data/lib/gooddata/models/membership.rb +4 -0
  159. data/lib/gooddata/models/metadata.rb +37 -10
  160. data/lib/gooddata/models/metadata/attribute.rb +6 -0
  161. data/lib/gooddata/models/metadata/dashboard.rb +54 -16
  162. data/lib/gooddata/models/metadata/dashboard/dashboard_item.rb +60 -0
  163. data/lib/gooddata/models/metadata/dashboard/filter_item.rb +15 -0
  164. data/lib/gooddata/models/metadata/dashboard/report_item.rb +51 -0
  165. data/lib/gooddata/models/metadata/dashboard_tab.rb +88 -0
  166. data/lib/gooddata/models/metadata/dataset.rb +4 -0
  167. data/lib/gooddata/models/metadata/dimension.rb +4 -0
  168. data/lib/gooddata/models/metadata/fact.rb +6 -0
  169. data/lib/gooddata/models/metadata/label.rb +15 -0
  170. data/lib/gooddata/models/metadata/metadata.rb +4 -0
  171. data/lib/gooddata/models/metadata/metric.rb +5 -4
  172. data/lib/gooddata/models/metadata/report.rb +62 -16
  173. data/lib/gooddata/models/metadata/report_definition.rb +44 -47
  174. data/lib/gooddata/models/metadata/variable.rb +4 -0
  175. data/lib/gooddata/models/model.rb +85 -36
  176. data/lib/gooddata/models/models.rb +4 -0
  177. data/lib/gooddata/models/module_constants.rb +4 -0
  178. data/lib/gooddata/models/process.rb +4 -0
  179. data/lib/gooddata/models/profile.rb +13 -0
  180. data/lib/gooddata/models/project.rb +173 -92
  181. data/lib/gooddata/models/project_creator.rb +18 -10
  182. data/lib/gooddata/models/project_metadata.rb +4 -0
  183. data/lib/gooddata/models/project_role.rb +4 -0
  184. data/lib/gooddata/models/report_data_result.rb +217 -125
  185. data/lib/gooddata/models/schedule.rb +140 -65
  186. data/lib/gooddata/models/tab_builder.rb +4 -0
  187. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +4 -0
  188. data/lib/gooddata/models/user_filters/user_filter.rb +4 -0
  189. data/lib/gooddata/models/user_filters/user_filter_builder.rb +98 -56
  190. data/lib/gooddata/models/user_filters/user_filters.rb +4 -0
  191. data/lib/gooddata/models/user_filters/variable_user_filter.rb +4 -0
  192. data/lib/gooddata/rest/client.rb +41 -38
  193. data/lib/gooddata/rest/connection.rb +91 -20
  194. data/lib/gooddata/rest/connections/rest_client_connection.rb +5 -1
  195. data/lib/gooddata/rest/object.rb +9 -1
  196. data/lib/gooddata/rest/object_factory.rb +5 -1
  197. data/lib/gooddata/rest/resource.rb +5 -1
  198. data/lib/gooddata/rest/rest.rb +4 -0
  199. data/lib/gooddata/version.rb +5 -1
  200. data/spec/bricks/bricks_spec.rb +4 -0
  201. data/spec/data/blueprints/test_project_model_spec.json +2 -2
  202. data/spec/data/gooddata_version_process/gooddata_version.rb +6 -0
  203. data/spec/data/hello_world_process/hello_world.rb +6 -0
  204. data/spec/data/manifests/test_project.json +5 -5
  205. data/spec/data/reports/left_attr_report.json +108 -0
  206. data/spec/data/reports/metric_only_one_line.json +83 -0
  207. data/spec/data/reports/report_1.json +197 -0
  208. data/spec/data/reports/top_attr_report.json +108 -0
  209. data/spec/data/ruby_params_process/ruby_params.rb +6 -0
  210. data/spec/data/ruby_process/process.rb +6 -0
  211. data/spec/environment/default.rb +5 -0
  212. data/spec/environment/develop.rb +10 -5
  213. data/spec/environment/environment.rb +4 -0
  214. data/spec/environment/hotfix.rb +5 -1
  215. data/spec/environment/production.rb +4 -0
  216. data/spec/environment/release.rb +4 -0
  217. data/spec/environment/staging.rb +30 -0
  218. data/spec/environment/staging_3.rb +37 -0
  219. data/spec/helpers/blueprint_helper.rb +4 -0
  220. data/spec/helpers/cli_helper.rb +4 -0
  221. data/spec/helpers/connection_helper.rb +24 -17
  222. data/spec/helpers/crypto_helper.rb +6 -0
  223. data/spec/helpers/csv_helper.rb +4 -0
  224. data/spec/helpers/process_helper.rb +5 -1
  225. data/spec/helpers/project_helper.rb +34 -29
  226. data/spec/helpers/schedule_helper.rb +4 -0
  227. data/spec/helpers/spec_helper.rb +4 -0
  228. data/spec/integration/blueprint_updates_spec.rb +28 -20
  229. data/spec/integration/command_datawarehouse_spec.rb +6 -0
  230. data/spec/integration/command_projects_spec.rb +6 -4
  231. data/spec/integration/create_from_template_spec.rb +6 -0
  232. data/spec/integration/create_project_spec.rb +6 -0
  233. data/spec/integration/deprecated_load_spec.rb +58 -0
  234. data/spec/integration/full_process_schedule_spec.rb +9 -0
  235. data/spec/integration/full_project_spec.rb +63 -9
  236. data/spec/integration/over_to_user_filters_spec.rb +7 -2
  237. data/spec/integration/partial_md_export_import_spec.rb +6 -0
  238. data/spec/integration/project_spec.rb +12 -6
  239. data/spec/integration/rest_spec.rb +6 -2
  240. data/spec/integration/schedule_spec.rb +627 -0
  241. data/spec/integration/user_filters_spec.rb +122 -21
  242. data/spec/integration/variables_spec.rb +8 -15
  243. data/spec/logging_in_logging_out_spec.rb +58 -0
  244. data/spec/spec_helper.rb +10 -5
  245. data/spec/unit/bricks/bricks_spec.rb +4 -0
  246. data/spec/unit/bricks/middleware/aws_middelware_spec.rb +4 -0
  247. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +4 -0
  248. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +4 -0
  249. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +4 -0
  250. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +4 -0
  251. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +4 -0
  252. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +4 -0
  253. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +4 -0
  254. data/spec/unit/cli/cli_spec.rb +4 -0
  255. data/spec/unit/cli/commands/cmd_api_spec.rb +4 -0
  256. data/spec/unit/cli/commands/cmd_auth_spec.rb +4 -0
  257. data/spec/unit/cli/commands/cmd_domain_spec.rb +4 -0
  258. data/spec/unit/cli/commands/cmd_process_spec.rb +4 -0
  259. data/spec/unit/cli/commands/cmd_project_spec.rb +4 -0
  260. data/spec/unit/cli/commands/cmd_role_spec.rb +4 -0
  261. data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +4 -0
  262. data/spec/unit/cli/commands/cmd_scaffold_spec.rb +6 -0
  263. data/spec/unit/cli/commands/cmd_user_spec.rb +6 -0
  264. data/spec/unit/commands/command_api_spec.rb +6 -0
  265. data/spec/unit/commands/command_auth_spec.rb +6 -0
  266. data/spec/unit/commands/command_dataset_spec.rb +10 -4
  267. data/spec/unit/commands/command_process_spec.rb +6 -0
  268. data/spec/unit/commands/command_projects_spec.rb +6 -0
  269. data/spec/unit/commands/command_scaffold_spec.rb +6 -0
  270. data/spec/unit/commands/command_user_spec.rb +6 -0
  271. data/spec/unit/core/connection_spec.rb +6 -0
  272. data/spec/unit/core/logging_spec.rb +4 -0
  273. data/spec/unit/core/nil_logger_spec.rb +4 -0
  274. data/spec/unit/core/project_spec.rb +4 -0
  275. data/spec/unit/data/guesser_spec.rb +6 -2
  276. data/spec/unit/extensions/hash_spec.rb +4 -0
  277. data/spec/unit/godzilla/goodzilla_spec.rb +4 -0
  278. data/spec/unit/helpers/csv_helper_spec.rb +4 -0
  279. data/spec/unit/helpers/data_helper_spec.rb +4 -0
  280. data/spec/unit/helpers/global_helpers_spec.rb +54 -0
  281. data/spec/unit/helpers_spec.rb +6 -1
  282. data/spec/unit/models/blueprint/attributes_spec.rb +5 -0
  283. data/spec/unit/models/blueprint/dataset_spec.rb +5 -0
  284. data/spec/unit/models/blueprint/labels_spec.rb +5 -0
  285. data/spec/unit/models/blueprint/project_blueprint_spec.rb +5 -0
  286. data/spec/unit/models/blueprint/reference_spec.rb +5 -0
  287. data/spec/unit/models/blueprint/schema_builder_spec.rb +4 -0
  288. data/spec/unit/models/blueprint/to_wire_spec.rb +5 -0
  289. data/spec/unit/models/domain_spec.rb +9 -7
  290. data/spec/unit/models/execution_spec.rb +6 -0
  291. data/spec/unit/models/from_wire_spec.rb +4 -0
  292. data/spec/unit/models/invitation_spec.rb +4 -0
  293. data/spec/unit/models/membership_spec.rb +4 -0
  294. data/spec/unit/models/metadata_spec.rb +46 -0
  295. data/spec/unit/models/metric_spec.rb +4 -0
  296. data/spec/unit/models/model_spec.rb +4 -0
  297. data/spec/unit/models/params_spec.rb +4 -0
  298. data/spec/unit/models/profile_spec.rb +4 -0
  299. data/spec/unit/models/project_creator_spec.rb +127 -0
  300. data/spec/unit/models/project_role_spec.rb +4 -0
  301. data/spec/unit/models/project_spec.rb +4 -0
  302. data/spec/unit/models/report_result_data_spec.rb +193 -0
  303. data/spec/unit/models/schedule_spec.rb +241 -386
  304. data/spec/unit/models/to_manifest_spec.rb +21 -0
  305. data/spec/unit/models/{unit_project.rb → unit_project_spec.rb} +21 -18
  306. data/spec/unit/models/user_filters_spec.rb +7 -1
  307. data/spec/unit/models/variable_spec.rb +6 -0
  308. data/spec/unit/rest/polling_spec.rb +8 -5
  309. data/spec/unit/rest/resource_spec.rb +4 -0
  310. metadata +190 -129
  311. data/.autotest +0 -2
  312. data/.travis.yml +0 -22
  313. data/examples.rb +0 -69
  314. data/lib/gooddata/models/data_result.rb +0 -38
  315. data/lib/gooddata/models/empty_result.rb +0 -57
  316. data/spec/unit/models/project_creator.rb +0 -73
@@ -1,4 +1,8 @@
1
1
  # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 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.
2
6
 
3
7
  require 'pry'
4
8
  require 'zip'
@@ -1,4 +1,8 @@
1
1
  # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 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.
2
6
 
3
7
  require 'pmap'
4
8
 
@@ -373,6 +377,15 @@ module GoodData
373
377
  (first_name || '') + (last_name || '')
374
378
  end
375
379
 
380
+ def password
381
+ @json['accountSetting']['password']
382
+ end
383
+
384
+ def password=(a_password)
385
+ @dirty = true
386
+ @json['accountSetting']['password'] = a_password
387
+ end
388
+
376
389
  def sso_provider
377
390
  @json['accountSetting']['ssoProvider']
378
391
  end
@@ -1,4 +1,8 @@
1
1
  # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 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.
2
6
 
3
7
  require 'csv'
4
8
  require 'zip'
@@ -171,6 +175,12 @@ module GoodData
171
175
  end
172
176
  end
173
177
 
178
+ def add_dashboard(dashboard)
179
+ GoodData::Dashboard.create(dashboard, :client => client, :project => self)
180
+ end
181
+
182
+ alias_method :create_dashboard, :add_dashboard
183
+
174
184
  # Creates a metric in a project
175
185
  #
176
186
  # @param [options] Optional report options
@@ -186,6 +196,9 @@ module GoodData
186
196
 
187
197
  alias_method :create_metric, :add_metric
188
198
 
199
+ alias_method :add_measure, :add_metric
200
+ alias_method :create_measure, :add_metric
201
+
189
202
  # Creates new instance of report in context of project
190
203
  #
191
204
  # @param [options] Optional report options
@@ -246,7 +259,7 @@ module GoodData
246
259
  #
247
260
  # @return [GoodData::ProjectRole] Project role if found
248
261
  def blueprint(options = {})
249
- result = client.get("/gdc/projects/#{pid}/model/view")
262
+ result = client.get("/gdc/projects/#{pid}/model/view", params: { includeDeprecated: true })
250
263
  polling_url = result['asyncTask']['link']['poll']
251
264
  model = client.poll_on_code(polling_url, options)
252
265
  bp = GoodData::Model::FromWire.from_wire(model)
@@ -259,10 +272,11 @@ module GoodData
259
272
  # @return [String] Project URL
260
273
  def browser_uri(options = {})
261
274
  grey = options[:grey]
275
+ server = client.connection.server_url
262
276
  if grey
263
- client.connection.url + uri
277
+ "#{server}#{uri}"
264
278
  else
265
- client.connection.url + '#s=' + uri
279
+ "#{server}/#s=#{uri}"
266
280
  end
267
281
  end
268
282
 
@@ -358,8 +372,11 @@ module GoodData
358
372
  GoodData::Metric.xexecute(expression, client: client, project: self)
359
373
  end
360
374
 
375
+ alias_method :compute_measure, :compute_metric
376
+
361
377
  def create_schedule(process, date, executable, options = {})
362
- GoodData::Schedule.create(process, date, executable, options.merge(client: client, project: self))
378
+ s = GoodData::Schedule.create(process, date, executable, options.merge(client: client, project: self))
379
+ s.save
363
380
  end
364
381
 
365
382
  def create_variable(data)
@@ -533,15 +550,8 @@ module GoodData
533
550
  end
534
551
  end
535
552
 
536
- # Get WebDav directory for user data
537
- # @return [String]
538
- def user_webdav_path
539
- u = URI(links['uploads'])
540
- URI.join(u.to_s.chomp(u.path.to_s), '/uploads/')
541
- end
542
-
543
- def upload_file(file)
544
- GoodData.upload_to_project_webdav(file, project: self)
553
+ def upload_file(file, options = {})
554
+ GoodData.upload_to_project_webdav(file, options.merge(project: self))
545
555
  end
546
556
 
547
557
  def download_file(file, where)
@@ -690,14 +700,20 @@ module GoodData
690
700
  GoodData::Metric[id, opts.merge(project: self, client: client)]
691
701
  end
692
702
 
703
+ alias_method :measures, :metrics
704
+
693
705
  def metric_by_title(title)
694
706
  GoodData::Metric.find_first_by_title(title, project: self, client: client)
695
707
  end
696
708
 
709
+ alias_method :measure_by_title, :metric_by_title
710
+
697
711
  def metrics_by_title(title)
698
712
  GoodData::Metric.find_by_title(title, project: self, client: client)
699
713
  end
700
714
 
715
+ alias_method :measures_by_title, :metrics_by_title
716
+
701
717
  # Checks if the profile is member of project
702
718
  #
703
719
  # @param [GoodData::Profile] profile - Profile to be checked
@@ -727,18 +743,23 @@ module GoodData
727
743
  GoodData::MdObject[id, opts.merge(project: self, client: client)]
728
744
  end
729
745
 
730
- def partial_md_export(objs, options = {})
746
+ # Transfer objects from one project to another
747
+ #
748
+ # @param [Array<GoodData::MdObject | String>, String, GoodData::MdObject] objs Any representation of the object or a list of those
749
+ # @param [Hash] options The options to migration.
750
+ # @option options [Number] :time_limit Time in seconds before the blocking call will fail. See GoodData::Rest::Client.poll_on_response for additional details
751
+ # @option options [Number] :sleep_interval Interval between polls on the status of the migration.
752
+ # @return [String] Returns token that you can use as input for object_import
753
+ def objects_export(objs, options = {})
731
754
  fail 'Nothing to migrate. You have to pass list of objects, ids or uris that you would like to migrate' if objs.nil?
732
- objs = [objs] unless objs.is_a?(Array)
755
+ objs = Array(objs)
733
756
  fail 'Nothing to migrate. The list you provided is empty' if objs.empty?
734
757
 
735
- target_project = options[:project]
736
- fail 'You have to provide a project instance or project pid to migrate to' if target_project.nil?
737
- target_project = client.projects(target_project)
738
- objs = objs.pmap { |obj| objects(obj) }
758
+ objs = objs.pmap { |obj| [obj, objects(obj)] }
759
+ fail ObjectsExportError, "Exporting objects failed with messages. Object #{objs.select { |_, obj| obj.nil? }.map { |o, _| o }.join(', ')} could not be found." if objs.any? { |_, obj| obj.nil? }
739
760
  export_payload = {
740
761
  :partialMDExport => {
741
- :uris => objs.map(&:uri)
762
+ :uris => objs.map { |_, obj| obj.uri }
742
763
  }
743
764
  }
744
765
  result = client.post("#{md['maintenance']}/partialmdexport", export_payload)
@@ -748,8 +769,22 @@ module GoodData
748
769
  polling_result = client.poll_on_response(polling_url, options) do |body|
749
770
  body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
750
771
  end
772
+ if polling_result['wTaskStatus'] && polling_result['wTaskStatus']['status'] == 'ERROR'
773
+ messages = GoodData::Helpers.interpolate_error_messages(polling_result['wTaskStatus']['messages']).join(' ')
774
+ fail ObjectsExportError, "Exporting objects failed with messages. #{messages}"
775
+ end
776
+ token
777
+ end
751
778
 
752
- fail 'Exporting objects failed' if polling_result['wTaskStatus'] && polling_result['wTaskStatus']['status'] == 'ERROR'
779
+ # Import objects from import token. If you do not need specifically this method what you are probably looking for is transfer_objects. This is a lower level method.
780
+ #
781
+ # @param [String] token Migration token ID
782
+ # @param [Hash] options The options to migration.
783
+ # @option options [Number] :time_limit Time in seconds before the blocking call will fail. See GoodData::Rest::Client.poll_on_response for additional details
784
+ # @option options [Number] :sleep_interval Interval between polls on the status of the migration.
785
+ # @return [Boolean] Returns true if it succeeds or throws exceoption
786
+ def objects_import(token, options = {})
787
+ fail 'You need to provide a token for object import' if token.blank?
753
788
 
754
789
  import_payload = {
755
790
  :partialMDImport => {
@@ -759,14 +794,56 @@ module GoodData
759
794
  }
760
795
  }
761
796
 
762
- result = client.post("#{target_project.md['maintenance']}/partialmdimport", import_payload)
797
+ result = client.post("#{md['maintenance']}/partialmdimport", import_payload)
763
798
  polling_url = result['uri']
764
799
 
765
- client.poll_on_response(polling_url, options) do |body|
800
+ polling_result = client.poll_on_response(polling_url, options) do |body|
766
801
  body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
767
802
  end
768
803
 
769
- fail 'Exporting objects failed' if polling_result['wTaskStatus']['status'] == 'ERROR'
804
+ if polling_result['wTaskStatus']['status'] == 'ERROR'
805
+ messages = GoodData::Helpers.interpolate_error_messages(polling_result['wTaskStatus']['messages']).join(' ')
806
+ fail ObjectsImportError, "Importing objects failed with messages. #{messages}"
807
+ end
808
+ true
809
+ end
810
+
811
+ # Transfer objects from one project to another
812
+ #
813
+ # @param [Array<GoodData::MdObject | String>, String, GoodData::MdObject] objects Any representation of the object or a list of those
814
+ # @param [Hash] options The options to migration.
815
+ # @option options [GoodData::Project | String | Array<String> | Array<GoodData::Project>] :project Project(s) to migrate to
816
+ # @option options [Number] :batch_size Number of projects that are migrated at the same time. Default is 10
817
+ #
818
+ # @return [Boolean | Array<Hash>] Return either true or throws exception if you passed only one project. If you provided an array returns list of hashes signifying sucees or failure. Take note that in case of list of projects it does not throw exception
819
+ def partial_md_export(objects, options = {})
820
+ projects = options[:project]
821
+ batch_size = options[:batch_size] || 10
822
+ token = objects_export(objects)
823
+
824
+ if projects.is_a?(Array)
825
+ projects.each_slice(batch_size).flat_map do |batch|
826
+ batch.pmap do |proj|
827
+ target_project = client.projects(proj)
828
+ begin
829
+ target_project.objects_import(token, options)
830
+ {
831
+ project: target_project,
832
+ result: true
833
+ }
834
+ rescue GoodData::ObjectsImportError => e
835
+ {
836
+ project: target_project,
837
+ result: false,
838
+ reason: e.message
839
+ }
840
+ end
841
+ end
842
+ end
843
+ else
844
+ target_project = client.projects(projects)
845
+ target_project.objects_import(token, options)
846
+ end
770
847
  end
771
848
 
772
849
  alias_method :transfer_objects, :partial_md_export
@@ -1030,14 +1107,6 @@ module GoodData
1030
1107
  self
1031
1108
  end
1032
1109
 
1033
- # Checks if is project saved
1034
- #
1035
- # @return [Boolean] True if saved, false if not
1036
- def saved?
1037
- res = uri.nil?
1038
- !res
1039
- end
1040
-
1041
1110
  # @param [String | Number | Object] Anything that you can pass to GoodData::Schedule[id]
1042
1111
  # @return [GoodData::Schedule | Array<GoodData::Schedule>] schedule instance or list
1043
1112
  def schedules(id = :all)
@@ -1078,6 +1147,10 @@ module GoodData
1078
1147
  GoodData::Model.upload_data(data, blueprint, dataset_name, options.merge(client: client, project: self))
1079
1148
  end
1080
1149
 
1150
+ def upload_multiple(data, blueprint, options = {})
1151
+ GoodData::Model.upload_multiple_data(data, blueprint, options.merge(client: client, project: self))
1152
+ end
1153
+
1081
1154
  def uri
1082
1155
  data['links']['self'] if data && data['links'] && data['links']['self']
1083
1156
  end
@@ -1107,7 +1180,7 @@ module GoodData
1107
1180
  tmp = client.get("/gdc/projects/#{pid}/users", params: { offset: offset, limit: limit })
1108
1181
  tmp['users'].each do |user_data|
1109
1182
  user = client.create(GoodData::Membership, user_data, project: self)
1110
- y << user if opts[:all] || user.enabled?
1183
+ y << user if opts[:all] || user && user.enabled?
1111
1184
  end
1112
1185
  break if tmp['users'].count < limit
1113
1186
  offset += limit
@@ -1133,7 +1206,6 @@ module GoodData
1133
1206
 
1134
1207
  # Imports users
1135
1208
  def import_users(new_users, options = {})
1136
- domain = options[:domain]
1137
1209
  role_list = roles
1138
1210
  users_list = users(all: true)
1139
1211
  new_users = new_users.map { |x| (x.is_a?(Hash) && x[:user] && x[:user].to_hash.merge(role: x[:role])) || x.to_hash }
@@ -1148,29 +1220,35 @@ module GoodData
1148
1220
  u
1149
1221
  end
1150
1222
 
1151
- diffable_new = diffable_new_with_default_role.map do |u|
1223
+ intermediate_new = diffable_new_with_default_role.map do |u|
1152
1224
  u[:role] = u[:role].map do |r|
1153
1225
  role = get_role(r, role_list)
1154
1226
  role && role.uri
1155
1227
  end
1228
+
1229
+ if u[:role].all?(&:nil?)
1230
+ u[:type] = :error
1231
+ u[:reason] = 'Invalid role(s) specified'
1232
+ else
1233
+ u[:type] = :ok
1234
+ end
1235
+
1156
1236
  u[:status] = 'ENABLED'
1157
1237
  u
1158
1238
  end
1159
1239
 
1240
+ intermediate_new_by_type = intermediate_new.group_by { |i| i[:type] }
1241
+ diffable_new = intermediate_new_by_type[:ok] || []
1242
+
1160
1243
  # Diff users. Only login and role is important for the diff
1161
1244
  diff = GoodData::Helpers.diff(whitelisted_users, diffable_new, key: :login, fields: [:login, :role, :status])
1162
1245
 
1163
- results = []
1164
1246
  # Create new users
1165
- u = diff[:added].map do |x|
1166
- {
1167
- user: x,
1168
- role: x[:role]
1169
- }
1170
- end
1171
- # This is only creating users that were not in the proejcts so far. This means this will reach into domain
1247
+ u = diff[:added].map { |x| { user: x, role: x[:role] } }
1248
+
1249
+ results = []
1172
1250
  GoodData.logger.warn("Creating #{diff[:added].count} users in project (#{pid})")
1173
- results.concat create_users(u, roles: role_list, domain: domain, project_users: whitelisted_users, only_domain: true)
1251
+ results.concat(create_users(u, roles: role_list, project_users: whitelisted_users))
1174
1252
 
1175
1253
  # # Update existing users
1176
1254
  GoodData.logger.warn("Updating #{diff[:changed].count} users in project (#{pid})")
@@ -1179,9 +1257,8 @@ module GoodData
1179
1257
 
1180
1258
  # Remove old users
1181
1259
  to_remove = diff[:removed].reject { |user| user[:status] == 'DISABLED' || user[:status] == :disabled }
1182
- GoodData.logger.warn("Removing #{to_remove.count} users in project (#{pid})")
1260
+ GoodData.logger.warn("Removing #{to_remove.count} users from project (#{pid})")
1183
1261
  results.concat(disable_users(to_remove))
1184
- results
1185
1262
  end
1186
1263
 
1187
1264
  def disable_users(list)
@@ -1190,46 +1267,26 @@ module GoodData
1190
1267
  payloads = list.map do |u|
1191
1268
  generate_user_payload(u[:uri], 'DISABLED')
1192
1269
  end
1270
+
1193
1271
  payloads.each_slice(100).mapcat do |payload|
1194
1272
  result = client.post(url, 'users' => payload)
1195
1273
  result['projectUsersUpdateResult'].mapcat { |k, v| v.map { |x| { type: k.to_sym, uri: x } } }
1196
1274
  end
1197
1275
  end
1198
1276
 
1199
- def verify_user_to_add(login, desired_roles, options = {})
1200
- user = login if login.respond_to?(:uri) && !login.uri.nil?
1201
- role_list = options[:roles] || roles
1202
- desired_roles = Array(desired_roles)
1203
- roles = desired_roles.map do |role_name|
1204
- role = get_role(role_name, role_list)
1205
- fail ArgumentError, "Invalid role '#{role_name}' specified for user '#{user.email}'" if role.nil?
1206
- role.uri
1207
- end
1208
- return [user.uri, roles] if user
1209
-
1210
- domain = client.domain(options[:domain]) if options[:domain]
1211
- domain_users = options[:domain_users] || (domain && domain.users)
1212
- project_users = options[:project_users] || users
1213
-
1214
- project_user = get_user(login, project_users)
1215
- domain_user = if domain && !project_user && !user
1216
- domain.get_user(login, domain_users) if domain && !project_user
1217
- end
1218
- user = project_user || domain_user
1219
- fail ArgumentError, "Invalid user '#{login}' specified" unless user
1220
- [user.uri, roles]
1221
- end
1222
-
1223
1277
  # Update user
1224
1278
  #
1225
1279
  # @param user User to be updated
1226
1280
  # @param desired_roles Roles to be assigned to user
1227
1281
  # @param role_list Optional cached list of roles used for lookups
1228
1282
  def set_user_roles(login, desired_roles, options = {})
1229
- user_uri, roles = verify_user_to_add(login, desired_roles, options)
1283
+ user_uri, roles = resolve_roles(login, desired_roles, options)
1230
1284
  url = "#{uri}/users"
1231
1285
  payload = generate_user_payload(user_uri, 'ENABLED', roles)
1232
- client.post(url, payload)
1286
+ res = client.post(url, payload)
1287
+ failure = GoodData::Helpers.get_path(res, %w(projectUsersUpdateResult failed))
1288
+ fail ArgumentError, "User #{user_uri} could not be aded. #{failure.first['message']}" unless failure.blank?
1289
+ res
1233
1290
  end
1234
1291
 
1235
1292
  alias_method :add_user, :set_user_roles
@@ -1242,33 +1299,30 @@ module GoodData
1242
1299
  return [] if list.empty?
1243
1300
  role_list = options[:roles] || roles
1244
1301
  project_users = options[:project_users] || users
1245
- domain = options[:domain] && client.domain(options[:domain])
1246
- domain_users = if domain.nil?
1247
- options[:domain_users]
1248
- else
1249
- if options[:only_domain] && list.count < 100
1250
- list.map { |l| domain.find_user_by_login(l[:user][:login]) }
1251
- else
1252
- domain.users
1253
- end
1254
- end
1255
-
1256
- users_to_add = list.flat_map do |user_hash|
1302
+
1303
+ intermediate_users = list.flat_map do |user_hash|
1257
1304
  user = user_hash[:user] || user_hash[:login]
1258
1305
  desired_roles = user_hash[:role] || user_hash[:roles] || 'readOnlyUser'
1259
1306
  begin
1260
- login, roles = verify_user_to_add(user, desired_roles, options.merge(domain_users: domain_users, project_users: project_users, roles: role_list))
1261
- [{ login: login, roles: roles }]
1262
- rescue
1263
- []
1307
+ login, roles = resolve_roles(user, desired_roles, options.merge(project_users: project_users, roles: role_list))
1308
+ [{ :type => :successful, user: login, roles: roles }]
1309
+ rescue => e
1310
+ [{ :type => :failed, :reason => e.message, user: login, roles: roles }]
1264
1311
  end
1265
1312
  end
1266
- payloads = users_to_add.map { |u| generate_user_payload(u[:login], 'ENABLED', u[:roles]) }
1267
- url = "#{uri}/users"
1313
+
1314
+ # User can fail pre sending to API during resolving roles. We add only users that passed that step.
1315
+ users_by_type = intermediate_users.group_by { |u| u[:type] }
1316
+ users_to_add = users_by_type[:successful] || []
1317
+
1318
+ payloads = users_to_add.map { |u| generate_user_payload(u[:user], 'ENABLED', u[:roles]) }
1268
1319
  results = payloads.each_slice(100).map do |payload|
1269
- client.post(url, 'users' => payload)
1320
+ client.post("#{uri}/users", 'users' => payload)
1270
1321
  end
1271
- results.flat_map { |x| x['projectUsersUpdateResult'].flat_map { |k, v| v.map { |v_2| { type: k.to_sym, uri: v_2 } } } }
1322
+ # this ugly line turns the hash of errors into list of errors with types so we can process them easily
1323
+ typed_results = results.flat_map { |x| x['projectUsersUpdateResult'].flat_map { |k, v| v.map { |v_2| v_2.is_a?(String) ? { type: k.to_sym, user: v_2 } : GoodData::Helpers.symbolize_keys(v_2).merge(type: k.to_sym) } } }
1324
+ # we have to concat errors from role resolution and API result
1325
+ typed_results + (users_by_type[:failed] || [])
1272
1326
  end
1273
1327
 
1274
1328
  alias_method :add_users, :set_users_roles
@@ -1305,6 +1359,33 @@ module GoodData
1305
1359
  GoodData::Model::ProjectCreator.migrate(options.merge(spec: blueprint, token: options[:auth_token], client: client, project: self))
1306
1360
  end
1307
1361
 
1362
+ def resolve_roles(login, desired_roles, options = {})
1363
+ user = if login.is_a?(String) && login.include?('@')
1364
+ '/gdc/account/profile/' + login
1365
+ elsif login.is_a?(String)
1366
+ login
1367
+ elsif login.is_a?(Hash) && login[:login]
1368
+ '/gdc/account/profile/' + login[:login]
1369
+ elsif login.is_a?(Hash) && login[:uri]
1370
+ login[:uri]
1371
+ elsif login.respond_to?(:uri) && login.uri
1372
+ login.uri
1373
+ elsif login.respond_to?(:login) && login.login
1374
+ '/gdc/account/profile/' + login.login
1375
+ else
1376
+ fail "Unsupported user specification #{login}"
1377
+ end
1378
+
1379
+ role_list = options[:roles] || roles
1380
+ desired_roles = Array(desired_roles)
1381
+ roles = desired_roles.map do |role_name|
1382
+ role = get_role(role_name, role_list)
1383
+ fail ArgumentError, "Invalid role '#{role_name}' specified for user '#{user.email}'" if role.nil?
1384
+ role.uri
1385
+ end
1386
+ [user, roles]
1387
+ end
1388
+
1308
1389
  private
1309
1390
 
1310
1391
  def generate_user_payload(user_uri, status = 'ENABLED', roles_uri = nil)