gooddata 0.6.24 → 0.6.25

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +54 -0
  3. data/CHANGELOG.md +3 -0
  4. data/DEPENDENCIES.md +155 -154
  5. data/README.md +15 -6
  6. data/Rakefile +5 -3
  7. data/dependency_decisions.yml +2 -0
  8. data/gooddata.gemspec +2 -3
  9. data/lib/gooddata/cli/cli.rb +1 -3
  10. data/lib/gooddata/cli/commands/auth_cmd.rb +16 -7
  11. data/lib/gooddata/cli/commands/project_cmd.rb +16 -178
  12. data/lib/gooddata/cli/shared.rb +46 -44
  13. data/lib/gooddata/commands/auth.rb +4 -0
  14. data/lib/gooddata/commands/project.rb +7 -24
  15. data/lib/gooddata/exceptions/object_migration.rb +4 -0
  16. data/lib/gooddata/exceptions/segment_not_empty.rb +18 -0
  17. data/lib/gooddata/extensions/object.rb +12 -0
  18. data/lib/gooddata/goodzilla/goodzilla.rb +56 -9
  19. data/lib/gooddata/helpers/global_helpers.rb +92 -0
  20. data/lib/gooddata/mixins/md_finders.rb +2 -8
  21. data/lib/gooddata/mixins/md_grantees.rb +42 -0
  22. data/lib/gooddata/mixins/md_id_to_uri.rb +1 -8
  23. data/lib/gooddata/mixins/md_object_id.rb +1 -1
  24. data/lib/gooddata/mixins/md_object_indexer.rb +5 -8
  25. data/lib/gooddata/mixins/md_object_query.rb +2 -2
  26. data/lib/gooddata/mixins/not_group.rb +17 -0
  27. data/lib/gooddata/mixins/rest_getters.rb +2 -2
  28. data/lib/gooddata/mixins/rest_resource.rb +1 -0
  29. data/lib/gooddata/mixins/to_json.rb +11 -0
  30. data/lib/gooddata/mixins/uri_getter.rb +9 -0
  31. data/lib/gooddata/models/blueprint/anchor_field.rb +14 -0
  32. data/lib/gooddata/models/blueprint/project_blueprint.rb +15 -1
  33. data/lib/gooddata/models/blueprint/to_wire.rb +10 -0
  34. data/lib/gooddata/models/client.rb +178 -0
  35. data/lib/gooddata/models/client_synchronization_result.rb +31 -0
  36. data/lib/gooddata/models/client_synchronization_result_details.rb +41 -0
  37. data/lib/gooddata/models/datawarehouse.rb +1 -5
  38. data/lib/gooddata/models/domain.rb +85 -1
  39. data/lib/gooddata/models/execution.rb +0 -2
  40. data/lib/gooddata/models/execution_detail.rb +0 -2
  41. data/lib/gooddata/models/from_wire.rb +10 -0
  42. data/lib/gooddata/models/invitation.rb +1 -1
  43. data/lib/gooddata/models/links.rb +1 -1
  44. data/lib/gooddata/models/membership.rb +10 -6
  45. data/lib/gooddata/models/metadata.rb +98 -11
  46. data/lib/gooddata/models/metadata/attribute.rb +6 -7
  47. data/lib/gooddata/models/metadata/dashboard.rb +41 -75
  48. data/lib/gooddata/models/metadata/dashboard/dashboard_item.rb +20 -4
  49. data/lib/gooddata/models/metadata/dashboard/filter_apply_item.rb +37 -0
  50. data/lib/gooddata/models/metadata/dashboard/filter_item.rb +49 -0
  51. data/lib/gooddata/models/metadata/dashboard/geo_chart_item.rb +56 -0
  52. data/lib/gooddata/models/metadata/dashboard/headline_item.rb +56 -0
  53. data/lib/gooddata/models/metadata/dashboard/iframe_item.rb +46 -0
  54. data/lib/gooddata/models/metadata/dashboard/report_item.rb +49 -8
  55. data/lib/gooddata/models/metadata/dashboard/text_item.rb +55 -0
  56. data/lib/gooddata/models/metadata/dashboard_tab.rb +83 -30
  57. data/lib/gooddata/models/metadata/dataset.rb +0 -2
  58. data/lib/gooddata/models/metadata/dimension.rb +1 -3
  59. data/lib/gooddata/models/metadata/fact.rb +1 -3
  60. data/lib/gooddata/models/metadata/label.rb +1 -3
  61. data/lib/gooddata/models/metadata/metric.rb +11 -42
  62. data/lib/gooddata/models/metadata/report.rb +7 -18
  63. data/lib/gooddata/models/metadata/report_definition.rb +21 -113
  64. data/lib/gooddata/models/metadata/scheduled_mail.rb +274 -0
  65. data/lib/gooddata/models/metadata/scheduled_mail/dashboard_attachment.rb +62 -0
  66. data/lib/gooddata/models/metadata/scheduled_mail/report_attachment.rb +64 -0
  67. data/lib/gooddata/models/metadata/variable.rb +8 -2
  68. data/lib/gooddata/models/model.rb +2 -9
  69. data/lib/gooddata/models/process.rb +7 -29
  70. data/lib/gooddata/models/profile.rb +1 -1
  71. data/lib/gooddata/models/project.rb +131 -167
  72. data/lib/gooddata/models/project_creator.rb +2 -7
  73. data/lib/gooddata/models/project_metadata.rb +2 -10
  74. data/lib/gooddata/models/project_role.rb +4 -10
  75. data/lib/gooddata/models/report_data_result.rb +3 -5
  76. data/lib/gooddata/models/schedule.rb +4 -31
  77. data/lib/gooddata/models/segment.rb +192 -0
  78. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +2 -2
  79. data/lib/gooddata/models/user_filters/user_filter_builder.rb +1 -1
  80. data/lib/gooddata/models/user_filters/variable_user_filter.rb +11 -0
  81. data/lib/gooddata/models/user_group.rb +241 -0
  82. data/lib/gooddata/rest/connection.rb +81 -16
  83. data/lib/gooddata/rest/object.rb +29 -0
  84. data/lib/gooddata/rest/object_factory.rb +6 -1
  85. data/lib/gooddata/rest/resource.rb +7 -1
  86. data/lib/gooddata/version.rb +1 -1
  87. data/spec/environment/default.rb +19 -16
  88. data/spec/environment/develop.rb +10 -10
  89. data/spec/environment/hotfix.rb +6 -6
  90. data/spec/environment/production.rb +14 -14
  91. data/spec/environment/release.rb +6 -6
  92. data/spec/environment/staging.rb +9 -9
  93. data/spec/environment/staging_3.rb +14 -15
  94. data/spec/integration/blueprint_with_grain_spec.rb +72 -0
  95. data/spec/integration/clients_spec.rb +135 -0
  96. data/spec/integration/date_dim_switch_spec.rb +142 -0
  97. data/spec/integration/full_project_spec.rb +3 -3
  98. data/spec/integration/project_spec.rb +20 -0
  99. data/spec/integration/segments_spec.rb +141 -0
  100. data/spec/integration/user_group_spec.rb +127 -0
  101. data/spec/spec_helper.rb +4 -0
  102. data/spec/unit/models/domain_spec.rb +7 -1
  103. data/spec/unit/models/metric_spec.rb +0 -8
  104. data/spec/unit/models/profile_spec.rb +1 -1
  105. data/spec/unit/models/report_result_data_spec.rb +6 -0
  106. metadata +38 -38
  107. data/lib/gooddata/cli/commands/api_cmd.rb +0 -34
  108. data/lib/gooddata/cli/commands/console_cmd.rb +0 -40
  109. data/lib/gooddata/cli/commands/domain_cmd.rb +0 -46
  110. data/lib/gooddata/cli/commands/process_cmd.rb +0 -145
  111. data/lib/gooddata/cli/commands/projects_cmd.rb +0 -23
  112. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +0 -77
  113. data/lib/gooddata/cli/commands/scaffold_cmd.rb +0 -35
  114. data/lib/gooddata/cli/commands/user_cmd.rb +0 -24
