zendesk_api 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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