zendesk_api 0.2.6 → 0.3.0

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 (121) hide show
  1. data/.gitignore +2 -1
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +10 -2
  4. data/LICENSE +176 -19
  5. data/Readme.md +13 -5
  6. data/config/newrelic.yml +255 -0
  7. data/lib/zendesk_api/association.rb +1 -1
  8. data/lib/zendesk_api/associations.rb +129 -100
  9. data/lib/zendesk_api/client.rb +44 -25
  10. data/lib/zendesk_api/collection.rb +83 -58
  11. data/lib/zendesk_api/console/extensions.rb +47 -28
  12. data/lib/zendesk_api/server/base.rb +4 -0
  13. data/lib/zendesk_api/server/docs/account_settings.md +8 -0
  14. data/lib/zendesk_api/server/docs/automations.md +6 -0
  15. data/lib/zendesk_api/server/docs/changes_roadmap.md +76 -1
  16. data/lib/zendesk_api/server/docs/forum_subscriptions.md +2 -2
  17. data/lib/zendesk_api/server/docs/introduction.md +4 -2
  18. data/lib/zendesk_api/server/docs/macros.md +2 -0
  19. data/lib/zendesk_api/server/docs/organizations.md +3 -4
  20. data/lib/zendesk_api/server/docs/requests.md +21 -7
  21. data/lib/zendesk_api/server/docs/tickets.md +64 -8
  22. data/lib/zendesk_api/server/docs/topic_subscriptions.md +3 -3
  23. data/lib/zendesk_api/server/docs/topic_votes.md +0 -1
  24. data/lib/zendesk_api/server/docs/triggers.md +7 -0
  25. data/lib/zendesk_api/server/docs/users.md +4 -4
  26. data/lib/zendesk_api/server/docs/views.md +57 -8
  27. data/lib/zendesk_api/server/public/doc/ZendeskAPI.html +131 -0
  28. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Ability.html +190 -0
  29. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Activity.html +616 -0
  30. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Attachment.html +362 -0
  31. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Automation.html +438 -0
  32. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Bookmark.html +243 -0
  33. data/lib/zendesk_api/server/public/doc/ZendeskAPI/CRMData.html +190 -0
  34. data/lib/zendesk_api/server/public/doc/ZendeskAPI/CRMDataStatus.html +190 -0
  35. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Category.html +462 -0
  36. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Client.html +1490 -0
  37. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Collection.html +2825 -0
  38. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Configuration.html +1212 -0
  39. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Console.html +860 -0
  40. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Console/Eval.html +190 -0
  41. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Create.html +134 -0
  42. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Create/ClassMethods.html +322 -0
  43. data/lib/zendesk_api/server/public/doc/ZendeskAPI/CreateResource.html +222 -0
  44. data/lib/zendesk_api/server/public/doc/ZendeskAPI/CustomRole.html +190 -0
  45. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Data.html +1432 -0
  46. data/lib/zendesk_api/server/public/doc/ZendeskAPI/DataResource.html +348 -0
  47. data/lib/zendesk_api/server/public/doc/ZendeskAPI/DeleteResource.html +216 -0
  48. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Destroy.html +307 -0
  49. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Destroy/ClassMethod.html +245 -0
  50. data/lib/zendesk_api/server/public/doc/ZendeskAPI/FormatError.html +123 -0
  51. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Forum.html +1196 -0
  52. data/lib/zendesk_api/server/public/doc/ZendeskAPI/ForumSubscription.html +616 -0
  53. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Group.html +243 -0
  54. data/lib/zendesk_api/server/public/doc/ZendeskAPI/GroupMembership.html +616 -0
  55. data/lib/zendesk_api/server/public/doc/ZendeskAPI/JobStatus.html +209 -0
  56. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Locale.html +209 -0
  57. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Macro.html +438 -0
  58. data/lib/zendesk_api/server/public/doc/ZendeskAPI/MobileDevice.html +361 -0
  59. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Organization.html +1016 -0
  60. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Read.html +278 -0
  61. data/lib/zendesk_api/server/public/doc/ZendeskAPI/ReadResource.html +220 -0
  62. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Request.html +826 -0
  63. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Request/Comment.html +604 -0
  64. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Resource.html +258 -0
  65. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Role.html +190 -0
  66. data/lib/zendesk_api/server/public/doc/ZendeskAPI/RuleExecution.html +383 -0
  67. data/lib/zendesk_api/server/public/doc/ZendeskAPI/SatisfactionRating.html +938 -0
  68. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Save.html +510 -0
  69. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Search.html +403 -0
  70. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Search/Result.html +166 -0
  71. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server.html +131 -0
  72. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/App.html +523 -0
  73. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/Helper.html +684 -0
  74. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/HtmlRenderer.html +303 -0
  75. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/HtmlRenderer/RedcarpetRenderer.html +508 -0
  76. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/UserRequest.html +125 -0
  77. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Server/ZlibJSON.html +244 -0
  78. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Setting.html +350 -0
  79. data/lib/zendesk_api/server/public/doc/ZendeskAPI/SharingAgreement.html +209 -0
  80. data/lib/zendesk_api/server/public/doc/ZendeskAPI/SingularResource.html +247 -0
  81. data/lib/zendesk_api/server/public/doc/ZendeskAPI/SuspendedTicket.html +342 -0
  82. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Ticket.html +2731 -0
  83. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Ticket/Audit.html +385 -0
  84. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Ticket/Comment.html +636 -0
  85. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Ticket/Tag.html +243 -0
  86. data/lib/zendesk_api/server/public/doc/ZendeskAPI/TicketField.html +243 -0
  87. data/lib/zendesk_api/server/public/doc/ZendeskAPI/TicketMetric.html +205 -0
  88. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Topic.html +1086 -0
  89. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Topic/TopicComment.html +232 -0
  90. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Topic/TopicVote.html +624 -0
  91. data/lib/zendesk_api/server/public/doc/ZendeskAPI/TopicComment.html +743 -0
  92. data/lib/zendesk_api/server/public/doc/ZendeskAPI/TopicSubscription.html +616 -0
  93. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Trigger.html +438 -0
  94. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Update.html +140 -0
  95. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Update/ClassMethod.html +237 -0
  96. data/lib/zendesk_api/server/public/doc/ZendeskAPI/UpdateResource.html +222 -0
  97. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Upload.html +404 -0
  98. data/lib/zendesk_api/server/public/doc/ZendeskAPI/User.html +3611 -0
  99. data/lib/zendesk_api/server/public/doc/ZendeskAPI/User/Identity.html +563 -0
  100. data/lib/zendesk_api/server/public/doc/ZendeskAPI/User/TopicComment.html +194 -0
  101. data/lib/zendesk_api/server/public/doc/ZendeskAPI/Verbs.html +338 -0
  102. data/lib/zendesk_api/server/public/doc/ZendeskAPI/View.html +1283 -0
  103. data/lib/zendesk_api/server/public/doc/ZendeskAPI/ViewCount.html +190 -0
  104. data/lib/zendesk_api/server/public/doc/ZendeskAPI/ViewRow.html +1342 -0
  105. data/lib/zendesk_api/server/public/doc/_index.html +799 -0
  106. data/lib/zendesk_api/server/public/doc/class_list.html +53 -0
  107. data/lib/zendesk_api/server/public/doc/css/common.css +1 -0
  108. data/lib/zendesk_api/server/public/doc/css/full_list.css +57 -0
  109. data/lib/zendesk_api/server/public/doc/css/style.css +328 -0
  110. data/lib/zendesk_api/server/public/doc/file.Readme.html +377 -0
  111. data/lib/zendesk_api/server/public/doc/file_list.html +55 -0
  112. data/lib/zendesk_api/server/public/doc/frames.html +28 -0
  113. data/lib/zendesk_api/server/public/doc/index.html +377 -0
  114. data/lib/zendesk_api/server/public/doc/js/app.js +214 -0
  115. data/lib/zendesk_api/server/public/doc/js/full_list.js +173 -0
  116. data/lib/zendesk_api/server/public/doc/js/jquery.js +4 -0
  117. data/lib/zendesk_api/server/public/doc/method_list.html +2540 -0
  118. data/lib/zendesk_api/server/public/doc/top-level-namespace.html +144 -0
  119. data/lib/zendesk_api/version.rb +1 -1
  120. data/zendesk_api.gemspec +1 -1
  121. metadata +96 -3