@@ -8,8 +8,6 @@ require_relative '../metadata'
8
8
 
9
9
  module GoodData
10
10
  class Dataset < MdObject
11
- root_key :dataSet
12
-
13
11
  class << self
14
12
  # Method intended to get all objects of that type in a specified project
15
13
  #
@@ -10,9 +10,7 @@ require_relative 'metadata'
10
10
 
11
11
  module GoodData
12
12
  class Dimension < GoodData::MdObject
13
- root_key :dimension
14
-
15
- include GoodData::Mixin::IsDimension
13
+ include Mixin::IsDimension
16
14
 
17
15
  class << self
18
16
  # Method intended to get all objects of that type in a specified project
@@ -12,9 +12,7 @@ require_relative 'metadata'
12
12
 
13
13
  module GoodData
14
14
  class Fact < GoodData::MdObject
15
- root_key :fact
16
-
17
- include GoodData::Mixin::IsFact
15
+ include Mixin::IsFact
18
16
 
19
17
  # TODO: verify that we have all (which we do not right now)
20
18
  FACT_BASE_AGGREGATIONS = [:sum, :min, :max, :avg, :median, :runsum, :runmin, :runmax, :runavg, :runstdev, :runstdevp, :runvar, :runvarp, :stdev, :stdevp, :var, :varp]
