gooddata-edge 0.6.27.edge

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 (364) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +36 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +89 -0
  6. data/.yardopts +22 -0
  7. data/CHANGELOG.md +196 -0
  8. data/CLI.md +439 -0
  9. data/DEPENDENCIES.md +817 -0
  10. data/Gemfile +4 -0
  11. data/Guardfile +5 -0
  12. data/LICENSE +22 -0
  13. data/LICENSE.rb +5 -0
  14. data/README.md +75 -0
  15. data/Rakefile +179 -0
  16. data/TODO.md +32 -0
  17. data/authors.sh +4 -0
  18. data/bin/gooddata +7 -0
  19. data/dependency_decisions.yml +104 -0
  20. data/gooddata +9 -0
  21. data/gooddata.gemspec +63 -0
  22. data/lib/gooddata.rb +31 -0
  23. data/lib/gooddata/app/app.rb +16 -0
  24. data/lib/gooddata/bricks/base_downloader.rb +86 -0
  25. data/lib/gooddata/bricks/brick.rb +38 -0
  26. data/lib/gooddata/bricks/bricks.rb +15 -0
  27. data/lib/gooddata/bricks/middleware/aws_middleware.rb +29 -0
  28. data/lib/gooddata/bricks/middleware/base_middleware.rb +56 -0
  29. data/lib/gooddata/bricks/middleware/bench_middleware.rb +24 -0
  30. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +37 -0
  31. data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +20 -0
  32. data/lib/gooddata/bricks/middleware/fs_download_middleware.rb +48 -0
  33. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +36 -0
  34. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +39 -0
  35. data/lib/gooddata/bricks/middleware/logger_middleware.rb +29 -0
  36. data/lib/gooddata/bricks/middleware/middleware.rb +12 -0
  37. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +61 -0
  38. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +23 -0
  39. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +29 -0
  40. data/lib/gooddata/bricks/middleware/undot_params_middleware.rb +37 -0
  41. data/lib/gooddata/bricks/pipeline.rb +32 -0
  42. data/lib/gooddata/bricks/utils.rb +18 -0
  43. data/lib/gooddata/cli/cli.rb +27 -0
  44. data/lib/gooddata/cli/commands/auth_cmd.rb +29 -0
  45. data/lib/gooddata/cli/commands/domain_cmd.rb +28 -0
  46. data/lib/gooddata/cli/commands/project_cmd.rb +45 -0
  47. data/lib/gooddata/cli/hooks.rb +57 -0
  48. data/lib/gooddata/cli/shared.rb +61 -0
  49. data/lib/gooddata/cli/terminal.rb +20 -0
  50. data/lib/gooddata/client.rb +67 -0
  51. data/lib/gooddata/commands/api.rb +64 -0
  52. data/lib/gooddata/commands/auth.rb +107 -0
  53. data/lib/gooddata/commands/base.rb +12 -0
  54. data/lib/gooddata/commands/commands.rb +12 -0
  55. data/lib/gooddata/commands/datasets.rb +148 -0
  56. data/lib/gooddata/commands/datawarehouse.rb +20 -0
  57. data/lib/gooddata/commands/domain.rb +40 -0
  58. data/lib/gooddata/commands/process.rb +67 -0
  59. data/lib/gooddata/commands/project.rb +175 -0
  60. data/lib/gooddata/commands/projects.rb +20 -0
  61. data/lib/gooddata/commands/role.rb +36 -0
  62. data/lib/gooddata/commands/runners.rb +47 -0
  63. data/lib/gooddata/commands/scaffold.rb +69 -0
  64. data/lib/gooddata/commands/user.rb +39 -0
  65. data/lib/gooddata/connection.rb +127 -0
  66. data/lib/gooddata/core/core.rb +12 -0
  67. data/lib/gooddata/core/logging.rb +105 -0
  68. data/lib/gooddata/core/nil_logger.rb +23 -0
  69. data/lib/gooddata/core/project.rb +74 -0
  70. data/lib/gooddata/core/rest.rb +149 -0
  71. data/lib/gooddata/core/user.rb +20 -0
  72. data/lib/gooddata/data/data.rb +12 -0
  73. data/lib/gooddata/data/guesser.rb +122 -0
  74. data/lib/gooddata/exceptions/attr_element_not_found.rb +16 -0
  75. data/lib/gooddata/exceptions/command_failed.rb +11 -0
  76. data/lib/gooddata/exceptions/exceptions.rb +12 -0
  77. data/lib/gooddata/exceptions/execution_limit_exceeded.rb +13 -0
  78. data/lib/gooddata/exceptions/filter_maqlization.rb +16 -0
  79. data/lib/gooddata/exceptions/malformed_user.rb +15 -0
  80. data/lib/gooddata/exceptions/no_project_error.rb +15 -0
  81. data/lib/gooddata/exceptions/object_migration.rb +32 -0
  82. data/lib/gooddata/exceptions/project_not_found.rb +13 -0
  83. data/lib/gooddata/exceptions/segment_not_empty.rb +18 -0
  84. data/lib/gooddata/exceptions/uncomputable_report.rb +13 -0
  85. data/lib/gooddata/exceptions/user_in_different_domain.rb +15 -0
  86. data/lib/gooddata/exceptions/validation_error.rb +16 -0
  87. data/lib/gooddata/extensions/big_decimal.rb +17 -0
  88. data/lib/gooddata/extensions/enumerable.rb +39 -0
  89. data/lib/gooddata/extensions/extensions.rb +10 -0
  90. data/lib/gooddata/extensions/false.rb +15 -0
  91. data/lib/gooddata/extensions/hash.rb +38 -0
  92. data/lib/gooddata/extensions/nil.rb +15 -0
  93. data/lib/gooddata/extensions/numeric.rb +15 -0
  94. data/lib/gooddata/extensions/object.rb +27 -0
  95. data/lib/gooddata/extensions/symbol.rb +15 -0
  96. data/lib/gooddata/extensions/true.rb +15 -0
  97. data/lib/gooddata/extract.rb +21 -0
  98. data/lib/gooddata/goodzilla/goodzilla.rb +159 -0
  99. data/lib/gooddata/helpers/auth_helpers.rb +75 -0
  100. data/lib/gooddata/helpers/csv_helper.rb +61 -0
  101. data/lib/gooddata/helpers/data_helper.rb +116 -0
  102. data/lib/gooddata/helpers/global_helpers.rb +331 -0
  103. data/lib/gooddata/helpers/global_helpers_params.rb +172 -0
  104. data/lib/gooddata/helpers/helpers.rb +10 -0
  105. data/lib/gooddata/mixins/author.rb +26 -0
  106. data/lib/gooddata/mixins/content_getter.rb +15 -0
  107. data/lib/gooddata/mixins/content_property_reader.rb +17 -0
  108. data/lib/gooddata/mixins/content_property_writer.rb +17 -0
  109. data/lib/gooddata/mixins/contributor.rb +20 -0
  110. data/lib/gooddata/mixins/data_getter.rb +15 -0
  111. data/lib/gooddata/mixins/data_property_reader.rb +19 -0
  112. data/lib/gooddata/mixins/data_property_writer.rb +19 -0
  113. data/lib/gooddata/mixins/inspector.rb +53 -0
  114. data/lib/gooddata/mixins/is_attribute.rb +17 -0
  115. data/lib/gooddata/mixins/is_dimension.rb +17 -0
  116. data/lib/gooddata/mixins/is_fact.rb +17 -0
  117. data/lib/gooddata/mixins/is_label.rb +19 -0
  118. data/lib/gooddata/mixins/links.rb +15 -0
  119. data/lib/gooddata/mixins/md_finders.rb +77 -0
  120. data/lib/gooddata/mixins/md_grantees.rb +42 -0
  121. data/lib/gooddata/mixins/md_id_to_uri.rb +34 -0
  122. data/lib/gooddata/mixins/md_json.rb +15 -0
  123. data/lib/gooddata/mixins/md_lock.rb +87 -0
  124. data/lib/gooddata/mixins/md_object_id.rb +15 -0
  125. data/lib/gooddata/mixins/md_object_indexer.rb +64 -0
  126. data/lib/gooddata/mixins/md_object_query.rb +128 -0
  127. data/lib/gooddata/mixins/md_relations.rb +43 -0
  128. data/lib/gooddata/mixins/meta_getter.rb +17 -0
  129. data/lib/gooddata/mixins/meta_property_reader.rb +19 -0
  130. data/lib/gooddata/mixins/meta_property_writer.rb +19 -0
  131. data/lib/gooddata/mixins/mixins.rb +19 -0
  132. data/lib/gooddata/mixins/not_attribute.rb +17 -0
  133. data/lib/gooddata/mixins/not_exportable.rb +15 -0
  134. data/lib/gooddata/mixins/not_fact.rb +17 -0
  135. data/lib/gooddata/mixins/not_group.rb +17 -0
  136. data/lib/gooddata/mixins/not_label.rb +19 -0
  137. data/lib/gooddata/mixins/not_metric.rb +19 -0
  138. data/lib/gooddata/mixins/obj_id.rb +15 -0
  139. data/lib/gooddata/mixins/rest_getters.rb +17 -0
  140. data/lib/gooddata/mixins/rest_resource.rb +47 -0
  141. data/lib/gooddata/mixins/root_key_getter.rb +15 -0
  142. data/lib/gooddata/mixins/root_key_setter.rb +15 -0
  143. data/lib/gooddata/mixins/timestamps.rb +19 -0
  144. data/lib/gooddata/mixins/to_json.rb +11 -0
  145. data/lib/gooddata/mixins/uri_getter.rb +9 -0
  146. data/lib/gooddata/models/blueprint/anchor_field.rb +64 -0
  147. data/lib/gooddata/models/blueprint/attribute_field.rb +29 -0
  148. data/lib/gooddata/models/blueprint/blueprint.rb +11 -0
  149. data/lib/gooddata/models/blueprint/blueprint_field.rb +70 -0
  150. data/lib/gooddata/models/blueprint/dashboard_builder.rb +30 -0
  151. data/lib/gooddata/models/blueprint/dataset_blueprint.rb +449 -0
  152. data/lib/gooddata/models/blueprint/date_dimension.rb +14 -0
  153. data/lib/gooddata/models/blueprint/fact_field.rb +20 -0
  154. data/lib/gooddata/models/blueprint/label_field.rb +43 -0
  155. data/lib/gooddata/models/blueprint/project_blueprint.rb +746 -0
  156. data/lib/gooddata/models/blueprint/project_builder.rb +83 -0
  157. data/lib/gooddata/models/blueprint/reference_field.rb +43 -0
  158. data/lib/gooddata/models/blueprint/schema_blueprint.rb +160 -0
  159. data/lib/gooddata/models/blueprint/schema_builder.rb +89 -0
  160. data/lib/gooddata/models/blueprint/to_manifest.rb +181 -0
  161. data/lib/gooddata/models/blueprint/to_wire.rb +154 -0
  162. data/lib/gooddata/models/client.rb +182 -0
  163. data/lib/gooddata/models/client_synchronization_result.rb +31 -0
  164. data/lib/gooddata/models/client_synchronization_result_details.rb +41 -0
  165. data/lib/gooddata/models/datawarehouse.rb +92 -0
  166. data/lib/gooddata/models/domain.rb +479 -0
  167. data/lib/gooddata/models/execution.rb +115 -0
  168. data/lib/gooddata/models/execution_detail.rb +81 -0
  169. data/lib/gooddata/models/from_wire.rb +160 -0
  170. data/lib/gooddata/models/invitation.rb +75 -0
  171. data/lib/gooddata/models/links.rb +50 -0
  172. data/lib/gooddata/models/membership.rb +441 -0
  173. data/lib/gooddata/models/metadata.rb +272 -0
  174. data/lib/gooddata/models/metadata/attribute.rb +134 -0
  175. data/lib/gooddata/models/metadata/dashboard.rb +108 -0
  176. data/lib/gooddata/models/metadata/dashboard/dashboard_item.rb +76 -0
  177. data/lib/gooddata/models/metadata/dashboard/filter_apply_item.rb +37 -0
  178. data/lib/gooddata/models/metadata/dashboard/filter_item.rb +64 -0
  179. data/lib/gooddata/models/metadata/dashboard/geo_chart_item.rb +56 -0
  180. data/lib/gooddata/models/metadata/dashboard/headline_item.rb +56 -0
  181. data/lib/gooddata/models/metadata/dashboard/iframe_item.rb +46 -0
  182. data/lib/gooddata/models/metadata/dashboard/report_item.rb +92 -0
  183. data/lib/gooddata/models/metadata/dashboard/text_item.rb +55 -0
  184. data/lib/gooddata/models/metadata/dashboard_tab.rb +141 -0
  185. data/lib/gooddata/models/metadata/dataset.rb +64 -0
  186. data/lib/gooddata/models/metadata/dimension.rb +54 -0
  187. data/lib/gooddata/models/metadata/fact.rb +44 -0
  188. data/lib/gooddata/models/metadata/label.rb +128 -0
  189. data/lib/gooddata/models/metadata/metadata.rb +12 -0
  190. data/lib/gooddata/models/metadata/metric.rb +198 -0
  191. data/lib/gooddata/models/metadata/report.rb +247 -0
  192. data/lib/gooddata/models/metadata/report_definition.rb +264 -0
  193. data/lib/gooddata/models/metadata/scheduled_mail.rb +274 -0
  194. data/lib/gooddata/models/metadata/scheduled_mail/dashboard_attachment.rb +62 -0
  195. data/lib/gooddata/models/metadata/scheduled_mail/report_attachment.rb +64 -0
  196. data/lib/gooddata/models/metadata/variable.rb +91 -0
  197. data/lib/gooddata/models/model.rb +282 -0
  198. data/lib/gooddata/models/models.rb +12 -0
  199. data/lib/gooddata/models/module_constants.rb +31 -0
  200. data/lib/gooddata/models/process.rb +316 -0
  201. data/lib/gooddata/models/profile.rb +426 -0
  202. data/lib/gooddata/models/project.rb +1514 -0
  203. data/lib/gooddata/models/project_creator.rb +126 -0
  204. data/lib/gooddata/models/project_metadata.rb +67 -0
  205. data/lib/gooddata/models/project_role.rb +79 -0
  206. data/lib/gooddata/models/report_data_result.rb +266 -0
  207. data/lib/gooddata/models/schedule.rb +518 -0
  208. data/lib/gooddata/models/segment.rb +201 -0
  209. data/lib/gooddata/models/tab_builder.rb +27 -0
  210. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +76 -0
  211. data/lib/gooddata/models/user_filters/user_filter.rb +100 -0
  212. data/lib/gooddata/models/user_filters/user_filter_builder.rb +512 -0
  213. data/lib/gooddata/models/user_filters/user_filters.rb +13 -0
  214. data/lib/gooddata/models/user_filters/variable_user_filter.rb +31 -0
  215. data/lib/gooddata/models/user_group.rb +241 -0
  216. data/lib/gooddata/rest/README.md +37 -0
  217. data/lib/gooddata/rest/client.rb +389 -0
  218. data/lib/gooddata/rest/connection.rb +765 -0
  219. data/lib/gooddata/rest/object.rb +69 -0
  220. data/lib/gooddata/rest/object_factory.rb +76 -0
  221. data/lib/gooddata/rest/resource.rb +27 -0
  222. data/lib/gooddata/rest/rest.rb +24 -0
  223. data/lib/gooddata/version.rb +23 -0
  224. data/lib/templates/bricks/brick.rb.erb +7 -0
  225. data/lib/templates/bricks/main.rb.erb +5 -0
  226. data/lib/templates/project/Goodfile.erb +4 -0
  227. data/lib/templates/project/data/commits.csv +4 -0
  228. data/lib/templates/project/data/devs.csv +4 -0
  229. data/lib/templates/project/data/repos.csv +3 -0
  230. data/lib/templates/project/model/model.rb.erb +20 -0
  231. data/spec/bricks/bricks_spec.rb +112 -0
  232. data/spec/bricks/default-config.json +8 -0
  233. data/spec/data/.gooddata +4 -0
  234. data/spec/data/blueprints/additional_dataset_module.json +32 -0
  235. data/spec/data/blueprints/big_blueprint_not_pruned.json +2079 -0
  236. data/spec/data/blueprints/invalid_blueprint.json +103 -0
  237. data/spec/data/blueprints/m_n_model.json +104 -0
  238. data/spec/data/blueprints/model_module.json +25 -0
  239. data/spec/data/blueprints/test_blueprint.json +38 -0
  240. data/spec/data/blueprints/test_project_model_spec.json +106 -0
  241. data/spec/data/cc/data/source/commits.csv +4 -0
  242. data/spec/data/cc/data/source/devs.csv +4 -0
  243. data/spec/data/cc/data/source/repos.csv +3 -0
  244. data/spec/data/cc/devel.prm +0 -0
  245. data/spec/data/cc/graph/graph.grf +11 -0
  246. data/spec/data/cc/workspace.prm +19 -0
  247. data/spec/data/column_based_permissions.csv +7 -0
  248. data/spec/data/column_based_permissions2.csv +6 -0
  249. data/spec/data/gd_gse_data_blueprint.json +1371 -0
  250. data/spec/data/gd_gse_data_manifest.json +1424 -0
  251. data/spec/data/gd_gse_data_model.json +1772 -0
  252. data/spec/data/gooddata_version_process/gooddata_version.rb +9 -0
  253. data/spec/data/gooddata_version_process/gooddata_version.zip +0 -0
  254. data/spec/data/hello_world_process/hello_world.rb +9 -0
  255. data/spec/data/hello_world_process/hello_world.zip +0 -0
  256. data/spec/data/line_based_permissions.csv +3 -0
  257. data/spec/data/manifests/test_blueprint.json +32 -0
  258. data/spec/data/manifests/test_project.json +107 -0
  259. data/spec/data/reports/left_attr_report.json +108 -0
  260. data/spec/data/reports/metric_only_one_line.json +83 -0
  261. data/spec/data/reports/report_1.json +197 -0
  262. data/spec/data/reports/top_attr_report.json +108 -0
  263. data/spec/data/ruby_params_process/ruby_params.rb +9 -0
  264. data/spec/data/ruby_process/deep_files/deep_stuff.txt +1 -0
  265. data/spec/data/ruby_process/process.rb +8 -0
  266. data/spec/data/ruby_process/stuff.txt +1 -0
  267. data/spec/data/superfluous_titles_view.json +81 -0
  268. data/spec/data/test-ci-data.csv +2 -0
  269. data/spec/data/users.csv +12 -0
  270. data/spec/data/wire_models/model_view.json +1775 -0
  271. data/spec/data/wire_models/nu_model.json +3046 -0
  272. data/spec/data/wire_models/test_blueprint.json +63 -0
  273. data/spec/data/wire_test_project.json +150 -0
  274. data/spec/environment/default.rb +41 -0
  275. data/spec/environment/develop.rb +31 -0
  276. data/spec/environment/environment.rb +18 -0
  277. data/spec/environment/hotfix.rb +21 -0
  278. data/spec/environment/production.rb +35 -0
  279. data/spec/environment/release.rb +21 -0
  280. data/spec/environment/staging.rb +30 -0
  281. data/spec/environment/staging_3.rb +36 -0
  282. data/spec/helpers/blueprint_helper.rb +26 -0
  283. data/spec/helpers/cli_helper.rb +36 -0
  284. data/spec/helpers/connection_helper.rb +41 -0
  285. data/spec/helpers/crypto_helper.rb +17 -0
  286. data/spec/helpers/csv_helper.rb +18 -0
  287. data/spec/helpers/process_helper.rb +33 -0
  288. data/spec/helpers/project_helper.rb +59 -0
  289. data/spec/helpers/schedule_helper.rb +31 -0
  290. data/spec/helpers/spec_helper.rb +15 -0
  291. data/spec/integration/blueprint_updates_spec.rb +101 -0
  292. data/spec/integration/blueprint_with_grain_spec.rb +72 -0
  293. data/spec/integration/clients_spec.rb +134 -0
  294. data/spec/integration/command_datawarehouse_spec.rb +39 -0
  295. data/spec/integration/command_projects_spec.rb +32 -0
  296. data/spec/integration/create_from_template_spec.rb +22 -0
  297. data/spec/integration/create_project_spec.rb +24 -0
  298. data/spec/integration/date_dim_switch_spec.rb +142 -0
  299. data/spec/integration/deprecated_load_spec.rb +58 -0
  300. data/spec/integration/full_process_schedule_spec.rb +298 -0
  301. data/spec/integration/full_project_spec.rb +569 -0
  302. data/spec/integration/over_to_user_filters_spec.rb +94 -0
  303. data/spec/integration/partial_md_export_import_spec.rb +42 -0
  304. data/spec/integration/project_spec.rb +264 -0
  305. data/spec/integration/rest_spec.rb +213 -0
  306. data/spec/integration/schedule_spec.rb +626 -0
  307. data/spec/integration/segments_spec.rb +141 -0
  308. data/spec/integration/user_filters_spec.rb +290 -0
  309. data/spec/integration/user_group_spec.rb +127 -0
  310. data/spec/integration/variables_spec.rb +188 -0
  311. data/spec/logging_in_logging_out_spec.rb +93 -0
  312. data/spec/spec_helper.rb +95 -0
  313. data/spec/unit/bricks/bricks_spec.rb +35 -0
  314. data/spec/unit/bricks/middleware/aws_middelware_spec.rb +51 -0
  315. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +15 -0
  316. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +15 -0
  317. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +15 -0
  318. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +15 -0
  319. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +15 -0
  320. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +15 -0
  321. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +15 -0
  322. data/spec/unit/cli/cli_spec.rb +17 -0
  323. data/spec/unit/cli/commands/cmd_auth_spec.rb +17 -0
  324. data/spec/unit/commands/command_projects_spec.rb +22 -0
  325. data/spec/unit/core/connection_spec.rb +57 -0
  326. data/spec/unit/core/logging_spec.rb +133 -0
  327. data/spec/unit/core/nil_logger_spec.rb +13 -0
  328. data/spec/unit/core/project_spec.rb +54 -0
  329. data/spec/unit/extensions/hash_spec.rb +23 -0
  330. data/spec/unit/godzilla/goodzilla_spec.rb +78 -0
  331. data/spec/unit/helpers/csv_helper_spec.rb +22 -0
  332. data/spec/unit/helpers/data_helper_spec.rb +61 -0
  333. data/spec/unit/helpers/global_helpers_spec.rb +111 -0
  334. data/spec/unit/helpers_spec.rb +86 -0
  335. data/spec/unit/models/blueprint/attributes_spec.rb +29 -0
  336. data/spec/unit/models/blueprint/dataset_spec.rb +121 -0
  337. data/spec/unit/models/blueprint/labels_spec.rb +44 -0
  338. data/spec/unit/models/blueprint/project_blueprint_spec.rb +648 -0
  339. data/spec/unit/models/blueprint/reference_spec.rb +29 -0
  340. data/spec/unit/models/blueprint/schema_builder_spec.rb +38 -0
  341. data/spec/unit/models/blueprint/to_wire_spec.rb +174 -0
  342. data/spec/unit/models/domain_spec.rb +144 -0
  343. data/spec/unit/models/execution_spec.rb +108 -0
  344. data/spec/unit/models/from_wire_spec.rb +296 -0
  345. data/spec/unit/models/invitation_spec.rb +17 -0
  346. data/spec/unit/models/membership_spec.rb +132 -0
  347. data/spec/unit/models/metadata_spec.rb +104 -0
  348. data/spec/unit/models/metric_spec.rb +117 -0
  349. data/spec/unit/models/model_spec.rb +82 -0
  350. data/spec/unit/models/params_spec.rb +118 -0
  351. data/spec/unit/models/profile_spec.rb +215 -0
  352. data/spec/unit/models/project_creator_spec.rb +127 -0
  353. data/spec/unit/models/project_role_spec.rb +94 -0
  354. data/spec/unit/models/project_spec.rb +162 -0
  355. data/spec/unit/models/report_result_data_spec.rb +199 -0
  356. data/spec/unit/models/schedule_spec.rb +418 -0
  357. data/spec/unit/models/to_manifest_spec.rb +63 -0
  358. data/spec/unit/models/unit_project_spec.rb +125 -0
  359. data/spec/unit/models/user_filters_spec.rb +95 -0
  360. data/spec/unit/models/variable_spec.rb +265 -0
  361. data/spec/unit/rest/polling_spec.rb +89 -0
  362. data/spec/unit/rest/resource_spec.rb +10 -0
  363. data/yard-server.sh +3 -0
  364. metadata +1125 -0