@@ -71,7 +71,7 @@ module ZendeskAPI
71
71
 
72
72
  def _side_load(resource, side_loads)
73
73
  side_loads.map! do |side_load|
74
- resource.send(:wrap_resource, side_load, options[:class], options)
74
+ resource.send(:wrap_resource, side_load, options)
75
75
  end
76
76
 
77
77
  ZendeskAPI::Collection.new(resource.client, options[:class]).tap do |collection|
@@ -10,11 +10,13 @@ module ZendeskAPI
10
10
  # @private
11
11
  module Associations
12
12
  def self.included(base)
13
- base.send(:extend, ClassMethods)
13
+ base.extend ClassMethods
14
14
  end
15
15
 
16
- def wrap_resource(resource, klass, class_level_association)
16
+ def wrap_resource(resource, class_level_association)
17
17
  instance_association = Association.new(class_level_association.merge(:parent => self))
18
+ klass = class_level_association[:class]
19
+
18
20
  case resource
19
21
  when Hash
20
22
  klass.new(@client, resource.merge(:association => instance_association))
@@ -30,6 +32,11 @@ module ZendeskAPI
30
32
  module ClassMethods
31
33
  include Rescue
32
34
 
35
+ def self.extended(klass)
36
+ klass.extend Has
37
+ klass.extend HasMany
38
+ end
39
+
33
40
  def associations