@@ -10,9 +10,7 @@ require_relative 'metadata'
10
10
 
11
11
  module GoodData
12
12
  class Label < GoodData::MdObject
13
- root_key :attributeDisplayForm
14
-
15
- include GoodData::Mixin::IsLabel
13
+ include Mixin::IsLabel
16
14
 
17
15
  # Finds an attribute element URI for given value. This URI can be used by find_element_value to find the original value again
18
16
  # @param [String] value value of an label you are looking for
@@ -12,12 +12,7 @@ require_relative 'metadata'
12
12
  module GoodData
13
13
  # Metric representation
14
14
  class Metric < MdObject
15
- include GoodData::Mixin::Lockable
16
-
17
- alias_method :to_hash, :json
18
-
19
- include GoodData::Mixin::RestResource
20
- root_key :metric
15
+ include Mixin::Lockable
21
16
 
22
17
  class << self
23
18
  # Method intended to get all objects of that type in a specified project
@@ -34,14 +29,7 @@ module GoodData
34
29
  end
35
30
 
36
31
  def create(metric, options = { :client => GoodData.connection, :project => GoodData.project })
37
- client = options[:client]
38
- fail ArgumentError, 'No :client specified' if client.nil?
39
-
40
- p = options[:project]
41
- fail ArgumentError, 'No :project specified' if p.nil?
42
-
43
- project = GoodData::Project[p, options]
44
- fail ArgumentError, 'Wrong :project specified' if project.nil?
32
+ client, project = GoodData.get_client_and_project(options)
45
33
 
46
34
  if metric.is_a?(String)
47
35
  expression = metric || options[:expression]
@@ -119,14 +107,7 @@ module GoodData
119
107
  end
120
108
 
121
109
  def xexecute(expression, opts = { :client => GoodData.connection, :project => GoodData.project })
122
- client = opts[:client]
123
- fail ArgumentError, 'No :client specified' if client.nil?
124
-
125
- p = opts[:project]
126
- fail ArgumentError, 'No :project specified' if p.nil?
127
-
128
- project = GoodData::Project[p, opts]
129
- fail ArgumentError, 'Wrong :project specified' if project.nil?
110
+ GoodData.get_client_and_project(opts)
130
111
 
131
112
  execute(expression, opts.merge(:extended_notation => true))
132
113
  end
@@ -175,27 +156,15 @@ module GoodData
175
156
  contain?(uri)
176
157
  end
177
158
 
178
- # Method used for replacing objects like Attribute, Fact or Metric.
179
- # @param [GoodData::MdObject] what Object that should be replaced
180
- # @param [GoodData::MdObject] for_what Object it is replaced with
159
+ # Method used for replacing values in their state according to mapping. Can be used to replace any values but it is typically used to replace the URIs. Returns a new object of the same type.
160
+ #
161
+ # @param [Array<Array>]Mapping specifying what should be exchanged for what. As mapping should be used output of GoodData::Helpers.prepare_mapping.
181
162
  # @return [GoodData::Metric]
