discourse_zendesk_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,58 @@
1
+ module ZendeskAPI
2
+ # @private
3
+ module Sideloading
4
+ def self.included(klass)
5
+ klass.send(:attr_reader, :included)
6
+ end
7
+
8
+ def set_includes(resource_or_resources, includes, body)
9
+ @included = {}
10
+
11
+ includes.each do |side_load|
12
+ unless body.key?(side_load.to_s)
13
+ @client.config.logger.warn "Missing #{side_load} key in response -- cannot side load"
14
+ end
15
+ end
16
+
17
+ resources = to_array(resource_or_resources)
18
+ resource_class = resources.first.class
19
+
20
+ return if resources.empty?
21
+
22
+ body.keys.each do |name|
23
+ @included[name] = body[name]
24
+ _side_load(name, resource_class, resources)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # Traverses the resource looking for associations
31
+ # then descends into those associations and checks for applicable
32
+ # resources to side load
33
+ def _side_load(name, klass, resources)
34
+ associations = klass.associated_with(name)
35
+
36
+ associations.each do |association|
37
+ association.side_load(resources, @included[name])
38
+ end
39
+
40
+ resources.each do |resource|
41
+ loaded_associations = resource.loaded_associations
42
+ loaded_associations.each do |association|
43
+ loaded = resource.send(association[:name])
44
+ next unless loaded
45
+ _side_load(name, association[:class], to_array(loaded))
46
+ end
47
+ end
48
+ end
49
+
50
+ def to_array(item)
51
+ if item.is_a?(Collection)
52
+ item
53
+ else
54
+ [item].flatten.compact
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,8 @@
1
+ require 'hashie'
2
+
3
+ module ZendeskAPI
4
+ # @private
5
+ class SilentMash < Hashie::Mash
6
+ disable_warnings
7
+ end
8
+ end
@@ -0,0 +1,85 @@
1
+ module ZendeskAPI
2
+ # Shamelessly stolen and modified from https://github.com/archan937/dirty_hashy
3
+ # @private
4
+ module TrackChanges
5
+ def self.included(base)
6
+ base.method_defined?(:regular_writer).tap do |defined|
7
+ base.send :include, InstanceMethods
8
+ unless defined
9
+ base.send :alias_method, :_store, :store
10
+ base.send :alias_method, :store, :regular_writer
11
+ base.send :alias_method, :[]=, :store
12
+ base.send :define_method, :update do |other|
13
+ other.each { |key, value| store key, value }
14
+ end
15
+ base.send :alias_method, :merge!, :update
16
+ end
17
+ end
18
+ end
19
+
20
+ # @private
21
+ module InstanceMethods
22
+ def clear_changes
23
+ each do |k, v|
24
+ if v.respond_to?(:clear_changes)
25
+ v.clear_changes
26
+ elsif v.is_a?(Array)
27
+ v.each do |val|
28
+ if val.respond_to?(:clear_changes)
29
+ val.clear_changes
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ changes.clear
36
+ end
37
+
38
+ def replace(other)
39
+ clear
40
+ merge! other
41
+ end
42
+
43
+ def clear
44
+ keys.each { |key| delete key }
45
+ end
46
+
47
+ def regular_writer(key, value)
48
+ if has_key?(key) && self[key] == value
49
+ value
50
+ else
51
+ changes[key] = value
52
+ defined?(_store) ? _store(key, value) : super(key, value)
53
+ end
54
+ end
55
+
56
+ def delete(key)
57
+ super.tap do |value|
58
+ changes[key] = nil
59
+ end
60
+ end
61
+
62
+ def changes
63
+ (@changes ||= self.class.superclass.new).tap do |changes|
64
+ each do |k, v|
65
+ if v.respond_to?(:changed?) && v.changed?
66
+ changes[k] = v.changes
67
+ elsif v.is_a?(Array) && v.any? { |val| val.respond_to?(:changed?) && val.changed? }
68
+ changes[k] = v
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def changed?(key = nil)
75
+ if key.nil?
76
+ !changes.empty? || any? { |_, v| v.respond_to?(:changed?) && v.changed? }
77
+ else
78
+ changes.key?(key)
79
+ end
80
+ end
81
+
82
+ alias :dirty? :changed?
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,13 @@
1
+ require 'zendesk_api/track_changes'
2
+ require 'zendesk_api/silent_mash'
3
+
4
+ module ZendeskAPI
5
+ # @private
6
+ class Trackie < SilentMash
7
+ include ZendeskAPI::TrackChanges
8
+
9
+ def size
10
+ self['size']
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ module ZendeskAPI
2
+ # Creates put, post, delete class methods for custom resource methods.
3
+ module Verbs
4
+ class << self
5
+ private
6
+
7
+ # @macro [attach] container.create_verb
8
+ # @method $1(method)
9
+ # Executes a $1 using the passed in method as a path.
10
+ # Reloads the resource's attributes if any are in the response body.
11
+ #
12
+ # Created method takes an optional options hash. Valid options to be passed in to the created method: reload (for caching, default: false)
13
+ def create_verb(method_verb)
14
+ define_method method_verb do |method|
15
+ define_method "#{method}!" do |*method_args|
16
+ opts = method_args.last.is_a?(Hash) ? method_args.pop : {}
17
+
18
+ if method_verb == :any
19
+ verb = opts.delete(:verb)
20
+ raise(ArgumentError, ":verb required for method defined as :any") unless verb
21
+ else
22
+ verb = method_verb
23
+ end
24
+
25
+ @response = @client.connection.send(verb, "#{path}/#{method}") do |req|
26
+ req.body = opts
27
+ end
28
+
29
+ return false unless @response.success?
30
+ return false unless @response.body
31
+
32
+ resource = nil
33
+
34
+ if @response.body.is_a?(Hash)
35
+ resource = @response.body[self.class.singular_resource_name]
36
+ resource ||= @response.body.fetch(self.class.resource_name, []).detect { |res| res["id"] == id }
37
+ end
38
+
39
+ @attributes.replace @attributes.deep_merge(resource || {})
40
+ @attributes.clear_changes
41
+ clear_associations
42
+
43
+ true
44
+ end
45
+
46
+ define_method method do |*method_args|
47
+ begin
48
+ send("#{method}!", *method_args)
49
+ rescue ZendeskAPI::Error::RecordInvalid => e
50
+ @errors = e.errors
51
+ false
52
+ rescue ZendeskAPI::Error::ClientError
53
+ false
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ create_verb :put
61
+ create_verb :post
62
+ create_verb :delete
63
+ create_verb :any
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module ZendeskAPI
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ module ZendeskAPI; end
2
+
3
+ require 'zendesk_api/core_ext/inflection'
4
+ require 'zendesk_api/client'
@@ -0,0 +1,74 @@
1
+ require 'zendesk_api'
2
+
3
+ class ResourceHandler < YARD::Handlers::Ruby::Base
4
+ handles method_call(:has), method_call(:has_many)
5
+
6
+ def process
7
+ many = statement.jump(:ident).source == "has_many"
8
+
9
+ klass = get_klass(statement)
10
+
11
+ if klass
12
+ begin
13
+ klass = klass.split("::").inject(ZendeskAPI) do |p, k|
14
+ p.const_get(k)
15
+ end
16
+ rescue NameError
17
+ parent = walk_namespace(namespace)
18
+ klass = parent.const_get(klass)
19
+ end
20
+
21
+ name = statement.parameters.first.jump(:ident).source
22
+ else
23
+ klass = statement.parameters.first.source
24
+
25
+ begin
26
+ klass = ZendeskAPI.const_get(klass)
27
+ rescue NameError
28
+ parent = walk_namespace(namespace)
29
+ klass = parent.const_get(klass)
30
+ end
31
+
32
+ name = many ? klass.resource_name : klass.singular_resource_name
33
+ end
34
+
35
+ reader = YARD::CodeObjects::MethodObject.new(namespace, name)
36
+ register(reader)
37
+ reader.dynamic = true
38
+ reader.docstring.add_tag(YARD::Tags::Tag.new(:return, "The associated object", klass.name))
39
+
40
+ if many
41
+ reader.signature = "def #{name}=(options = {})"
42
+ reader.parameters = [['options', {}]]
43
+ reader.docstring.add_tag(YARD::Tags::Tag.new(:param, "Options to pass to the collection object", "Hash", "options"))
44
+ end
45
+
46
+ writer = YARD::CodeObjects::MethodObject.new(namespace, "#{name}=")
47
+ register(writer)
48
+ writer.signature = "def #{name}=(value)"
49
+ writer.parameters = [['value', nil]]
50
+ writer.dynamic = true
51
+ writer.docstring.add_tag(YARD::Tags::Tag.new(:return, "The associated object", klass.name))
52
+ writer.docstring.add_tag(YARD::Tags::Tag.new(:param, "The associated object or its attributes", "Hash or #{klass.name}", "value"))
53
+ end
54
+
55
+ def walk_namespace(namespace)
56
+ namespace.to_s.split('::').inject(ZendeskAPI) do |klass, namespace|
57
+ klass.const_get(namespace)
58
+ end
59
+ end
60
+
61
+ def get_klass(statement)
62
+ statement.traverse do |node|
63
+ if node.type == :assoc && node.jump(:kw).source == "class"
64
+ node.traverse do |value|
65
+ if value.type == :const_path_ref || value.type == :var_ref
66
+ return value.source
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ nil
73
+ end
74
+ end
@@ -0,0 +1,16 @@
1
+ class VerbHandler < YARD::Handlers::Ruby::Base
2
+ handles method_call(:put), method_call(:post), method_call(:get)
3
+
4
+ def process
5
+ name = statement.parameters.first.jump(:ident).source
6
+
7
+ verb = YARD::CodeObjects::MethodObject.new(namespace, name)
8
+ register(verb)
9
+ verb.dynamic = true
10
+ verb.docstring.add_tag(YARD::Tags::Tag.new(:return, "Success of this call", "Boolean"))
11
+
12
+ verb.signature = "def #{name}=(options = {})"
13
+ verb.parameters = [['options', {}]]
14
+ verb.docstring.add_tag(YARD::Tags::Tag.new(:param, "Options to pass to the request", "Hash", "options"))
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: discourse_zendesk_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Discourse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: hashie
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 3.5.2
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 5.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.5.2
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 5.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: inflection
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: multipart-post
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '2.0'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '2.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: mini_mime
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Ruby wrapper for the REST API at https://www.zendesk.com. Documentation
96
+ at https://developer.zendesk.com.
97
+ email:
98
+ - isaac.janzen@discourse.org
99
+ - sam.saffron@discourse.org
100
+ - robin.ward@discourse.org
101
+ - team@discourse.org
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - LICENSE
107
+ - lib/zendesk_api.rb
108
+ - lib/zendesk_api/actions.rb
109
+ - lib/zendesk_api/association.rb
110
+ - lib/zendesk_api/associations.rb
111
+ - lib/zendesk_api/client.rb
112
+ - lib/zendesk_api/collection.rb
113
+ - lib/zendesk_api/configuration.rb
114
+ - lib/zendesk_api/core_ext/inflection.rb
115
+ - lib/zendesk_api/delegator.rb
116
+ - lib/zendesk_api/error.rb
117
+ - lib/zendesk_api/helpers.rb
118
+ - lib/zendesk_api/lru_cache.rb
119
+ - lib/zendesk_api/middleware/request/encode_json.rb
120
+ - lib/zendesk_api/middleware/request/etag_cache.rb
121
+ - lib/zendesk_api/middleware/request/raise_rate_limited.rb
122
+ - lib/zendesk_api/middleware/request/retry.rb
123
+ - lib/zendesk_api/middleware/request/upload.rb
124
+ - lib/zendesk_api/middleware/request/url_based_access_token.rb
125
+ - lib/zendesk_api/middleware/response/callback.rb
126
+ - lib/zendesk_api/middleware/response/deflate.rb
127
+ - lib/zendesk_api/middleware/response/gzip.rb
128
+ - lib/zendesk_api/middleware/response/logger.rb
129
+ - lib/zendesk_api/middleware/response/parse_iso_dates.rb
130
+ - lib/zendesk_api/middleware/response/parse_json.rb
131
+ - lib/zendesk_api/middleware/response/raise_error.rb
132
+ - lib/zendesk_api/middleware/response/sanitize_response.rb
133
+ - lib/zendesk_api/resource.rb
134
+ - lib/zendesk_api/resources.rb
135
+ - lib/zendesk_api/sideloading.rb
136
+ - lib/zendesk_api/silent_mash.rb
137
+ - lib/zendesk_api/track_changes.rb
138
+ - lib/zendesk_api/trackie.rb
139
+ - lib/zendesk_api/verbs.rb
140
+ - lib/zendesk_api/version.rb
141
+ - util/resource_handler.rb
142
+ - util/verb_handler.rb
143
+ homepage: https://developer.zendesk.com
144
+ licenses:
145
+ - Apache-2.0
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '2.3'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 1.3.6
161
+ requirements: []
162
+ rubygems_version: 3.2.3
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: Discourse Zendesk REST API Client
166
+ test_files: []