34
41
  @associations ||= []
35
42
  end
@@ -44,133 +51,155 @@ module ZendeskAPI
44
51
  end
45
52
  end
46
53
 
47
- # Represents a parent-to-child association between resources. Options to pass in are: class, path.
48
- # @param [Symbol] resource_name_or_class The underlying resource name or a class to get it from
49
- # @param [Hash] class_level_options The options to pass to the method definition.
50
- def has(resource_name_or_class, class_level_options = {})
51
- if klass = class_level_options.delete(:class)
52
- resource_name = resource_name_or_class
53
- else
54
- klass = resource_name_or_class
55
- resource_name = klass.singular_resource_name
56
- end
54
+ private
57
55
 
58
- class_level_association = {
56
+ def build_association(klass, resource_name, options)
57
+ {
59
58
  :class => klass,
60
59
  :name => resource_name,
61
- :inline => class_level_options.delete(:inline),
62
- :path => class_level_options.delete(:path),
63
- :include => (class_level_options.delete(:include) || klass.resource_name).to_s,
64
- :include_key => (class_level_options.delete(:include_key) || :id).to_s,
65
- :singular => true
60
+ :inline => options.delete(:inline),
61
+ :path => options.delete(:path),
62
+ :include => (options.delete(:include) || klass.resource_name).to_s,
63
+ :include_key => (options.delete(:include_key) || :id).to_s,
64
+ :singular => options.delete(:singular)
66
65
  }
66
+ end
67
67
 
68
- associations << class_level_association
68
+ def define_used(association)
69
+ define_method "#{association[:name]}_used?" do
70
+ !!instance_variable_get("@#{association[:name]}")
71
+ end
72
+ end
69
73
 
70
- id_column = "#{resource_name}_id"
74
+ module Has
75
+ # Represents a parent-to-child association between resources. Options to pass in are: class, path.
76
+ # @param [Symbol] resource_name_or_class The underlying resource name or a class to get it from
77
+ # @param [Hash] class_level_options The options to pass to the method definition.
78
+ def has(resource_name_or_class, class_level_options = {})
79
+ if klass = class_level_options.delete(:class)
80
+ resource_name = resource_name_or_class
81
+ else
82
+ klass = resource_name_or_class
83
+ resource_name = klass.singular_resource_name
84
+ end
85
+
86
+ class_level_association = build_association(klass, resource_name, class_level_options)
87
+ class_level_association.merge!(:singular => true, :id_column => "#{resource_name}_id")
71
88
 
72
- define_method "#{resource_name}_used?" do
73
- !!instance_variable_get("@#{resource_name}")
89
+ associations << class_level_association
90
+
91
+ define_used(class_level_association)
92
+ define_has_getter(class_level_association)
93
+ define_has_setter(class_level_association)
74
94
  end
75
95
 
76
- define_method resource_name do |*args|
77
- instance_options = args.last.is_a?(Hash) ? args.pop : {}
78
-
79
- # return if cached
80
- cached = instance_variable_get("@#{resource_name}")
81
- return cached if cached && !instance_options[:reload]
82
-
83
- # find and cache association
84
- instance_association = Association.new(class_level_association.merge(:parent => self))
85
- resource = if klass.respond_to?(:find) && resource_id = method_missing(id_column)
86
- klass.find(@client, :id => resource_id, :association => instance_association)
87
- elsif found = method_missing(resource_name.to_sym)
88
- wrap_resource(found, klass, class_level_association)
89
- elsif klass.superclass == DataResource
90
- rescue_client_error do
91
- response = @client.connection.get(instance_association.generate_path(:with_parent => true))
92
- klass.new(@client, response.body[klass.singular_resource_name].merge(:association => instance_association))
96
+ private
97
+
98
+ def define_has_getter(association)
99
+ klass = association[:class] # shorthand
100
+
101
+ define_method association[:name] do |*args|
102
+ instance_options = args.last.is_a?(Hash) ? args.pop : {}
103
+
104
+ # return if cached
105
+ cached = instance_variable_get("@#{association[:name]}")
106
+ return cached if cached && !instance_options[:reload]
107
+
108
+ # find and cache association
109
+ instance_association = Association.new(association.merge(:parent => self))
110
+ resource = if klass.respond_to?(:find) && resource_id = method_missing(association[:id_column])
111
+ klass.find(@client, :id => resource_id, :association => instance_association)
112
+ elsif found = method_missing(association[:name].to_sym)
113
+ wrap_resource(found, association)
114
+ elsif klass.superclass == DataResource
115
+ rescue_client_error do
116
+ response = @client.connection.get(instance_association.generate_path(:with_parent => true))
117
+ klass.new(@client, response.body[klass.singular_resource_name].merge(:association => instance_association))
118
+ end
93
119
  end
94
- end
95
120
 
96
- send("#{id_column}=", resource.id) if resource && has_key?(id_column)
97
- instance_variable_set("@#{resource_name}", resource)
121
+ send("#{association[:id_column]}=", resource.id) if resource && has_key?(association[:id_column])
122
+ instance_variable_set("@#{association[:name]}", resource)
123
+ end
98
124
  end
99
125
 
100
- define_method "#{resource_name}=" do |resource|
101
- resource = wrap_resource(resource, klass, class_level_association)
102
- send("#{id_column}=", resource.id) if has_key?(id_column)
103
- instance_variable_set("@#{resource_name}", resource)
126
+ def define_has_setter(association)
127
+ define_method "#{association[:name]}=" do |resource|
128
+ resource = wrap_resource(resource, association)
129
+ send("#{association[:id_column]}=", resource.id) if has_key?(association[:id_column])
130
+ instance_variable_set("@#{association[:name]}", resource)
131
+ end
104
132
  end
105
133
  end
106
134
 
107
- # Represents a parent-to-children association between resources. Options to pass in are: class, path.
108
- # @param [Symbol] resource_name_or_class The underlying resource name or class to get it from
109
- # @param [Hash] class_level_options The options to pass to the method definition.
110
- def has_many(resource_name_or_class, class_level_options = {})
111
- if klass = class_level_options.delete(:class)
112
- resource_name = resource_name_or_class
113
- else
114
- klass = resource_name_or_class
115
- resource_name = klass.resource_name
116
- end
117
-
118
- class_level_association = {
119
- :class => klass,
120
- :name => resource_name,
121
- :inline => class_level_options.delete(:inline),
122
- :path => class_level_options.delete(:path),
123
- :include => (class_level_options.delete(:include) || klass.resource_name).to_s,
124
- :include_key => (class_level_options.delete(:include_key) || :id).to_s,
125
- :singular => false
126
- }
135
+ module HasMany
136
+ # Represents a parent-to-children association between resources. Options to pass in are: class, path.
137
+ # @param [Symbol] resource_name_or_class The underlying resource name or class to get it from
138
+ # @param [Hash] class_level_options The options to pass to the method definition.
139
+ def has_many(resource_name_or_class, class_level_options = {})
140
+ if klass = class_level_options.delete(:class)
141
+ resource_name = resource_name_or_class
142
+ else
143
+ klass = resource_name_or_class
144
+ resource_name = klass.resource_name
145
+ end
127
146
 
128
- associations << class_level_association
147
+ class_level_association = build_association(klass, resource_name, class_level_options)
148
+ class_level_association.merge!(:singular => false, :id_column => "#{resource_name}_ids")
129
149
 
130
- id_column = "#{resource_name}_ids"
150
+ associations << class_level_association
131
151
 
132
- define_method "#{resource_name}_used?" do
133
- !!instance_variable_get("@#{resource_name}")
152
+ define_used(class_level_association)
153
+ define_has_many_getter(class_level_association)
154
+ define_has_many_setter(class_level_association)
134
155
  end
135
156
 
136
- define_method resource_name do |*args|
137
- instance_opts = args.last.is_a?(Hash) ? args.pop : {}
157
+ private
158
+
159
+ def define_has_many_getter(association)
160
+ klass = association[:class]
161
+
162
+ define_method association[:name] do |*args|
163
+ instance_opts = args.last.is_a?(Hash) ? args.pop : {}
138
164
 
139
- # return if cached
140
- cached = instance_variable_get("@#{resource_name}")
141
- return cached if cached && !instance_opts[:reload]
165
+ # return if cached
166
+ cached = instance_variable_get("@#{association[:name]}")
167
+ return cached if cached && !instance_opts[:reload]
142
168
 
143
- # find and cache association
144
- instance_association = Association.new(class_level_association.merge(:parent => self))
145
- singular_resource_name = Inflection.singular(resource_name.to_s)
169
+ # find and cache association
170
+ instance_association = Association.new(association.merge(:parent => self))
171
+ singular_resource_name = Inflection.singular(association[:name].to_s)
146
172
 
147
- resources = if (ids = method_missing("#{singular_resource_name}_ids")) && ids.any?
148
- ids.map do |id|
149
- klass.find(@client, :id => id, :association => instance_association)
150
- end.compact
151
- elsif (resources = method_missing(resource_name.to_sym)) && resources.any?
152
- resources.map do |res|
153
- klass.new(@client, res.merge(:association => instance_association))
173
+ resources = if (ids = method_missing("#{singular_resource_name}_ids")) && ids.any?
174
+ ids.map do |id|
175
+ klass.find(@client, :id => id, :association => instance_association)
176
+ end.compact
177
+ elsif (resources = method_missing(association[:name].to_sym)) && resources.any?
178
+ resources.map do |res|
179
+ klass.new(@client, res.merge(:association => instance_association))
180
+ end
181
+ else
182
+ ZendeskAPI::Collection.new(@client, klass, instance_opts.merge(:association => instance_association))
154
183
  end
155
- else
156
- ZendeskAPI::Collection.new(@client, klass, instance_opts.merge(:association => instance_association))
157
- end
158
184
 
159
- send("#{id_column}=", resources.map(&:id)) if resource && has_key?(id_column)
160
- instance_variable_set("@#{resource_name}", resources)
185
+ send("#{association[:id_column]}=", resources.map(&:id)) if resource && has_key?(association[:id_column])
186
+ instance_variable_set("@#{association[:name]}", resources)
187
+ end
161
188
  end
162
189
 
163
- define_method "#{resource_name}=" do |resources|
164
- if resources.is_a?(Array)
165
- resources.map! { |attr| wrap_resource(attr, klass, class_level_association) }
166
- send(resource_name).replace(resources)
167
- else
168
- resources.association = instance_association
169
- instance_variable_set("@#{resource_name}", resources)
170
- end
190
+ def define_has_many_setter(association)
191
+ define_method "#{association[:name]}=" do |resources|
192
+ if resources.is_a?(Array)
193
+ resources.map! { |attr| wrap_resource(attr, association) }
194
+ send(association[:name]).replace(resources)
195
+ else
196
+ resources.association = Association.new(association.merge(:parent => self))
197
+ instance_variable_set("@#{association[:name]}", resources)
198
+ end
171
199
 
172
- send("#{id_column}=", resources.map(&:id)) if resources && has_key?(id_column)
173
- resource
200
+ send("#{association[:id_column]}=", resources.map(&:id)) if resources && has_key?(association[:id_column])
201
+ resource
202
+ end
174
203
  end
175
204
  end
176
205
  end
@@ -78,34 +78,16 @@ module ZendeskAPI
78
78
  @config = ZendeskAPI::Configuration.new
79
79
  yield config
80
80
 
81
- if !config.allow_http && config.url !~ /^https/
82
- raise ArgumentError, "zendesk_api is ssl only; url must begin with https://"
83
- end
84
-
85
- config.retry = !!config.retry # nil -> false
86
-
87
- if config.token && !config.password
88
- config.password = config.token
89
- config.username += "/token" unless config.username.end_with?("/token")
90
- end
91
-
92
- if config.logger.nil? || config.logger == true
93
- require 'logger'
94
- config.logger = Logger.new($stderr)
95
- config.logger.level = Logger::WARN
96
- end
97
-
98
81
  @callbacks = []
99
-
100
82
  @resource_cache = {}
101
83
 
102
- if logger = config.logger
103
- insert_callback do |env|
104
- if warning = env[:response_headers]["X-Zendesk-API-Warn"]
105
- logger.warn "WARNING: #{warning}"
106
- end
107
- end
108
- end
84
+ check_url
85
+
86
+ config.retry = !!config.retry # nil -> false
87
+
88
+ set_token_auth
89
+ set_default_logger
90
+ add_warning_callback
109
91
  end
110
92
 
111
93
  # Creates a connection if there is none, otherwise returns the existing connection.
@@ -162,5 +144,42 @@ module ZendeskAPI
162
144
  builder.adapter *config.adapter || Faraday.default_adapter
163
145
  end
164
146
  end
147
+
148
+ private
149
+
150
+ def check_url
151
+ if !config.allow_http && config.url !~ /^https/
152
+ raise ArgumentError, "zendesk_api is ssl only; url must begin with https://"
153
+ end
154
+
155
+ if config.url !~ %r{api/v2}
156
+ warn "this gem doesn't support the v1 api"
157
+ end
158
+ end
159
+
160
+ def set_token_auth
161
+ if config.token && !config.password
162
+ config.password = config.token
163
+ config.username += "/token" unless config.username.end_with?("/token")
164
+ end
165
+ end
166
+
167
+ def set_default_logger
168
+ if config.logger.nil? || config.logger == true
169
+ require 'logger'
170
+ config.logger = Logger.new($stderr)
171
+ config.logger.level = Logger::WARN
172
+ end
173
+ end
174
+
175
+ def add_warning_callback
176
+ return unless logger = config.logger
177
+
178
+ insert_callback do |env|
179
+ if warning = env[:response_headers]["X-Zendesk-API-Warn"]
180
+ logger.warn "WARNING: #{warning}"
181
+ end
182
+ end
183
+ end
165
184
  end
166
185
  end
@@ -27,32 +27,21 @@ module ZendeskAPI
27
27
  # @param [String] resource The resource being collected.
28
28
  # @param [Hash] options Any additional options to be passed in.
29
29
  def initialize(client, resource, options = {})
30
- @client, @resource = client, resource.resource_name
30
+ @client, @resource_class, @resource = client, resource, resource.resource_name
31
31
  @options = Hashie::Mash.new(options)
32
32
 
33
- @verb = @options.delete(:verb)
34
- @collection_path = @options.delete(:collection_path)
35
-
36
- association_options = { :path => @options.delete(:path) }
37
- association_options[:path] ||= @collection_path.join("/") if @collection_path
38
- @association = @options.delete(:association) || Association.new(association_options.merge(:class => resource))
33
+ set_association_from_options
34
+ join_special_params
39
35
 
40
- # some params use comma-joined strings instead of query-based arrays for multiple values
41
- @options.each do |k, v|
42
- if SPECIALLY_JOINED_PARAMS.include?(k.to_sym) && v.is_a?(Array)
43
- @options[k] = v.join(',')
44
- end
45
- end
46
-
47
- @collection_path ||= [@resource]
48
- @resource_class = resource
49
- @fetchable = true
36
+ @verb = @options.delete(:verb)
50
37
  @includes = Array(@options.delete(:include))
51
38
 
52
39
  # Used for Attachments, TicketComment
53
40
  if @resource_class.is_a?(Class) && @resource_class.superclass == ZendeskAPI::Data
54
41
  @resources = []
55
42
  @fetchable = false
43
+ else
44
+ @fetchable = true
56
45
  end
57
46
  end
58
47
 
@@ -158,39 +147,16 @@ module ZendeskAPI
158
147
  # Executes actual GET from API and loads resources into proper class.
159
148
  # @param [Boolean] reload Whether to disregard cache
160
149
  def fetch(reload = false)
161
- return @resources if @resources && (!@fetchable || !reload)
162
-
163
- if association && association.options.parent && association.options.parent.new_record?
150
+ if @resources && (!@fetchable || !reload)
151
+ return @resources
152
+ elsif association && association.options.parent && association.options.parent.new_record?
164
153
  return @resources = []
165
154
  end
166
155
 
167
- if @query
168
- path = @query
169
- @query = nil
170
- else
171
- path = self.path
172
- end
173
-
174
- @response = @client.connection.send(@verb || "get", path) do |req|
175
- opts = @options.delete_if {|k, v| v.nil?}
176
-
177
- req.params.merge!(:include => @includes.join(",")) if @includes.any?
178
-
179
- if %w{put post}.include?(@verb.to_s)
180
- req.body = opts
181
- else
182
- req.params.merge!(opts)
183
- end
184
- end
185
-
186
- body = @response.body.dup
187
-
188
- results = body.delete(@resource_class.model_key) || body.delete("results")
189
- @resources = results.map {|res| @resource_class.new(@client, res)}
190
-
191
- set_page_and_count(body)
192
- set_includes(@resources, @includes, body)
156
+ @response = get_response(@query || self.path)
157
+ handle_response(@response.body.dup)
193
158
 
159
+ @query = nil
194
160
  @resources
195
161
  end
196
162
 
@@ -238,8 +204,7 @@ module ZendeskAPI
238
204
  if @options["page"]
239
205
  clear_cache
240
206
  @options["page"] += 1
241
- elsif @next_page
242
- @query = @next_page
207
+ elsif @query = @next_page
243
208
  fetch(true)
244
209
  else
245
210
  clear_cache
@@ -255,8 +220,7 @@ module ZendeskAPI
255
220
  if @options["page"] && @options["page"] > 1
256
221
  clear_cache
257
222
  @options["page"] -= 1
258
- elsif @prev_page
259
- @query = @prev_page
223
+ elsif @query = @prev_page
260
224
  fetch(true)
261
225
  else
262
226
  clear_cache
@@ -277,16 +241,12 @@ module ZendeskAPI
277
241
 
278
242
  # Sends methods to underlying array of resources.
279
243
  def method_missing(name, *args, &block)
280
- methods = @resource_class.singleton_methods(false).map(&:to_sym)
281
-
282
- if methods.include?(name)
283
- @resource_class.send(name, @client, *args, &block)
244
+ if resource_methods.include?(name)
245
+ collection_method(name, *args, &block)
284
246
  elsif Array.new.respond_to?(name)
285
- to_a.send(name, *args, &block)
247
+ array_method(name, *args, &block)
286
248
  else
287
- opts = args.last.is_a?(Hash) ? args.last : {}
288
- opts.merge!(:collection_path => @collection_path.dup.push(name))
289
- self.class.new(@client, @resource_class, @options.merge(opts))
249
+ next_collection(name, *args, &block)
290
250
  end
291
251
  end
292
252
 
@@ -316,5 +276,70 @@ module ZendeskAPI
316
276
  @options["page"] = $1.to_i + 1
317
277
  end
318
278
  end
279
+
280
+ ## Initialize
281
+
282
+ def join_special_params
283
+ # some params use comma-joined strings instead of query-based arrays for multiple values
284
+ @options.each do |k, v|
285
+ if SPECIALLY_JOINED_PARAMS.include?(k.to_sym) && v.is_a?(Array)
286
+ @options[k] = v.join(',')
287
+ end
288
+ end
289
+ end
290
+
291
+ def set_association_from_options
292
+ @collection_path = @options.delete(:collection_path)
293
+
294
+ association_options = { :path => @options.delete(:path) }
295
+ association_options[:path] ||= @collection_path.join("/") if @collection_path
296
+ @association = @options.delete(:association) || Association.new(association_options.merge(:class => @resource_class))
297
+
298
+ @collection_path ||= [@resource]
299
+ end
300
+
301
+ ## Fetch
302
+
303
+ def get_response(path)
304
+ @response = @client.connection.send(@verb || "get", path) do |req|
305
+ opts = @options.delete_if {|_, v| v.nil?}
306
+
307
+ req.params.merge!(:include => @includes.join(",")) if @includes.any?
308
+
309
+ if %w{put post}.include?(@verb.to_s)
310
+ req.body = opts
311
+ else
312
+ req.params.merge!(opts)
313
+ end
314
+ end
315
+ end
316
+
317
+ def handle_response(body)
318
+ results = body.delete(@resource_class.model_key) || body.delete("results")
319
+ @resources = results.map {|res| @resource_class.new(@client, res)}
320
+
321
+ set_page_and_count(body)
322
+ set_includes(@resources, @includes, body)
323
+ end
324
+
325
+ ## Method missing
326
+
327
+ def array_method(name, *args, &block)
328
+ to_a.send(name, *args, &block)
329
+ end
330
+
331
+ def next_collection(name, *args, &block)
332
+ opts = args.last.is_a?(Hash) ? args.last : {}
333
+ opts.merge!(:collection_path => @collection_path.dup.push(name))
334
+ self.class.new(@client, @resource_class, @options.merge(opts))
335
+ end
336
+
337
+ def collection_method(name, *args, &block)
338
+ @resource_class.send(name, @client, *args, &block)
339
+ end
340
+
341
+ def resource_methods
342
+ @resource_methods ||= @resource_class.singleton_methods(false).map(&:to_sym)
343
+ end
319
344
  end
320
345
  end