182
- def replace(what, for_what = nil)
183
- pairs = if what.is_a?(Hash)
184
- whats = what.keys
185
- to_whats = what.values
186
- whats.zip(to_whats)
187
- elsif what.is_a?(Array) && for_what.is_a?(Array)
188
- whats.zip(to_whats)
189
- else
190
- [[what, for_what]]
191
- end
192
-
193
- pairs.each do |a, b|
194
- uri_what = a.respond_to?(:uri) ? a.uri : a
195
- uri_for_what = b.respond_to?(:uri) ? b.uri : b
196
- self.expression = expression.gsub("[#{uri_what}]", "[#{uri_for_what}]")
197
- end
198
- self
163
+ def replace(mapping)
164
+ x = GoodData::MdObject.replace_quoted(self, mapping)
165
+ x = GoodData::MdObject.replace_bracketed(x, mapping)
166
+ vals = GoodData::MdObject.find_replaceable_values(x, mapping)
167
+ GoodData::MdObject.replace_bracketed(x, vals)
199
168
  end
200
169
 
201
170
  # Method used for replacing attribute element values. Looks up certain value of a label in the MAQL expression and exchanges it for a different value of the same label.
@@ -9,9 +9,7 @@ require_relative 'metadata'
9
9
 
10
10
  module GoodData
11
11
  class Report < GoodData::MdObject
12
- root_key :report
13
-
14
- include GoodData::Mixin::Lockable
12
+ include Mixin::Lockable
15
13
 
16
14
  class << self
17
15
  # Method intended to get all objects of that type in a specified project
@@ -24,14 +22,7 @@ module GoodData
24
22
  end
25
23
 
26
24
  def create(options = { :client => GoodData.connection, :project => GoodData.project })
27
- client = options[:client]
28
- fail ArgumentError, 'No :client specified' if client.nil?
29
-
30
- p = options[:project]
31
- fail ArgumentError, 'No :project specified' if p.nil?
32
-
33
- project = client.projects(p)
34
- fail ArgumentError, 'Wrong :project specified' if project.nil?
25
+ client, project = GoodData.get_client_and_project(options)
35
26
 
36
27
  title = options[:title]
37
28
  fail 'Report needs a title specified' unless title
@@ -208,15 +199,13 @@ module GoodData
208
199
  self
209
200
  end
210
201
 
211
- # Replaces all occurences of something with something else. This is just a convenience method. The
212
- # real work is done under the hood in report definition. This is just deferring to those
202
+ # Method used for replacing values in their state according to mapping. Can be used to replace any values but it is typically used to replace the URIs. Returns a new object of the same type.
213
203
  #
214
- # @param what [Object] What you would like to have changed
215
- # @param for_what [Object] What you would like to have changed this for
216
- # @return [GoodData::Report] Returns report with removed definition
217
- def replace(what, for_what)
204
+ # @param [Array<Array>]Mapping specifying what should be exchanged for what. As mapping should be used output of GoodData::Helpers.prepare_mapping.
205
+ # @return [GoodData::Report]
206
+ def replace(mapping)
218
207
  new_defs = definitions.map do |rep_def|
219
- rep_def.replace(what, for_what)
208
+ rep_def.replace(mapping)
220
209
  end
221
210
  new_defs.pmap(&:save)
222
211
  self
@@ -12,8 +12,6 @@ module GoodData
12
12
  # Report Definition
13
13
  # TODO: Add more doc ...
14
14
  class ReportDefinition < GoodData::MdObject
15
- root_key :reportDefinition
16
-
17
15
  class << self
18
16
  # Method intended to get all objects of that type in a specified project
19
17
  #
@@ -52,10 +50,16 @@ module GoodData
52
50
  }
53
51
  end
54
52
 
