discourse_zendesk_api 1.0.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 (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +176 -0
  3. data/lib/zendesk_api/actions.rb +334 -0
  4. data/lib/zendesk_api/association.rb +195 -0
  5. data/lib/zendesk_api/associations.rb +212 -0
  6. data/lib/zendesk_api/client.rb +243 -0
  7. data/lib/zendesk_api/collection.rb +474 -0
  8. data/lib/zendesk_api/configuration.rb +79 -0
  9. data/lib/zendesk_api/core_ext/inflection.rb +3 -0
  10. data/lib/zendesk_api/delegator.rb +5 -0
  11. data/lib/zendesk_api/error.rb +49 -0
  12. data/lib/zendesk_api/helpers.rb +24 -0
  13. data/lib/zendesk_api/lru_cache.rb +39 -0
  14. data/lib/zendesk_api/middleware/request/encode_json.rb +26 -0
  15. data/lib/zendesk_api/middleware/request/etag_cache.rb +52 -0
  16. data/lib/zendesk_api/middleware/request/raise_rate_limited.rb +31 -0
  17. data/lib/zendesk_api/middleware/request/retry.rb +59 -0
  18. data/lib/zendesk_api/middleware/request/upload.rb +86 -0
  19. data/lib/zendesk_api/middleware/request/url_based_access_token.rb +26 -0
  20. data/lib/zendesk_api/middleware/response/callback.rb +21 -0
  21. data/lib/zendesk_api/middleware/response/deflate.rb +17 -0
  22. data/lib/zendesk_api/middleware/response/gzip.rb +19 -0
  23. data/lib/zendesk_api/middleware/response/logger.rb +44 -0
  24. data/lib/zendesk_api/middleware/response/parse_iso_dates.rb +30 -0
  25. data/lib/zendesk_api/middleware/response/parse_json.rb +23 -0
  26. data/lib/zendesk_api/middleware/response/raise_error.rb +26 -0
  27. data/lib/zendesk_api/middleware/response/sanitize_response.rb +11 -0
  28. data/lib/zendesk_api/resource.rb +208 -0
  29. data/lib/zendesk_api/resources.rb +971 -0
  30. data/lib/zendesk_api/sideloading.rb +58 -0
  31. data/lib/zendesk_api/silent_mash.rb +8 -0
  32. data/lib/zendesk_api/track_changes.rb +85 -0
  33. data/lib/zendesk_api/trackie.rb +13 -0
  34. data/lib/zendesk_api/verbs.rb +65 -0
  35. data/lib/zendesk_api/version.rb +3 -0
  36. data/lib/zendesk_api.rb +4 -0
  37. data/util/resource_handler.rb +74 -0
  38. data/util/verb_handler.rb +16 -0
  39. metadata +166 -0
@@ -0,0 +1,971 @@
1
+ module ZendeskAPI
2
+ # @internal The following are redefined later, but needed by some circular resources (e.g. Ticket -> User, User -> Ticket)
3
+
4
+ class Ticket < Resource; end
5
+ class User < Resource; end
6
+ class UserRelated < DataResource; end
7
+ class Category < Resource; end
8
+ class OrganizationMembership < ReadResource; end
9
+ class OrganizationSubscription < ReadResource; end
10
+
11
+ # @internal Begin actual Resource definitions
12
+
13
+ class RecipientAddress < Resource; end
14
+
15
+ class Locale < ReadResource; end
16
+
17
+ class CustomRole < DataResource; end
18
+
19
+ class Role < DataResource
20
+ def to_param
21
+ name
22
+ end
23
+ end
24
+
25
+ class Topic < Resource
26
+ class << self
27
+ def resource_path
28
+ "community/topics"
29
+ end
30
+ end
31
+ end
32
+
33
+ class Bookmark < Resource; end
34
+ class Ability < DataResource; end
35
+ class Group < Resource; end
36
+ class SharingAgreement < ReadResource; end
37
+ class JobStatus < ReadResource; end
38
+
39
+ class Session < ReadResource
40
+ include Destroy
41
+ end
42
+
43
+ class Tag < DataResource
44
+ include Update
45
+ include Destroy
46
+
47
+ alias :name :id
48
+ alias :to_param :id
49
+
50
+ def path(opts = {})
51
+ raise "tags must have parent resource" unless association.options.parent
52
+ super(opts.merge(:with_parent => true, :with_id => false))
53
+ end
54
+
55
+ def changed?
56
+ true
57
+ end
58
+
59
+ def destroy!
60
+ super do |req|
61
+ req.body = attributes_for_save
62
+ end
63
+ end
64
+
65
+ module Update
66
+ def _save(method = :save)
67
+ return self unless @resources
68
+
69
+ @client.connection.post(path) do |req|
70
+ req.body = { :tags => @resources.reject(&:destroyed?).map(&:id) }
71
+ end
72
+
73
+ true
74
+ rescue Faraday::ClientError => e
75
+ if method == :save
76
+ false
77
+ else
78
+ raise e
79
+ end
80
+ end
81
+ end
82
+
83
+ def attributes_for_save
84
+ { self.class.resource_name => [id] }
85
+ end
86
+ end
87
+
88
+ class Attachment < ReadResource
89
+ def initialize(client, attributes = {})
90
+ attributes[:file] ||= attributes.delete(:id)
91
+
92
+ super
93
+ end
94
+
95
+ def save
96
+ upload = Upload.create!(@client, attributes)
97
+ self.token = upload.token
98
+ end
99
+
100
+ def to_param
101
+ token
102
+ end
103
+ end
104
+
105
+ class Upload < Data
106
+ include Create
107
+ include Destroy
108
+
109
+ def id
110
+ token
111
+ end
112
+
113
+ has_many Attachment
114
+
115
+ private
116
+
117
+ def attributes_for_save
118
+ attributes.changes
119
+ end
120
+ end
121
+
122
+ class MobileDevice < Resource
123
+ # Clears this devices' badge
124
+ put :clear_badge
125
+ end
126
+
127
+ class OrganizationRelated < DataResource; end
128
+
129
+ class Organization < Resource
130
+ extend CreateMany
131
+ extend CreateOrUpdate
132
+ extend DestroyMany
133
+
134
+ has Ability, :inline => true
135
+ has Group
136
+ has :related, :class => OrganizationRelated
137
+
138
+ has_many Ticket
139
+ has_many User
140
+ has_many Tag, :extend => Tag::Update, :inline => :create
141
+ has_many OrganizationMembership
142
+ has_many :subscriptions, class: OrganizationSubscription
143
+
144
+ # Gets a incremental export of organizations from the start_time until now.
145
+ # @param [Client] client The {Client} object to be used
146
+ # @param [Integer] start_time The start_time parameter
147
+ # @return [Collection] Collection of {Organization}
148
+ def self.incremental_export(client, start_time)
149
+ ZendeskAPI::Collection.new(client, self, :path => "incremental/organizations?start_time=#{start_time.to_i}")
150
+ end
151
+ end
152
+
153
+ class Brand < Resource
154
+ def destroy!
155
+ self.active = false
156
+ save!
157
+
158
+ super
159
+ end
160
+ end
161
+
162
+ class OrganizationMembership < ReadResource
163
+ include Create
164
+ include Destroy
165
+
166
+ extend CreateMany
167
+ extend DestroyMany
168
+
169
+ has User
170
+ has Organization
171
+ end
172
+
173
+ class OrganizationSubscription < ReadResource
174
+ include Create
175
+ include Destroy
176
+
177
+ has User
178
+ has Organization
179
+ end
180
+
181
+ class Category < Resource
182
+ class << self
183
+ def resource_path
184
+ "help_center/categories"
185
+ end
186
+ end
187
+
188
+ class Section < Resource
189
+ end
190
+
191
+ has_many Section
192
+ end
193
+
194
+ class Section < ReadResource
195
+ class << self
196
+ def resource_path
197
+ "help_center/sections"
198
+ end
199
+ end
200
+
201
+ has Category
202
+
203
+ class Article < Resource
204
+ end
205
+
206
+ has_many Article
207
+ end
208
+
209
+ class Article < ReadResource
210
+ class << self
211
+ def resource_path
212
+ "help_center/articles"
213
+ end
214
+ end
215
+ end
216
+
217
+ class TopicSubscription < Resource
218
+ class << self
219
+ def model_key
220
+ "subscriptions"
221
+ end
222
+ end
223
+
224
+ has Topic
225
+ has User
226
+
227
+ def path(options = {})
228
+ super(options.merge(:with_parent => true))
229
+ end
230
+ end
231
+
232
+ class Topic < Resource
233
+ has_many :subscriptions, :class => TopicSubscription, :inline => true
234
+ has_many Tag, :extend => Tag::Update, :inline => :create
235
+ has_many Attachment
236
+ has_many :uploads, :class => Attachment, :inline => true
237
+ end
238
+
239
+ class Activity < Resource
240
+ has User
241
+ has :actor, :class => User
242
+ end
243
+
244
+ class Setting < UpdateResource
245
+ attr_reader :on
246
+
247
+ def initialize(client, attributes = {})
248
+ # Try and find the root key
249
+ @on = (attributes.keys.map(&:to_s) - %w{association options}).first
250
+
251
+ # Make what's inside that key the root attributes
252
+ attributes.merge!(attributes.delete(@on))
253
+
254
+ super
255
+ end
256
+
257
+ def new_record?
258
+ false
259
+ end
260
+
261
+ def path(options = {})
262
+ super(options.merge(:with_parent => true))
263
+ end
264
+
265
+ def attributes_for_save
266
+ { self.class.resource_name => { @on => attributes.changes } }
267
+ end
268
+ end
269
+
270
+ class SatisfactionRating < ReadResource
271
+ has :assignee, :class => User
272
+ has :requester, :class => User
273
+ has Ticket
274
+ has Group
275
+ end
276
+
277
+ class Search
278
+ class Result < Data; end
279
+
280
+ # Creates a search collection
281
+ def self.search(client, options = {})
282
+ unless (%w{query external_id} & options.keys.map(&:to_s)).any?
283
+ warn "you have not specified a query for this search"
284
+ end
285
+
286
+ ZendeskAPI::Collection.new(client, self, options)
287
+ end
288
+
289
+ # Quack like a Resource
290
+ # Creates the correct resource class from the result_type passed in
291
+ def self.new(client, attributes)
292
+ result_type = attributes["result_type"]
293
+
294
+ if result_type
295
+ result_type = ZendeskAPI::Helpers.modulize_string(result_type)
296
+ klass = ZendeskAPI.const_get(result_type) rescue nil
297
+ end
298
+
299
+ (klass || Result).new(client, attributes)
300
+ end
301
+
302
+ class << self
303
+ def resource_name
304
+ "search"
305
+ end
306
+
307
+ alias :resource_path :resource_name
308
+
309
+ def model_key
310
+ "results"
311
+ end
312
+ end
313
+ end
314
+
315
+ class Request < Resource
316
+ class Comment < DataResource
317
+ include Save
318
+
319
+ has_many :uploads, :class => Attachment, :inline => true
320
+ has :author, :class => User
321
+
322
+ def save
323
+ if new_record?
324
+ save_associations
325
+ true
326
+ else
327
+ false
328
+ end
329
+ end
330
+
331
+ alias :save! :save
332
+ end
333
+
334
+ has Comment, :inline => true
335
+ has_many Comment
336
+
337
+ has Organization
338
+ has Group
339
+ has :requester, :class => User
340
+ end
341
+
342
+ class AnonymousRequest < CreateResource
343
+ def self.singular_resource_name
344
+ 'request'
345
+ end
346
+
347
+ namespace 'portal'
348
+ end
349
+
350
+ class TicketField < Resource; end
351
+
352
+ class TicketMetric < DataResource
353
+ include Read
354
+ end
355
+
356
+ class TicketRelated < DataResource; end
357
+
358
+ class TicketEvent < DataResource
359
+ class Event < Data; end
360
+
361
+ has_many :child_events, :class => Event
362
+ has Ticket
363
+ has :updater, :class => User
364
+
365
+ # Gets a incremental export of ticket events from the start_time until now.
366
+ # @param [Client] client The {Client} object to be used
367
+ # @param [Integer] start_time The start_time parameter
368
+ # @return [Collection] Collection of {TicketEvent}
369
+ def self.incremental_export(client, start_time)
370
+ ZendeskAPI::Collection.new(client, self, :path => "incremental/ticket_events?start_time=#{start_time.to_i}")
371
+ end
372
+ end
373
+
374
+ class Ticket < Resource
375
+ extend CreateMany
376
+ extend UpdateMany
377
+ extend DestroyMany
378
+
379
+ class Audit < DataResource
380
+ class Event < Data
381
+ has :author, :class => User
382
+ end
383
+
384
+ put :trust
385
+
386
+ # need this to support SideLoading
387
+ has :author, :class => User
388
+
389
+ has_many Event
390
+ end
391
+
392
+ class Comment < DataResource
393
+ include Save
394
+
395
+ has_many :uploads, :class => Attachment, :inline => true
396
+ has :author, :class => User
397
+
398
+ def save
399
+ if new_record?
400
+ save_associations
401
+ true
402
+ else
403
+ false
404
+ end
405
+ end
406
+
407
+ alias :save! :save
408
+ end
409
+
410
+ class SatisfactionRating < CreateResource
411
+ class << self
412
+ alias :resource_name :singular_resource_name
413
+ end
414
+ end
415
+
416
+ put :mark_as_spam
417
+ post :merge
418
+
419
+ has :requester, :class => User, :inline => :create
420
+ has :submitter, :class => User
421
+ has :assignee, :class => User
422
+
423
+ has_many :collaborators, :class => User, :inline => true, :extend => (Module.new do
424
+ def to_param
425
+ map(&:id)
426
+ end
427
+ end)
428
+
429
+ has_many Audit
430
+ has :metrics, :class => TicketMetric
431
+ has Group
432
+ has Organization
433
+ has Brand
434
+ has :related, :class => TicketRelated
435
+
436
+ has Comment, :inline => true
437
+ has_many Comment
438
+
439
+ has :last_comment, :class => Comment, :inline => true
440
+ has_many :last_comments, :class => Comment, :inline => true
441
+
442
+ has_many Tag, :extend => Tag::Update, :inline => :create
443
+
444
+ has_many :incidents, :class => Ticket
445
+
446
+ # Gets a incremental export of tickets from the start_time until now.
447
+ # @param [Client] client The {Client} object to be used
448
+ # @param [Integer] start_time The start_time parameter
449
+ # @return [Collection] Collection of {Ticket}
450
+ def self.incremental_export(client, start_time)
451
+ ZendeskAPI::Collection.new(client, self, :path => "incremental/tickets?start_time=#{start_time.to_i}")
452
+ end
453
+
454
+ # Imports a ticket through the imports/tickets endpoint using save!
455
+ # @param [Client] client The {Client} object to be used
456
+ # @param [Hash] attributes The attributes to create.
457
+ # @return [Ticket] Created object or nil
458
+ def self.import!(client, attributes)
459
+ new(client, attributes).tap do |ticket|
460
+ ticket.save!(:path => "imports/tickets")
461
+ end
462
+ end
463
+
464
+ # Imports a ticket through the imports/tickets endpoint
465
+ # @param [Client] client The {Client} object to be used
466
+ # @param [Hash] attributes The attributes to create.
467
+ # @return [Ticket] Created object or nil
468
+ def self.import(client, attributes)
469
+ ticket = new(client, attributes)
470
+ return unless ticket.save(:path => "imports/tickets")
471
+ ticket
472
+ end
473
+ end
474
+
475
+ class SuspendedTicket < ReadResource
476
+ include Destroy
477
+
478
+ # Recovers this suspended ticket to an actual ticket
479
+ put :recover
480
+ end
481
+
482
+ class DeletedTicket < ReadResource
483
+ include Destroy
484
+ extend DestroyMany
485
+
486
+ # Restores this previously deleted ticket to an actual ticket
487
+ put :restore
488
+ put :restore_many
489
+ end
490
+
491
+ class UserViewRow < DataResource
492
+ has User
493
+ def self.model_key
494
+ "rows"
495
+ end
496
+ end
497
+
498
+ class ViewRow < DataResource
499
+ has Ticket
500
+
501
+ # @internal Optional columns
502
+
503
+ has Group
504
+ has :assignee, :class => User
505
+ has :requester, :class => User
506
+ has :submitter, :class => User
507
+ has Organization
508
+
509
+ def self.model_key
510
+ "rows"
511
+ end
512
+ end
513
+
514
+ class RuleExecution < Data
515
+ has_many :custom_fields, :class => TicketField
516
+ end
517
+
518
+ class ViewCount < DataResource; end
519
+
520
+ class Rule < Resource
521
+ private
522
+
523
+ def attributes_for_save
524
+ to_save = [:conditions, :actions, :output].inject({}) { |h, k| h.merge(k => send(k)) }
525
+ { self.class.singular_resource_name.to_sym => attributes.changes.merge(to_save) }
526
+ end
527
+ end
528
+
529
+ class TriggerCategory < Resource; end
530
+
531
+ module Conditions
532
+ def all_conditions=(all_conditions)
533
+ self.conditions ||= {}
534
+ self.conditions[:all] = all_conditions
535
+ end
536
+
537
+ def any_conditions=(any_conditions)
538
+ self.conditions ||= {}
539
+ self.conditions[:any] = any_conditions
540
+ end
541
+
542
+ def add_all_condition(field, operator, value)
543
+ self.conditions ||= {}
544
+ self.conditions[:all] ||= []
545
+ self.conditions[:all] << { :field => field, :operator => operator, :value => value }
546
+ end
547
+
548
+ def add_any_condition(field, operator, value)
549
+ self.conditions ||= {}
550
+ self.conditions[:any] ||= []
551
+ self.conditions[:any] << { :field => field, :operator => operator, :value => value }
552
+ end
553
+ end
554
+
555
+ module Actions
556
+ def add_action(field, value)
557
+ self.actions ||= []
558
+ self.actions << { :field => field, :value => value }
559
+ end
560
+ end
561
+
562
+ class View < Rule
563
+ include Conditions
564
+
565
+ has_many :tickets, :class => Ticket
566
+ has_many :feed, :class => Ticket, :path => "feed"
567
+
568
+ has_many :rows, :class => ViewRow, :path => "execute"
569
+ has :execution, :class => RuleExecution
570
+ has ViewCount, :path => "count"
571
+
572
+ def add_column(column)
573
+ columns = execution.columns.map(&:id)
574
+ columns << column
575
+ self.columns = columns
576
+ end
577
+
578
+ def columns=(columns)
579
+ self.output ||= {}
580
+ self.output[:columns] = columns
581
+ end
582
+
583
+ def self.preview(client, options = {})
584
+ Collection.new(client, ViewRow, options.merge(:path => "views/preview", :verb => :post))
585
+ end
586
+ end
587
+
588
+ class Trigger < Rule
589
+ include Conditions
590
+ include Actions
591
+
592
+ has :execution, :class => RuleExecution
593
+ end
594
+
595
+ class Automation < Rule
596
+ include Conditions
597
+ include Actions
598
+
599
+ has :execution, :class => RuleExecution
600
+ end
601
+
602
+ class Macro < Rule
603
+ include Actions
604
+
605
+ has :execution, :class => RuleExecution
606
+
607
+ # Returns the update to a ticket that happens when a macro will be applied.
608
+ # @param [Ticket] ticket Optional {Ticket} to apply this macro to.
609
+ # @raise [Faraday::ClientError] Raised for any non-200 response.
610
+ def apply!(ticket = nil)
611
+ path = "#{self.path}/apply"
612
+
613
+ if ticket
614
+ path = "#{ticket.path}/#{path}"
615
+ end
616
+
617
+ response = @client.connection.get(path)
618
+ SilentMash.new(response.body.fetch("result", {}))
619
+ end
620
+
621
+ # Returns the update to a ticket that happens when a macro will be applied.
622
+ # @param [Ticket] ticket Optional {Ticket} to apply this macro to
623
+ def apply(ticket = nil)
624
+ apply!(ticket)
625
+ rescue Faraday::ClientError
626
+ SilentMash.new
627
+ end
628
+ end
629
+
630
+ class UserView < Rule
631
+ def self.preview(client, options = {})
632
+ Collection.new(client, UserViewRow, options.merge!(:path => "user_views/preview", :verb => :post))
633
+ end
634
+ end
635
+
636
+ class GroupMembership < Resource
637
+ extend CreateMany
638
+ extend DestroyMany
639
+
640
+ has User
641
+ has Group
642
+ end
643
+
644
+ class User < Resource
645
+ extend CreateMany
646
+ extend UpdateMany
647
+ extend CreateOrUpdate
648
+ extend CreateOrUpdateMany
649
+ extend DestroyMany
650
+
651
+ class GroupMembership < Resource
652
+ put :make_default
653
+ end
654
+
655
+ class Identity < Resource
656
+ # Makes this identity the primary one bumping all other identities down one
657
+ put :make_primary
658
+
659
+ # Verifies this identity
660
+ put :verify
661
+
662
+ # Requests verification for this identity
663
+ put :request_verification
664
+ end
665
+
666
+ any :password
667
+
668
+ # Set a user's password
669
+ def set_password(opts = {})
670
+ password(opts.merge(:verb => :post))
671
+ end
672
+
673
+ # Change a user's password
674
+ def change_password(opts = {})
675
+ password(opts.merge(:verb => :put))
676
+ end
677
+
678
+ # Set a user's password
679
+ def set_password!(opts = {})
680
+ password!(opts.merge(:verb => :post))
681
+ end
682
+
683
+ # Change a user's password
684
+ def change_password!(opts = {})
685
+ password!(opts.merge(:verb => :put))
686
+ end
687
+
688
+ # Gets a incremental export of users from the start_time until now.
689
+ # @param [Client] client The {Client} object to be used
690
+ # @param [Integer] start_time The start_time parameter
691
+ # @return [Collection] Collection of {User}
692
+ def self.incremental_export(client, start_time)
693
+ ZendeskAPI::Collection.new(client, self, :path => "incremental/users?start_time=#{start_time.to_i}")
694
+ end
695
+
696
+ has Organization
697
+
698
+ class Session < Resource
699
+ end
700
+
701
+ class CurrentSession < SingularResource
702
+ class << self
703
+ def singular_resource_name
704
+ 'session'
705
+ end
706
+
707
+ alias :resource_name :singular_resource_name
708
+ end
709
+ end
710
+
711
+ has_many Session
712
+
713
+ def current_session
714
+ ZendeskAPI::User::CurrentSession.find(@client, :user_id => 'me')
715
+ end
716
+
717
+ delete :logout
718
+
719
+ def clear_sessions!
720
+ @client.connection.delete(path + '/sessions')
721
+ end
722
+
723
+ def clear_sessions
724
+ clear_sessions!
725
+ rescue ZendeskAPI::Error::ClientError
726
+ false
727
+ end
728
+
729
+ put :merge
730
+
731
+ has CustomRole, :inline => true, :include => :roles
732
+ has Role, :inline => true, :include_key => :name
733
+ has Ability, :inline => true
734
+ has :related, :class => UserRelated
735
+
736
+ has_many Identity
737
+
738
+ has_many Request
739
+ has_many :requested_tickets, :class => Ticket, :path => 'tickets/requested'
740
+ has_many :assigned_tickets, :class => Ticket, :path => 'tickets/assigned'
741
+ has_many :ccd_tickets, :class => Ticket, :path => 'tickets/ccd'
742
+
743
+ has_many Group
744
+ has_many GroupMembership
745
+ has_many OrganizationMembership
746
+ has_many OrganizationSubscription
747
+
748
+ has_many Setting
749
+ has_many Tag, :extend => Tag::Update, :inline => :create
750
+
751
+ def attributes_for_save
752
+ # Don't send role_id, it's necessary
753
+ # for side-loading, but causes problems on save
754
+ # see #initialize
755
+ attrs = attributes.changes.delete_if do |k, _|
756
+ k == "role_id"
757
+ end
758
+
759
+ { self.class.singular_resource_name => attrs }
760
+ end
761
+
762
+ def handle_response(*)
763
+ super
764
+
765
+ # Needed for proper Role sideloading
766
+ self.role_id = role.name if key?(:role)
767
+ end
768
+ end
769
+
770
+ class DeletedUser < ReadResource
771
+ include Destroy
772
+ end
773
+
774
+ class UserField < Resource; end
775
+ class OrganizationField < Resource; end
776
+
777
+ class OauthClient < Resource
778
+ namespace "oauth"
779
+
780
+ def self.singular_resource_name
781
+ "client"
782
+ end
783
+ end
784
+
785
+ class OauthToken < ReadResource
786
+ include Destroy
787
+ namespace "oauth"
788
+
789
+ def self.singular_resource_name
790
+ "token"
791
+ end
792
+ end
793
+
794
+ class Target < Resource; end
795
+
796
+ module Voice
797
+ include DataNamespace
798
+
799
+ class PhoneNumber < Resource
800
+ namespace "channels/voice"
801
+ end
802
+
803
+ class Address < Resource
804
+ namespace "channels/voice"
805
+ end
806
+
807
+ class Greeting < Resource
808
+ namespace "channels/voice"
809
+ end
810
+
811
+ class GreetingCategory < Resource
812
+ namespace "channels/voice"
813
+ end
814
+
815
+ class Ticket < CreateResource
816
+ namespace "channels/voice"
817
+ end
818
+
819
+ class Agent < ReadResource
820
+ namespace "channels/voice"
821
+
822
+ class Ticket < CreateResource
823
+ def new_record?
824
+ true
825
+ end
826
+
827
+ def self.display!(client, options)
828
+ new(client, options).tap do |resource|
829
+ resource.save!(path: resource.path + '/display')
830
+ end
831
+ end
832
+ end
833
+
834
+ has_many Ticket
835
+ end
836
+ end
837
+
838
+ class TicketForm < Resource
839
+ # TODO
840
+ # post :clone
841
+ end
842
+
843
+ class AppInstallation < Resource
844
+ namespace "apps"
845
+
846
+ def self.singular_resource_name
847
+ "installation"
848
+ end
849
+
850
+ # Don't nest attributes
851
+ def attributes_for_save
852
+ attributes.changes
853
+ end
854
+
855
+ def handle_response(response)
856
+ @attributes.replace(response.body) if response.body
857
+ end
858
+ end
859
+
860
+ class AppNotification < CreateResource
861
+ class << self
862
+ def resource_path
863
+ "apps/notify"
864
+ end
865
+ end
866
+
867
+ # Don't nest attributes
868
+ def attributes_for_save
869
+ attributes.changes
870
+ end
871
+
872
+ def handle_response(response)
873
+ @attributes.replace(response.body) if response.body.is_a?(Hash)
874
+ end
875
+ end
876
+
877
+ class App < Resource
878
+ def initialize(client, attributes = {})
879
+ attributes[:upload_id] ||= nil
880
+
881
+ super
882
+ end
883
+
884
+ def self.create!(client, attributes = {}, &block)
885
+ if file_path = attributes.delete(:upload)
886
+ attributes[:upload_id] = client.apps.uploads.create!(:file => file_path).id
887
+ end
888
+
889
+ super
890
+ end
891
+
892
+ class Plan < Resource
893
+ end
894
+
895
+ class Upload < Data
896
+ class << self
897
+ def resource_path
898
+ "uploads"
899
+ end
900
+ end
901
+
902
+ include Create
903
+
904
+ def initialize(client, attributes)
905
+ attributes[:file] ||= attributes.delete(:id)
906
+
907
+ super
908
+ end
909
+
910
+ # Not nested under :upload, just returns :id
911
+ def save!(*)
912
+ super.tap do
913
+ attributes.id = @response.body["id"]
914
+ end
915
+ end
916
+
917
+ # Always save
918
+ def changed?
919
+ true
920
+ end
921
+
922
+ # Don't nest attributes
923
+ def attributes_for_save
924
+ attributes
925
+ end
926
+ end
927
+
928
+ def self.uploads(client, *args, &block)
929
+ ZendeskAPI::Collection.new(client, Upload, *args, &block)
930
+ end
931
+
932
+ def self.installations(client, *args, &block)
933
+ ZendeskAPI::Collection.new(client, AppInstallation, *args, &block)
934
+ end
935
+
936
+ has Upload, :path => "uploads"
937
+ has_many Plan
938
+
939
+ # Don't nest attributes
940
+ def attributes_for_save
941
+ attributes.changes
942
+ end
943
+
944
+ def handle_response(response)
945
+ @attributes.replace(response.body) if response.body
946
+ end
947
+ end
948
+
949
+ module DynamicContent
950
+ include DataNamespace
951
+
952
+ class Item < ZendeskAPI::Resource
953
+ namespace 'dynamic_content'
954
+
955
+ class Variant < ZendeskAPI::Resource
956
+ end
957
+
958
+ has_many Variant
959
+ end
960
+ end
961
+
962
+ class PushNotificationDevice < DataResource
963
+ def self.destroy_many(client, tokens)
964
+ ZendeskAPI::Collection.new(
965
+ client, self, "push_notification_devices" => tokens,
966
+ :path => "push_notification_devices/destroy_many",
967
+ :verb => :post
968
+ )
969
+ end
970
+ end
971
+ end