@@ -0,0 +1,765 @@
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.
6
+
7
+ require 'terminal-table'
8
+ require 'securerandom'
9
+ require 'monitor'
10
+ require 'thread_safe'
11
+ require 'rest-client'
12
+
13
+ require_relative '../version'
14
+ require_relative '../exceptions/exceptions'
15
+
16
+ module RestClient
17
+ module AbstractResponse
18
+ alias_method :old_follow_redirection, :follow_redirection
19
+ def follow_redirection(request = nil, result = nil, &block)
20
+ fail 'Using monkey patched version of RestClient::AbstractResponse#follow_redirection which is guaranteed to be compatible only with RestClient 1.8.0' if RestClient::VERSION != '1.8.0'
21
+
22
+ # @args[:cookies] = request.cookies
23
+ # old_follow_redirection(request, result, &block)
24
+
25
+ new_args = @args.dup
26
+
27
+ url = headers[:location]
28
+ url = URI.parse(request.url).merge(url).to_s if url !~ /^http/
29
+
30
+ new_args[:url] = url
31
+ if request
32
+ fail MaxRedirectsReached if request.max_redirects == 0
33
+ new_args[:password] = request.password
34
+ new_args[:user] = request.user
35
+ new_args[:headers] = request.headers
36
+ new_args[:max_redirects] = request.max_redirects - 1
37
+
38
+ # TODO: figure out what to do with original :cookie, :cookies values
39
+ new_args[:cookies] = get_redirection_cookies(request, result, new_args)
40
+ end
41
+
42
+ Request.execute(new_args, &block)
43
+ end
44
+
45
+ # Returns cookies which should be passed when following redirect
46
+ #
47
+ # @param request [RestClient::Request] Original request
48
+ # @param result [Net::HTTPResponse] Response
49
+ # @param args [Hash] Original arguments
50
+ # @return [Hash] Cookies to be passsed when following redirect
51
+ def get_redirection_cookies(request, _result, _args)
52
+ request.cookies
53
+ end
54
+ end
55
+ end
56
+
57
+ module GoodData
58
+ module Rest
59
+ # Wrapper of low-level HTTP/REST client/library
60
+ class Connection
61
+ include MonitorMixin
62
+
63
+ DEFAULT_URL = 'https://secure.gooddata.com'
64
+ LOGIN_PATH = '/gdc/account/login'
65
+ TOKEN_PATH = '/gdc/account/token'
66
+ KEYS_TO_SCRUB = [:password, :verifyPassword, :authorizationToken]
67
+
68
+ ID_LENGTH = 16
69
+
70
+ DEFAULT_HEADERS = {
71
+ :content_type => :json,
72
+ :accept => [:json, :zip],
73
+ :user_agent => GoodData.gem_version_string
74
+ }
75
+
76
+ DEFAULT_WEBDAV_HEADERS = {
77
+ :user_agent => GoodData.gem_version_string
78
+ }
79
+
80
+ DEFAULT_LOGIN_PAYLOAD = {
81
+ :headers => DEFAULT_HEADERS,
82
+ :verify_ssl => true
83
+ }
84
+
85
+ RETRYABLE_ERRORS = [
86
+ RestClient::InternalServerError,
87
+ RestClient::RequestTimeout,
88
+ RestClient::MethodNotAllowed,
89
+ SystemCallError,
90
+ Timeout::Error
91
+ ]
92
+
93
+ RETRIES_ON_TOO_MANY_REQUESTS_ERROR = 12
94
+ RETRY_TIME_INITIAL_VALUE = 1
95
+ RETRY_TIME_COEFFICIENT = 1.5
96
+ RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
97
+
98
+ class << self
99
+ def construct_login_payload(username, password)
100
+ res = {
101
+ 'postUserLogin' => {
102
+ 'login' => username,
103
+ 'password' => password,
104
+ 'remember' => 1
105
+ }
106
+ }
107
+ res
108
+ end
109
+
110
+ # Generate random string with URL safe base64 encoding
111
+ #
112
+ # @param [String] length Length of random string to be generated
113
+ #
114
+ # @return [String] Generated random string
115
+ def generate_string(length = ID_LENGTH)
116
+ SecureRandom.urlsafe_base64(length)
117
+ end
118
+
119
+ # Retry block if exception thrown
120
+ def retryable(options = {}, &_block)
121
+ opts = { :tries => 1, :on => RETRYABLE_ERRORS }.merge(options)
122
+
123
+ retry_exception = opts[:on]
124
+ retries = opts[:tries]
125
+ too_many_requests_tries = RETRIES_ON_TOO_MANY_REQUESTS_ERROR
126
+
127
+ unless retry_exception.is_a?(Array)
128
+ retry_exception = [retry_exception]
129
+ end
130
+
131
+ retry_time = RETRY_TIME_INITIAL_VALUE
132
+ begin
133
+ return yield
134
+ rescue RestClient::Unauthorized, RestClient::Forbidden => e # , RestClient::Unauthorized => e
135
+ raise e unless options[:refresh_token]
136
+ raise e if options[:dont_reauth]
137
+ options[:refresh_token].call # (dont_reauth: true)
138
+ retry if (retries -= 1) > 0
139
+ rescue RestClient::TooManyRequests, RestClient::ServiceUnavailable
140
+ GoodData.logger.warn "Too many requests, retrying in #{retry_time} seconds"
141
+ sleep retry_time
142
+ retry_time *= RETRY_TIME_COEFFICIENT
143
+ # 10 requests with 1.5 coefficent should take ~ 3 mins to finish
144
+ retry if (too_many_requests_tries -= 1) > 1
145
+ rescue *retry_exception => e
146
+ GoodData.logger.warn e.inspect
147
+ retry if (retries -= 1) > 1
148
+ end
149
+ yield
150
+ end
151
+ end
152
+
153
+ attr_reader :request_params
154
+
155
+ # backward compatibility
156
+ alias_method :cookies, :request_params
157
+ attr_reader :server
158
+ attr_reader :stats
159
+ attr_reader :user
160
+
161
+ def initialize(opts)
162
+ super()
163
+ @stats = ThreadSafe::Hash.new
164
+
165
+ headers = opts[:headers] || {}
166
+ @webdav_headers = DEFAULT_WEBDAV_HEADERS.merge(headers)
167
+
168
+ @user = nil
169
+ @server = nil
170
+ @opts = opts
171
+
172
+ # Initialize cookies
173
+ reset_cookies!
174
+
175
+ @at_exit_handler_installed = nil
176
+ end
177
+
178
+ # Connect using username and password
179
+ def connect(username, password, options = {})
180
+ server = options[:server] || Helpers::AuthHelper.read_server
181
+ options = DEFAULT_LOGIN_PAYLOAD.merge(options)
182
+ headers = options[:headers] || {}
183
+
184
+ options = options.merge(headers)
185
+ @server = RestClient::Resource.new server, options
186
+
187
+ # Install at_exit handler first
188
+ unless @at_exit_handler_installed
189
+ begin
190
+ at_exit { disconnect if @user }
191
+ rescue RestClient::Unauthorized
192
+ GoodData.logger.info 'Already logged out'
193
+ ensure
194
+ @at_exit_handler_installed = true
195
+ end
196
+ end
197
+
198
+ # Reset old cookies first
199
+ if options[:sst_token]
200
+ merge_cookies!('GDCAuthSST' => options[:sst_token])
201
+ get('/gdc/account/token', @request_params)
202
+
203
+ @user = get(get('/gdc/app/account/bootstrap')['bootstrapResource']['accountSetting']['links']['self'])
204
+ GoodData.logger.info("Connected using SST to server #{@server.url} to profile \"#{@user['accountSetting']['login']}\"")
205
+ @auth = {}
206
+ refresh_token :dont_reauth => true
207
+ else
208
+ GoodData.logger.info("Connected using username \"#{username}\" to server #{@server.url}")
209
+ credentials = Connection.construct_login_payload(username, password)
210
+ generate_session_id
211
+ @auth = post(LOGIN_PATH, credentials, :dont_reauth => true)['userLogin']
212
+
213
+ refresh_token :dont_reauth => true
214
+ @user = get(@auth['profile'])
215
+ end
216
+ GoodData.logger.info('Connection successful')
217
+ rescue RestClient::Unauthorized => e
218
+ GoodData.logger.info('Bad Login or Password')
219
+ GoodData.logger.info('Connection failed')
220
+ raise e
221
+ rescue RestClient::Forbidden => e
222
+ GoodData.logger.info('Connection failed')
223
+ raise e
224
+ end
225
+
226
+ # Disconnect
227
+ def disconnect
228
+ # TODO: Wrap somehow
229
+ url = @auth['state']
230
+
231
+ begin
232
+ clear_session_id
233
+ delete url if url
234
+ rescue RestClient::Unauthorized
235
+ GoodData.logger.info 'Already disconnected'
236
+ end
237
+
238
+ @auth = nil
239
+ @server = nil
240
+ @user = nil
241
+
242
+ reset_cookies!
243
+ end
244
+
245
+ def download(what, where, options = {})
246
+ # handle the path (directory) given in what
247
+ ilast_slash = what.rindex('/')
248
+ if ilast_slash.nil?
249
+ what_dir = ''
250
+ else
251
+ # take the directory from the path
252
+ what_dir = what[0..ilast_slash - 1]
253
+ # take the filename from the path
254
+ what = what[ilast_slash + 1..-1]
255
+ end
256
+
257
+ option_dir = options[:directory] || ''
258
+ option_dir = option_dir[0..-2] if option_dir[-1] == '/'
259
+
260
+ # join the otion dir with the what_dir
261
+ # [option dir empty, what dir empty] => the joined dir
262
+ dir_hash = {
263
+ [true, true] => '',
264
+ [true, false] => what_dir,
265
+ [false, true] => option_dir,
266
+ [false, false] => "#{what_dir}/#{option_dir}"
267
+ }
268
+ dir = dir_hash[[option_dir.empty?, what_dir.empty?]]
269
+
270
+ staging_uri = options[:staging_url].to_s
271
+
272
+ base_url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
273
+ url = URI.join(base_url, CGI.escape(what)).to_s
274
+
275
+ b = proc do
276
+ raw = {
277
+ :headers => {
278
+ :user_agent => GoodData.gem_version_string
279
+ },
280
+ :method => :get,
281
+ :url => url,
282
+ :verify_ssl => (@opts[:verify_ssl] == false || @opts[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
283
+ }.merge(cookies)
284
+
285
+ if where.is_a?(IO) || where.is_a?(StringIO)
286
+ RestClient::Request.execute(raw) do |chunk, _x, response|
287
+ if response.code.to_s != '200'
288
+ fail ArgumentError, "Error downloading #{url}. Got response: #{response.code} #{response} #{response.body}"
289
+ end
290
+ where.write chunk
291
+ end
292
+ else
293
+ # Assume it is a string or file
294
+ File.open(where, 'w') do |f|
295
+ RestClient::Request.execute(raw) do |chunk, _x, response|
296
+ if response.code.to_s != '200'
297
+ fail ArgumentError, "Error downloading #{url}. Got response: #{response.code} #{response} #{response.body}"
298
+ end
299
+ f.write chunk
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ res = nil
306
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
307
+ res = b.call
308
+ end
309
+ res
310
+ end
311
+
312
+ def refresh_token(_options = {})
313
+ begin # rubocop:disable RedundantBegin
314
+ get TOKEN_PATH, :dont_reauth => true # avoid infinite loop GET fails with 401
315
+ rescue Exception => e # rubocop:disable RescueException
316
+ puts e.message
317
+ raise e
318
+ end
319
+ end
320
+
321
+ # Returns server URI
322
+ #
323
+ # @return [String] server uri
324
+ def server_url
325
+ @server && @server.url
326
+ end
327
+
328
+ # HTTP DELETE
329
+ #
330
+ # @param uri [String] Target URI
331
+ def delete(uri, options = {})
332
+ options = log_info(options)
333
+ GoodData.rest_logger.info "DELETE: #{@server.url}#{uri}"
334
+ profile "DELETE #{uri}" do
335
+ b = proc do
336
+ params = fresh_request_params(options[:request_id])
337
+ begin
338
+ @server[uri].delete(params)
339
+ rescue RestClient::Exception => e
340
+ # log the error if it happens
341
+ log_error(e, uri, params, options)
342
+ raise e
343
+ end
344
+ end
345
+ process_response(options, &b)
346
+ end
347
+ end
348
+
349
+ # Helper for logging error
350
+ #
351
+ # @param e [RuntimeException] Exception to log
352
+ # @param uri [String] Uri on which the request failed
353
+ # @param uri [Hash] Additional params
354
+ def log_error(e, uri, params, options = {})
355
+ return if e.response && e.response.code == 401 && !uri.include?('token') && !uri.include?('login')
356
+
357
+ if options[:do_not_log].nil? || options[:do_not_log].index(e.class).nil?
358
+ GoodData.logger.error(format_error(e, params))
359
+ end
360
+ end
361
+
362
+ # HTTP GET
363
+ #
364
+ # @param uri [String] Target URI
365
+ def get(uri, options = {}, &user_block)
366
+ options = log_info(options)
367
+ GoodData.rest_logger.info "GET: #{@server.url}#{uri}, #{options}"
368
+ profile "GET #{uri}" do
369
+ b = proc do
370
+ params = fresh_request_params(options[:request_id]).merge(options)
371
+ begin
372
+ @server[uri].get(params, &user_block)
373
+ rescue RestClient::Exception => e
374
+ # log the error if it happens
375
+ log_error(e, uri, params, options)
376
+ raise e
377
+ end
378
+ end
379
+ process_response(options, &b)
380
+ end
381
+ end
382
+
383
+ # HTTP PUT
384
+ #
385
+ # @param uri [String] Target URI
386
+ def put(uri, data, options = {})
387
+ options = log_info(options)
388
+ payload = data.is_a?(Hash) ? data.to_json : data
389
+ GoodData.rest_logger.info "PUT: #{@server.url}#{uri}, #{scrub_params(data, KEYS_TO_SCRUB)}"
390
+ profile "PUT #{uri}" do
391
+ b = proc do
392
+ params = fresh_request_params(options[:request_id])
393
+ begin
394
+ @server[uri].put(payload, params)
395
+ rescue RestClient::Exception => e
396
+ # log the error if it happens
397
+ log_error(e, uri, params, options)
398
+ raise e
399
+ end
400
+ end
401
+ process_response(options, &b)
402
+ end
403
+ end
404
+
405
+ # HTTP POST
406
+ #
407
+ # @param uri [String] Target URI
408
+ def post(uri, data = nil, options = {})
409
+ options = log_info(options)
410
+ GoodData.rest_logger.info "POST: #{@server.url}#{uri}, #{scrub_params(data, KEYS_TO_SCRUB)}"
411
+ profile "POST #{uri}" do
412
+ payload = data.is_a?(Hash) ? data.to_json : data
413
+ b = proc do
414
+ params = fresh_request_params(options[:request_id])
415
+ begin
416
+ @server[uri].post(payload, params)
417
+ rescue RestClient::Exception => e
418
+ # log the error if it happens
419
+ log_error(e, uri, params, options)
420
+ raise e
421
+ end
422
+ end
423
+ process_response(options, &b)
424
+ end
425
+ end
426
+
427
+ # Reader method for SST token
428
+ #
429
+ # @return uri [String] SST token
430
+ def sst_token
431
+ request_params[:cookies]['GDCAuthSST']
432
+ end
433
+
434
+ def stats_table(values = stats)
435
+ sorted = values.sort_by { |_k, v| v[:avg] }
436
+ Terminal::Table.new :headings => %w(title avg min max total calls) do |t|
437
+ overall = {
438
+ :avg => 0,
439
+ :calls => 0,
440
+ :total => 0
441
+ }
442
+
443
+ sorted.each do |l|
444
+ avg = l[1][:avg]
445
+ min = l[1][:min]
446
+ max = l[1][:max]
447
+ total = l[1][:total]
448
+ calls = l[1][:calls]
449
+
450
+ row = [
451
+ l[0],
452
+ sprintf('%.3f', avg),
453
+ sprintf('%.3f', min),
454
+ sprintf('%.3f', max),
455
+ sprintf('%.3f', total),
456
+ calls
457
+ ]
458
+
459
+ overall[:min] = min if overall[:min].nil? || min < overall[:min]
460
+ overall[:max] = max if overall[:max].nil? || max > overall[:max]
461
+ overall[:total] += total
462
+ overall[:calls] += calls
463
+ overall[:avg] += avg
464
+
465
+ t.add_row row
466
+ end
467
+
468
+ overall[:avg] = overall[:avg] / sorted.length
469
+ row = [
470
+ 'TOTAL',
471
+ sprintf('%.3f', overall[:avg]),
472
+ sprintf('%.3f', overall[:min]),
473
+ sprintf('%.3f', overall[:max]),
474
+ sprintf('%.3f', overall[:total]),
475
+ overall[:calls]
476
+ ]
477
+
478
+ t.add_row :separator
479
+ t.add_row row
480
+ end
481
+ end
482
+
483
+ # Reader method for TT token
484
+ #
485
+ # @return uri [String] TT token
486
+ def tt_token
487
+ request_params[:cookies]['GDCAuthTT']
488
+ end
489
+
490
+ # Uploads a file to GoodData server
491
+ def upload(file, options = {})
492
+ dir = options[:directory] || ''
493
+ staging_uri = options[:staging_url].to_s
494
+ url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
495
+ # Make a directory, if needed
496
+ create_webdav_dir_if_needed url unless dir.empty?
497
+
498
+ webdav_filename = options[:filename] || File.basename(file)
499
+ do_stream_file URI.join(url, CGI.escape(webdav_filename)), file
500
+ end
501
+
502
+ def generate_request_id
503
+ "#{session_id}:#{call_id}"
504
+ end
505
+
506
+ private
507
+
508
+ def create_webdav_dir_if_needed(url)
509
+ return if webdav_dir_exists?(url)
510
+
511
+ method = :mkcol
512
+ b = proc do
513
+ raw = {
514
+ :method => method,
515
+ :url => url,
516
+ :headers => @webdav_headers,
517
+ :verify_ssl => (@opts[:verify_ssl] == false || @opts[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
518
+ }.merge(cookies)
519
+ RestClient::Request.execute(raw)
520
+ end
521
+
522
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
523
+ b.call
524
+ end
525
+ end
526
+
527
+ def do_stream_file(uri, filename, _options = {})
528
+ GoodData.logger.info "Uploading file user storage #{uri}"
529
+
530
+ to_upload = File.new(filename)
531
+ cookies_str = request_params[:cookies].map { |cookie| "#{cookie[0]}=#{cookie[1]}" }.join(';')
532
+ req = Net::HTTP::Put.new(uri.path, 'User-Agent' => GoodData.gem_version_string, 'Cookie' => cookies_str)
533
+ req.content_length = to_upload.size
534
+ req.body_stream = to_upload
535
+ http = Net::HTTP.new(uri.host, uri.port)
536
+ http.use_ssl = true
537
+ http.verify_mode = (@opts[:verify_ssl] == false || @opts[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
538
+
539
+ response = nil
540
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
541
+ response = http.start { |client| client.request(req) }
542
+ end
543
+ response
544
+ end
545
+
546
+ def format_error(e, params)
547
+ "#{params[:x_gdc_request]} #{e.inspect}"
548
+ end
549
+
550
+ # generate session id to be passed as the first part to
551
+ # x_gdc_request header
552
+ def session_id
553
+ @session_id ||= Connection.generate_string
554
+ end
555
+
556
+ def call_id
557
+ Connection.generate_string
558
+ end
559
+
560
+ def generate_session_id
561
+ @session_id = Connection.generate_string
562
+ end
563
+
564
+ def clear_session_id
565
+ @session_id = nil
566
+ end
567
+
568
+ # log info_message given in options and make sure request_id is there
569
+ def log_info(options)
570
+ # if info_message given, log it with request_id (given or generated)
571
+ if options[:info_message]
572
+ request_id = options[:request_id] || generate_request_id
573
+ GoodData.logger.info "#{options[:info_message]} Request id: #{request_id}"
574
+ end
575
+ options
576
+ end
577
+
578
+ # request heders with freshly generated request id
579
+ def fresh_request_params(request_id = nil)
580
+ @request_params.merge(:x_gdc_request => request_id || generate_request_id)
581
+ end
582
+
583
+ def merge_cookies!(cookies)
584
+ @request_params[:cookies].merge! cookies
585
+ end
586
+
587
+ def process_response(options = {}, &block)
588
+ retries = options[:tries] || 3
589
+ opts = { tries: retries, refresh_token: proc { refresh_token unless options[:dont_reauth] } }.merge(options)
590
+ response = GoodData::Rest::Connection.retryable(opts) do
591
+ block.call
592
+ end
593
+
594
+ merge_cookies! response.cookies
595
+ content_type = response.headers[:content_type]
596
+ return response if options[:process] == false
597
+
598
+ if content_type == 'application/json' || content_type == 'application/json;charset=UTF-8'
599
+ result = response.to_str == '""' ? {} : MultiJson.load(response.to_str)
600
+ GoodData.rest_logger.debug "Request ID: #{response.headers[:x_gdc_request]} - Response: #{result.inspect}"
601
+ elsif ['text/plain;charset=UTF-8', 'text/plain; charset=UTF-8', 'text/plain'].include?(content_type)
602
+ result = response
603
+ GoodData.rest_logger.debug 'Response: plain text'
604
+ elsif content_type == 'application/zip'
605
+ result = response
606
+ GoodData.rest_logger.debug 'Response: a zipped stream'
607
+ elsif response.headers[:content_length].to_s == '0'
608
+ result = nil
609
+ GoodData.rest_logger.debug 'Response: Empty response possibly 204'
610
+ elsif response.code == 204
611
+ result = nil
612
+ GoodData.rest_logger.debug 'Response: 204 no content'
613
+ else
614
+ fail "Unsupported response content type '%s':\n%s" % [content_type, response.to_str[0..127]]
615
+ end
616
+ result
617
+ rescue RestClient::Exception => e
618
+ GoodData.logger.error "Response: #{e.response}"
619
+ raise $ERROR_INFO
620
+ end
621
+
622
+ def profile(title, &block)
623
+ t1 = Time.now
624
+ res = block.call
625
+ t2 = Time.now
626
+ delta = t2 - t1
627
+
628
+ update_stats title, delta
629
+ res
630
+ end
631
+
632
+ def reset_cookies!
633
+ @request_params = { :cookies => {} }
634
+ end
635
+
636
+ def scrub_params(params, keys)
637
+ keys = keys.reduce([]) { |a, e| a.concat([e.to_s, e.to_sym]) }
638
+
639
+ new_params = GoodData::Helpers.deep_dup(params)
640
+ GoodData::Helpers.hash_dfs(new_params) do |k, _key|
641
+ keys.each do |key_to_scrub|
642
+ k[key_to_scrub] = ('*' * k[key_to_scrub].length) if k && k.key?(key_to_scrub) && k[key_to_scrub]
643
+ end
644
+ end
645
+ new_params
646
+ end
647
+
648
+ # TODO: Store PH_MAP for wildcarding of URLs in reports in separate file
649
+ PH_MAP = [
650
+ ['/gdc/account/profile/{id}', %r{/gdc/account/profile/[\w]+}],
651
+ ['/gdc/account/login/{id}', %r{/gdc/account/login/[\w]+}],
652
+ ['/gdc/account/domains/{id}/users?login={login}', %r{/gdc/account/domains/[\w\d-]+/users\?login=[^&$]+}],
653
+ ['/gdc/account/domains/{id}', %r{/gdc/account/domains/[\w\d-]+}],
654
+
655
+ ['/gdc/app/projects/{id}/execute', %r{/gdc/app/projects/[\w]+/execute}],
656
+
657
+ ['/gdc/datawarehouse/instances/{id}', %r{/gdc/datawarehouse/instances/[\w]+}],
658
+ ['/gdc/datawarehouse/executions/{id}', %r{/gdc/datawarehouse/executions/[\w]+}],
659
+
660
+ ['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}', %r{/gdc/domains/[\w]+/segments/[\w-]+/synchronizeClients/results/[\w]+/details/\?offset=[\d]+&limit=[\d]+}],
661
+ ['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}', %r{/gdc/domains/[\w]+/segments/[\w-]+/synchronizeClients/results/[\w]+}],
662
+ ['/gdc/domains/{id}/segments/{segment}/', %r{/gdc/domains/[\w]+/segments/[\w-]+/}],
663
+ ['/gdc/domains/{id}/segments/{segment}', %r{/gdc/domains/[\w]+/segments/[\w-]+}],
664
+ ['/gdc/domains/{id}/clients?segment={segment}', %r{/gdc/domains/[\w]+/clients\?segment=[\w-]+}],
665
+ ['/gdc/domains/{id}/', %r{/gdc/domains/[\w]+/}],
666
+
667
+ ['/gdc/exporter/result/{id}/{id}', %r{/gdc/exporter/result/[\w]+/[\w]+}],
668
+
669
+ ['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[\w]+/objects/setPermissions}],
670
+
671
+ ['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[\w]+/variables/item/[\d]+}],
672
+ ['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[\w]+/validate/task/[\w]+}],
673
+ ['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[\w]+/using2/[\d]+/[\d]+}],
674
+ ['/gdc/md/{id}/using2/{id}', %r{/gdc/md/[\w]+/using2/[\d]+}],
675
+ ['/gdc/md/{id}/userfilters?users={users}', %r{/gdc/md/[\w]+/userfilters\?users=[/\w]+}],
676
+ ['/gdc/md/{id}/userfilters?count={count}&offset={offset}', %r{/gdc/md/[\w]+/userfilters\?count=[\d]+&offset=[\d]+}],
677
+ ['/gdc/md/{id}/usedby2/{id}/{id}', %r{/gdc/md/[\w]+/usedby2/[\d]+/[\d]+}],
678
+ ['/gdc/md/{id}/usedby2/{id}', %r{/gdc/md/[\w]+/usedby2/[\d]+}],
679
+ ['/gdc/md/{id}/tasks/{id}/status', %r{/gdc/md/[\w]+/tasks/[\w]+/status}],
680
+ ['/gdc/md/{id}/obj/{id}/validElements', %r{/gdc/md/[\w]+/obj/[\d]+/validElements(/)?(\?.*)?}],
681
+ ['/gdc/md/{id}/obj/{id}/elements', %r{/gdc/md/[\w]+/obj/[\d]+/elements(/)?(\?.*)?}],
682
+ ['/gdc/md/{id}/obj/{id}', %r{/gdc/md/[\w]+/obj/[\d]+}],
683
+ ['/gdc/md/{id}/etltask/{id}', %r{/gdc/md/[\w]+/etltask/[\w]+}],
684
+ ['/gdc/md/{id}/dataResult/{id}', %r{/gdc/md/[\w]+/dataResult/[\d]+}],
685
+ ['/gdc/md/{id}', %r{/gdc/md/[\w]+}],
686
+
687
+ ['/gdc/projects/{id}/users/{id}/roles', %r{/gdc/projects/[\w]+/users/[\w]+/roles}],
688
+ ['/gdc/projects/{id}/users/{id}/permissions', %r{/gdc/projects/[\w]+/users/[\w]+/permissions}],
689
+ ['/gdc/projects/{id}/users', %r{/gdc/projects/[\w]+/users}],
690
+ ['/gdc/projects/{id}/schedules/{id}/executions/{id}', %r{/gdc/projects/[\w]+/schedules/[\w]+/executions/[\w]+}],
691
+ ['/gdc/projects/{id}/schedules/{id}', %r{/gdc/projects/[\w]+/schedules/[\w]+}],
692
+ ['/gdc/projects/{id}/roles/{id}', %r{/gdc/projects/[\w]+/roles/[\d]+}],
693
+ ['/gdc/projects/{id}/model/view/{id}', %r{/gdc/projects/[\w]+/model/view/[\w]+}],
694
+ ['/gdc/projects/{id}/model/view', %r{/gdc/projects/[\w]+/model/view}],
695
+ ['/gdc/projects/{id}/model/diff/{id}', %r{/gdc/projects/[\w]+/model/diff/[\w]+}],
696
+ ['/gdc/projects/{id}/model/diff', %r{/gdc/projects/[\w]+/model/diff}],
697
+ ['/gdc/projects/{id}/dataload/processes/{id}/executions/{id}', %r{/gdc/projects/[\w]+/dataload/processes/[\w-]+/executions/[\w-]+}],
698
+ ['/gdc/projects/{id}/dataload/processes/{id}', %r{/gdc/projects/[\w]+/dataload/processes/[\w-]+}],
699
+ ['/gdc/projects/{id}/', %r{/gdc/projects/[\w]+/}],
700
+ ['/gdc/projects/{id}', %r{/gdc/projects/[\w]+}]
701
+ ]
702
+
703
+ def update_stats(title, delta)
704
+ synchronize do
705
+ orig_title = title
706
+
707
+ placeholders = true
708
+
709
+ if placeholders
710
+ PH_MAP.each do |pm|
711
+ break if title.gsub!(pm[1], pm[0])
712
+ end
713
+ end
714
+
715
+ stat = stats[title]
716
+ if stat.nil?
717
+ stat = {
718
+ :min => delta,
719
+ :max => delta,
720
+ :total => 0,
721
+ :avg => 0,
722
+ :calls => 0,
723
+ :entries => []
724
+ }
725
+ end
726
+
727
+ stat[:min] = delta if delta < stat[:min]
728
+ stat[:max] = delta if delta > stat[:max]
729
+ stat[:total] += delta
730
+ stat[:calls] += 1
731
+ stat[:avg] = stat[:total] / stat[:calls]
732
+
733
+ stat[:entries] << orig_title if placeholders
734
+
735
+ stats[title] = stat
736
+ end
737
+ end
738
+
739
+ def webdav_dir_exists?(url)
740
+ method = :get
741
+ GoodData.logger.debug "#{method}: #{url}"
742
+
743
+ b = proc do
744
+ raw = {
745
+ :method => method,
746
+ :url => url,
747
+ :headers => @webdav_headers,
748
+ :verify_ssl => (@opts[:verify_ssl] == false || @opts[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
749
+ }.merge(cookies)
750
+ begin
751
+ RestClient::Request.execute(raw)
752
+ rescue RestClient::Exception => e
753
+ false if e.http_code == 404
754
+ end
755
+ end
756
+
757
+ res = nil
758
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
759
+ res = b.call
760
+ end
761
+ res
762
+ end
763
+ end
764
+ end
765
+ end