55
- def create_filters_part(filters)
56
- filters.select { |f| f.class == GoodData::Variable }.map do |v|
57
- { expression: "[#{v.uri}]" }
58
- end
53
+ # Method creates the list of filter representaion suitable for posting on the api. It can currently recognize 2 types of filters. Variable filters and attribute filters. Method for internal usage
54
+ #
55
+ # @param filters [GoodData::Variable|Array<Array>]
56
+ # @param options [Hash] the options hash
57
+ # @return [Array<Hash>] Returns the structure that is stored internally in the report definition and later psted on the API
58
+ def create_filters_part(filters, options = {})
59
+ project = options[:project]
60
+ vars = filters.select { |f| f.is_a?(GoodData::Variable) }.map { |v| { expression: "[#{v.uri}]" } }
61
+ category = filters.select { |f| f.is_a?(Array) }.map { |v| GoodData::SmallGoodZilla.create_category_filter(v, project) }
62
+ vars + category
59
63
  end
60
64
 
61
65
  def create_part(stuff)
@@ -75,10 +79,7 @@ module GoodData
75
79
  end
76
80
 
77
81
  def find(stuff, opts = { :client => GoodData.connection, :project => GoodData.project })
78
- client = opts[:client]
79
- project = opts[:project]
80
- fail ArgumentError, 'No :client specified' if client.nil?
81
- fail ArgumentError, 'No :project specified' if project.nil?
82
+ _client, project = GoodData.get_client_and_project(opts)
82
83
 
83
84
  stuff.map do |item|
84
85
  obj = if item.is_a?(String)
@@ -133,14 +134,7 @@ module GoodData
133
134
  end
134
135
 
135
136
  def create(options = { :client => GoodData.connection, :project => GoodData.project })
136
- client = options[:client]
137
- fail ArgumentError, 'No :client specified' if client.nil?
138
-
139
- p = options[:project]
140
- fail ArgumentError, 'No :project specified' if p.nil?
141
-
142
- project = GoodData::Project[p, options]
143
- fail ArgumentError, 'Wrong :project specified' if project.nil?
137
+ client, project = GoodData.get_client_and_project(options)
144
138
 
145
139
  left = Array(options[:left])
146
140
  top = Array(options[:top])
@@ -167,7 +161,7 @@ module GoodData
167
161
  'rows' => ReportDefinition.create_part(left)
168
162
  },
169
163
  'format' => 'grid',
170
- 'filters' => ReportDefinition.create_filters_part(filters)
164
+ 'filters' => ReportDefinition.create_filters_part(filters, :project => project)
171
165
  },
172
166
  'meta' => {
173
167
  'tags' => '',
@@ -249,101 +243,15 @@ module GoodData
249
243
  content['filters'].map { |f| f['expression'] }
250
244
  end
251
245
 
252
- # Replace certain object in report definition. Returns new definition which is not saved.
246
+ # Method used for replacing values in their state according to mapping. Can be used to replace any values but it is typically used to replace the URIs. Returns a new object of the same type.
253
247
  #
254
- # @param what [GoodData::MdObject | String] Object which responds to uri or a string that should be replaced
255
- # @option for_what [GoodData::MdObject | String] Object which responds to uri or a string that should used as replacement
256
- # @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
257
- def replace(what, for_what = nil)
258
- pairs = if what.is_a?(Hash)
259
- whats = what.keys
260
- to_whats = what.values
261
- whats.zip(to_whats)
262
- elsif what.is_a?(Array) && for_what.is_a?(Array)
263
- whats.zip(to_whats)
264
- else
265
- [[what, for_what]]
266
- end
267
-
268
- pairs.each do |pair|
269
- what = pair[0]
270
- for_what = pair[1]
271
-
272
- uri_what = what.respond_to?(:uri) ? what.uri : what
273
- uri_for_what = for_what.respond_to?(:uri) ? for_what.uri : for_what
274
-
275
- content['grid']['metrics'] = metric_parts.map do |item|
276
- GoodData::Helpers.deep_dup(item).tap do |i|
277
- i['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
278
- end
279
- end
280
-
281
- cols = content['grid']['columns'] || []
282
- content['grid']['columns'] = cols.map do |item|
283
- if item.is_a?(Hash)
284
- GoodData::Helpers.deep_dup(item).tap do |i|
285
- i['attribute']['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
286
- end
287
- else
288
- item
289
- end
290
- end
291
-
292
- rows = content['grid']['rows'] || []
293
- content['grid']['rows'] = rows.map do |item|
294
- if item.is_a?(Hash)
295
- GoodData::Helpers.deep_dup(item).tap do |i|
296
- i['attribute']['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
297
- end
298
- else
299
- item
300
- end
301
- end
302
-
303
- widths = content['grid']['columnWidths'] || []
304
- content['grid']['columnWidths'] = widths.map do |item|
305
- if item.is_a?(Hash)
306
- GoodData::Helpers.deep_dup(item).tap do |i|
307
- if i['locator'].length > 0 && i['locator'][0].key?('attributeHeaderLocator')
308
- i['locator'][0]['attributeHeaderLocator']['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
309
- end
310
- end
311
- else
312
- item
313
- end
314
- end
315
-
316
- sort = content['grid']['sort']['columns'] || []
317
- content['grid']['sort']['columns'] = sort.map do |item|
318
- if item.is_a?(Hash)
319
- GoodData::Helpers.deep_dup(item).tap do |i|
320
- next unless i.key?('metricSort')
321
- next unless i['metricSort'].key?('locators')
322
- next unless i['metricSort']['locators'][0].key?('attributeLocator2')
323
- i['metricSort']['locators'][0]['attributeLocator2']['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
324
- i['metricSort']['locators'][0]['attributeLocator2']['element'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
325
- end
326
- else
327
- item
328
- end
329
- end
330
-
331
- if content.key?('chart')
332
- content['chart']['buckets'] = content['chart']['buckets'].reduce({}) do |a, e|
333
- key = e[0]
334
- val = e[1]
335
- a[key] = val.map do |item|
336
- GoodData::Helpers.deep_dup(item).tap do |i|
337
- i['uri'].gsub!("[#{uri_what}]", "[#{uri_for_what}]")
338
- end
339
- end
340
- a
341
- end
342
- end
343
-
344
- content['filters'] = filters.map { |filter_expression| { 'expression' => filter_expression.gsub("[#{uri_what}]", "[#{uri_for_what}]") } }
345
- end
346
- self
248
+ # @param [Array<Array>]Mapping specifying what should be exchanged for what. As mapping should be used output of GoodData::Helpers.prepare_mapping.
249
+ # @return [GoodData::ReportDefinition]
250
+ def replace(mapping)
251
+ x = GoodData::MdObject.replace_quoted(self, mapping)
252
+ x = GoodData::MdObject.replace_bracketed(x, mapping)
253
+ vals = GoodData::MdObject.find_replaceable_values(self, mapping)
254
+ GoodData::MdObject.replace_bracketed(x, vals)
347
255
  end
348
256
 
349
257
  # Return true if the report definition is a table
@@ -0,0 +1,274 @@
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_relative 'scheduled_mail/dashboard_attachment'
8
+ require_relative 'scheduled_mail/report_attachment'
9
+
10
+ require_relative '../../helpers/global_helpers'
11
+
12
+ require_relative '../../core/core'
13
+ require_relative '../metadata'
14
+ require_relative 'metadata'
15
+ require_relative 'report'
16
+
17
+ require 'multi_json'
18
+
19
+ module GoodData
20
+ class ScheduledMail < GoodData::MdObject
21
+ root_key :scheduledMail
22
+
23
+ include GoodData::Mixin::Lockable
24
+
25
+ DEFAULT_OPTS = {
26
+ # Meta options
27
+ :title => 'Scheduled report example',
28
+ :summary => 'Daily at 12:00pm PT',
29
+ :tags => '',
30
+ :deprecated => 0,
31
+
32
+ # Content When options
33
+ :recurrency => '0:0:0:12:0:0',
34
+ :startDate => '2012-06-05',
35
+ :timeZone => 'America/Los_Angeles',
36
+
37
+ # Content Email options
38
+ :to => [],
39
+ :bcc => [],
40
+ :subject => 'Scheduled Report',
41
+ :body => "Hey, I'm sending you new Reports and Dashboards!",
42
+
43
+ # Attachments
44
+ :attachments => []
45
+ }
46
+
47
+ class << self
48
+ # Method intended to get all objects of that type in a specified project
49
+ #
50
+ # @param options [Hash] the options hash
51
+ # @option options [Boolean] :full if passed true the subclass can decide to pull in full objects. This is desirable from the usability POV but unfortunately has negative impact on performance so it is not the default
52
+ # @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
53
+ def all(options = { :client => GoodData.connection, :project => GoodData.project })
54
+ query('scheduledMail', ScheduledMail, options)
55
+ end
56
+
57
+ def convert_attachment(item, opts)
58
+ if item.is_a?(GoodData::Dashboard)
59
+ {
60
+ dashboardAttachment: GoodData::DashboardAttachment::DEFAULT_OPTS.merge(opts.merge(:uri => item.uri))
61
+ }
62
+ elsif item.is_a?(GoodData::Report)
63
+ {
64
+ reportAttachment: GoodData::ReportAttachment::DEFAULT_OPTS.merge(opts.merge(:uri => item.uri))
65
+ }
66
+ elsif item.is_a?(GoodData::DashboardAttachment)
67
+ item.json
68
+ elsif item.is_a?(GoodData::ReportAttachment)
69
+ item.json
70
+ elsif item.is_a?(Hash)
71
+ item
72
+ elsif item == 'dashboardAttachment'
73
+ {
74
+ dashboardAttachment: GoodData::DashboardAttachment::DEFAULT_OPTS.merge(opts)
75
+ }
76
+ elsif item == 'reportAttachment'
77
+ {
78
+ reportAttachment: GoodData::ReportAttachment::DEFAULT_OPTS.merge(opts)
79
+ }
80
+ end
81
+ end
82
+
83
+ def create(options = { :client => GoodData.connection, :project => GoodData.project })
84
+ client = options[:client]
85
+ fail ArgumentError, 'No :client specified' if client.nil?
86
+
87
+ p = options[:project]
88
+ fail ArgumentError, 'No :project specified' if p.nil?
89
+
90
+ project = client.projects(p)
91
+ fail ArgumentError, 'Wrong :project specified' if project.nil?
92
+
93
+ opts = GoodData::ScheduledMail::DEFAULT_OPTS.merge(GoodData::Helpers.symbolize_keys(options))
94
+
95
+ scheduled_mail = {
96
+ :scheduledMail => {
97
+ :meta => {
98
+ :title => opts[:title],
99
+ :summary => opts[:summary],
100
+ :tags => opts[:tags],
101
+ :deprecated => opts[:deprecated]
102
+ },
103
+ :content => {
104
+ :when => {
105
+ :recurrency => opts[:recurrency],
106
+ :startDate => opts[:startDate] || opts[:start_date],
107
+ :timeZone => opts[:timeZone] || opts[:time_zone] || opts[:timezone]
108
+ },
109
+ :to => opts[:to].is_a?(Array) ? opts[:to] : [opts[:to]],
110
+ :bcc => opts[:bcc].is_a?(Array) ? opts[:bcc] : [opts[:bcc]],
111
+ :subject => opts[:subject],
112
+ :body => opts[:body]
113
+ }
114
+ }
115
+ }
116
+
117
+ attachments = opts[:attachments].map do |attachment|
118
+ key = attachment.keys.first
119
+ body = attachment[key]
120
+
121
+ ScheduledMail.convert_attachment(key, body)
122
+ end
123
+
124
+ scheduled_mail[:scheduledMail][:content][:attachments] = attachments
125
+
126
+ client.create(ScheduledMail, GoodData::Helpers.deep_stringify_keys(scheduled_mail), :project => project)
127
+ end
128
+ end
129
+
130
+ # Add attachment
131
+ #
132
+ # @param [String | Object] item Schedule to add
133
+ # @param [Hash] opts Optional schedule options
134
+ # @return [Array] New list of attachments
135
+ def add_attachment(item, opts)
136
+ attachment = ScheduledMail.convert_attachment(item, opts)
137
+ fail ArgumentError unless attachment
138
+
139
+ content['attachments'] << attachment
140
+ end
141
+
142
+ # Add attachment and save
143
+ #
144
+ # @param [String | Object] item Schedule to add
145
+ # @param [Hash] opts Optional schedule options
146
+ # @return [Array] New list of attachments
147
+ def add_attachment!(item, opts)
148
+ add_attachment(item, opts)
149
+ save!
150
+ end
151
+
152
+ # Get attachments as objects
153
+ #
154
+ # @return [Array<GoodData::DashboardAttachment | GoodData::ReportAttachment>] Array of attachments
155
+ def attachments
156
+ content['attachments'].map do |attachment|
157
+ key = attachment.keys.first
158
+
159
+ if key == 'dashboardAttachment'
160
+ GoodData::DashboardAttachment.new(self, attachment)
161
+ elsif key == 'reportAttachment'
162
+ GoodData::ReportAttachment.new(self, attachment)
163
+ else
164
+ RuntimeError "Unsupported attachment type: #{key}"
165
+ end
166
+ end
167
+ end
168
+
169
+ # Get body
170
+ #
171
+ # @return [String] Scheduled email body
172
+ def body
173
+ content['body']
174
+ end
175
+
176
+ # Set body
177
+ #
178
+ # @param [String] new_body New body to be set
179
+ # @return [String] New body
180
+ def body=(new_body)
181
+ content['body'] = new_body
182
+ end
183
+
184
+ # Get recurrency string
185
+ #
186
+ # @return [String] Recurrency (cron) string
187
+ def recurrency
188
+ content['when']['recurrency']
189
+ end
190
+
191
+ # Set recurrency
192
+ #
193
+ # @param [String] new_recurrency New recurrency to be set
194
+ # @return [Hash] New recurrency
195
+ def recurrency=(new_recurrency)
196
+ content['when']['recurrency'] = new_recurrency
197
+ end
198
+
199
+ # Get start date
200
+ #
201
+ # @return [String] Start date
202
+ def start_date
203
+ content['when']['startDate']
204
+ end
205
+
206
+ # Set start date
207
+ #
208
+ # @param [String] new_start_date New start date to be set
209
+ # @return [String] New start date
210
+ def start_date=(new_start_date)
211
+ content['when']['startDate'] = new_start_date
212
+ end
213
+
214
+ # Get subject
215
+ #
216
+ # @return [String] Subject of scheduled email
217
+ def subject
218
+ content['subject']
219
+ end
220
+
221
+ # Set subject
222
+ #
223
+ # @param [String] new_subject New subject to be set
224
+ # @return [String] New subject
225
+ def subject=(new_subject)
226
+ content['subject'] = new_subject
227
+ end
228
+
229
+ # Get timezone
230
+ #
231
+ # @return [String] Timezone
232
+ def timezone
233
+ content['when']['timeZone']
234
+ end
235
+
236
+ # Set timezone
237
+ #
238
+ # @param [String] new_timezone New timezone string to be set
239
+ # @return [String] New timezone
240
+ def timezone=(new_timezone)
241
+ content['when']['timeZone'] = new_timezone
242
+ end
243
+
244
+ # Get recipients
245
+ #
246
+ # @return [String] Recipients of email
247
+ def to
248
+ content['to']
249
+ end
250
+
251
+ # Set recipients
252
+ #
253
+ # @param [String|Array<String>] new_to New recipients to be set
254
+ # @return [Array<String>] New recipient list
255
+ def to=(new_to)
256
+ content['to'] = new_to.is_a?(Array) ? new_to : [new_to]
257
+ end
258
+
259
+ # Get 'when' section
260
+ #
261
+ # @return [Hash] 'when' section from json
262
+ def when
263
+ content['when']
264
+ end
265
+
266
+ # Set 'when' section
267
+ #
268
+ # @param [Hash] new_when New 'when' section to be set
269
+ # @return [Hash] New 'when' section
270
+ def when=(new_when)
271
+ content['when'] = new_when
272
+ end
273
+ end
274
+ end