teamsupport 0.1.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.
- checksums.yaml +7 -0
- data/.yardopts +12 -0
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +47 -0
- data/LICENSE.md +26 -0
- data/README.md +132 -0
- data/lib/teamsupport.rb +21 -0
- data/lib/teamsupport/arguments.rb +26 -0
- data/lib/teamsupport/base.rb +173 -0
- data/lib/teamsupport/client.rb +86 -0
- data/lib/teamsupport/creatable.rb +31 -0
- data/lib/teamsupport/customer.rb +66 -0
- data/lib/teamsupport/customer_product.rb +14 -0
- data/lib/teamsupport/error.rb +135 -0
- data/lib/teamsupport/headers.rb +51 -0
- data/lib/teamsupport/identity.rb +43 -0
- data/lib/teamsupport/null_object.rb +52 -0
- data/lib/teamsupport/product.rb +14 -0
- data/lib/teamsupport/rest/api.rb +19 -0
- data/lib/teamsupport/rest/client.rb +25 -0
- data/lib/teamsupport/rest/customers.rb +156 -0
- data/lib/teamsupport/rest/products.rb +113 -0
- data/lib/teamsupport/rest/request.rb +116 -0
- data/lib/teamsupport/rest/tickets.rb +134 -0
- data/lib/teamsupport/rest/utils.rb +325 -0
- data/lib/teamsupport/ticket.rb +81 -0
- data/lib/teamsupport/ticket_action.rb +16 -0
- data/lib/teamsupport/utils.rb +33 -0
- data/lib/teamsupport/version.rb +73 -0
- data/teamsupport.gemspec +27 -0
- metadata +158 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'teamsupport/error'
|
2
|
+
require 'teamsupport/utils'
|
3
|
+
require 'teamsupport/version'
|
4
|
+
|
5
|
+
module Teamsupport
|
6
|
+
class Client
|
7
|
+
# Provide api_key and api_secret methods for accessing Client API values
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
11
|
+
# teamsupport_client.api_key
|
12
|
+
# teamsupport_client.api_secret
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
attr_accessor :api_key, :api_secret
|
18
|
+
|
19
|
+
# Provide user_agent method for overriding default Client user_agent value
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
23
|
+
# teamsupport_client.user_agent = 'MyTeamsupportClient/1.0.0'
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
attr_writer :user_agent
|
29
|
+
|
30
|
+
# Initializes a new Client object
|
31
|
+
#
|
32
|
+
# @param options [Hash]
|
33
|
+
#
|
34
|
+
# @return [Teamsupport::Client]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
def initialize(options = {})
|
38
|
+
options.each do |key, value|
|
39
|
+
instance_variable_set("@#{key}", value)
|
40
|
+
end
|
41
|
+
yield(self) if block_given?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns user agent string for the Client
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
48
|
+
# teamsupport_client.user_agent
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def user_agent
|
54
|
+
@user_agent ||= "TeamsupportRubyGem/#{Teamsupport::Version}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns authentication hash for the Client
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
61
|
+
# teamsupport_client.auth
|
62
|
+
#
|
63
|
+
# @return [Hash]
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def auth
|
67
|
+
{
|
68
|
+
user: api_key,
|
69
|
+
password: api_secret,
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Checks for the existence of an authentication hash on the Client
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
77
|
+
# teamsupport_client.auth?
|
78
|
+
#
|
79
|
+
# @return [Boolean]
|
80
|
+
#
|
81
|
+
# @api public
|
82
|
+
def auth?
|
83
|
+
auth.values.all?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module Teamsupport
|
4
|
+
module Creatable
|
5
|
+
# Time when object was created on TeamSupport
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# teamsupport_object = Teamsupport::Creatable.new(DateCreated: '4/4/2015 9:45 AM')
|
9
|
+
# teamsupport_object.DateCreated
|
10
|
+
#
|
11
|
+
# @return [Time]
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def DateCreated # rubocop:disable Style/MethodName
|
15
|
+
Time.strptime(@attrs[:DateCreated], '%m/%d/%Y %l:%M %p').utc unless @attrs[:DateCreated].nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Time when object was last modified on TeamSupport
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# teamsupport_object = Teamsupport::Creatable.new(DateModified: '4/4/2015 10:00 AM')
|
22
|
+
# teamsupport_object.DateModified
|
23
|
+
#
|
24
|
+
# @return [Time]
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
def DateModified # rubocop:disable Style/MethodName
|
28
|
+
Time.strptime(@attrs[:DateModified], '%m/%d/%Y %l:%M %p').utc unless @attrs[:DateModified].nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'teamsupport/base'
|
2
|
+
require 'teamsupport/creatable'
|
3
|
+
require 'teamsupport/identity'
|
4
|
+
|
5
|
+
module Teamsupport
|
6
|
+
class Customer < Teamsupport::Identity
|
7
|
+
include Teamsupport::Creatable
|
8
|
+
|
9
|
+
# @return [Integer]
|
10
|
+
attr_reader :ID, :PrimaryUserID, :CreatorID, :ModifierID, :SlaLevelID, :DefaultSupportGroupID, :DefaultSupportUserID, :SupportHoursMonth, :SupportHoursUsed, :SupportHoursRemaining
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :Name, :Description, :Website, :InActiveReason, :PrimaryContact, :Domains, :CreatedBy, :LastModifiedBy, :SlaName, :CRMLinkId, :DefaultWikiArticle, :DefaultSupportGroup, :DefaultSupportUser
|
13
|
+
|
14
|
+
# Boolean indicating whether a Customer is active on Teamsupport
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# teamsupport_customer = Teamsupport::Customer.new(IsActive: true)
|
18
|
+
# teamsupport_customer.IsActive
|
19
|
+
#
|
20
|
+
# @return [Boolean]
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def IsActive # rubocop:disable Style/MethodName
|
24
|
+
@attrs[:IsActive] == 'True' ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Boolean indicating whether a Customer has portal access on Teamsupport
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# teamsupport_customer = Teamsupport::Customer.new(HasPortalAccess: true)
|
31
|
+
# teamsupport_customer.HasPortalAccess
|
32
|
+
#
|
33
|
+
# @return [Boolean]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def HasPortalAccess # rubocop:disable Style/MethodName
|
37
|
+
@attrs[:HasPortalAccess] == 'True' ? true : false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Boolean indicating whether a Customer needs indexing on Teamsupport
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# teamsupport_customer = Teamsupport::Customer.new(NeedsIndexing: true)
|
44
|
+
# teamsupport_customer.NeedsIndexing
|
45
|
+
#
|
46
|
+
# @return [Boolean]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def NeedsIndexing # rubocop:disable Style/MethodName
|
50
|
+
@attrs[:NeedsIndexing] == 'True' ? true : false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Time when the Customer's Service Agreement expires on Teamsupport
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# teamsupport_customer = Teamsupport::Customer.new(SAExpirationDate: '4/4/2015 10:15 AM')
|
57
|
+
# teamsupport_customer.SAExpirationDate
|
58
|
+
#
|
59
|
+
# @return [Time]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def SAExpirationDate # rubocop:disable Style/MethodName
|
63
|
+
Time.strptime(@attrs[:SAExpirationDate], '%m/%d/%Y %l:%M %p').utc unless @attrs[:SAExpirationDate].nil?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'teamsupport/base'
|
2
|
+
require 'teamsupport/creatable'
|
3
|
+
require 'teamsupport/product'
|
4
|
+
|
5
|
+
module Teamsupport
|
6
|
+
class CustomerProduct < Teamsupport::Product
|
7
|
+
include Teamsupport::Creatable
|
8
|
+
|
9
|
+
# @return [Integer]
|
10
|
+
attr_reader :ID, :CreatorID, :ModifierID, :OrganizationID, :ProductID
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :Name, :Description
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Teamsupport
|
2
|
+
# Custom error class for rescuing from all Teamsupport errors
|
3
|
+
class Error < StandardError
|
4
|
+
# Provide a code method for reading HTTP status code from Error
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# teamsupport_error = Teamsupport::Error.new(code: 404)
|
8
|
+
# teamsupport_error.code
|
9
|
+
#
|
10
|
+
# @return [Integer]
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
attr_reader :code
|
14
|
+
|
15
|
+
# Raised when Teamsupport returns a 4xx HTTP status code
|
16
|
+
ClientError = Class.new(self)
|
17
|
+
|
18
|
+
# Raised when Teamsupport returns the HTTP status code 400
|
19
|
+
BadRequest = Class.new(ClientError)
|
20
|
+
|
21
|
+
# Raised when Teamsupport returns the HTTP status code 401
|
22
|
+
Unauthorized = Class.new(ClientError)
|
23
|
+
|
24
|
+
# Raised when Teamsupport returns the HTTP status code 403
|
25
|
+
Forbidden = Class.new(ClientError)
|
26
|
+
|
27
|
+
# Raised when Teamsupport returns the HTTP status code 404
|
28
|
+
NotFound = Class.new(ClientError)
|
29
|
+
|
30
|
+
# Raised when Teamsupport returns the HTTP status code 406
|
31
|
+
NotAcceptable = Class.new(ClientError)
|
32
|
+
|
33
|
+
# Raised when Teamsupport returns the HTTP status code 422
|
34
|
+
UnprocessableEntity = Class.new(ClientError)
|
35
|
+
|
36
|
+
# Raised when Teamsupport returns the HTTP status code 429
|
37
|
+
TooManyRequests = Class.new(ClientError)
|
38
|
+
|
39
|
+
# Raised when Teamsupport returns a 5xx HTTP status code
|
40
|
+
ServerError = Class.new(self)
|
41
|
+
|
42
|
+
# Raised when Teamsupport returns the HTTP status code 500
|
43
|
+
InternalServerError = Class.new(ServerError)
|
44
|
+
|
45
|
+
# Raised when Teamsupport returns the HTTP status code 502
|
46
|
+
BadGateway = Class.new(ServerError)
|
47
|
+
|
48
|
+
# Raised when Teamsupport returns the HTTP status code 503
|
49
|
+
ServiceUnavailable = Class.new(ServerError)
|
50
|
+
|
51
|
+
# Raised when Teamsupport returns the HTTP status code 504
|
52
|
+
GatewayTimeout = Class.new(ServerError)
|
53
|
+
|
54
|
+
ERRORS = {
|
55
|
+
400 => Teamsupport::Error::BadRequest,
|
56
|
+
401 => Teamsupport::Error::Unauthorized,
|
57
|
+
403 => Teamsupport::Error::Forbidden,
|
58
|
+
404 => Teamsupport::Error::NotFound,
|
59
|
+
406 => Teamsupport::Error::NotAcceptable,
|
60
|
+
422 => Teamsupport::Error::UnprocessableEntity,
|
61
|
+
429 => Teamsupport::Error::TooManyRequests,
|
62
|
+
500 => Teamsupport::Error::InternalServerError,
|
63
|
+
502 => Teamsupport::Error::BadGateway,
|
64
|
+
503 => Teamsupport::Error::ServiceUnavailable,
|
65
|
+
504 => Teamsupport::Error::GatewayTimeout,
|
66
|
+
}.freeze
|
67
|
+
|
68
|
+
class << self
|
69
|
+
# Create a new error from an HTTP response
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# teamsupport_error = Teamsupport::Error::ERRORS[code]
|
73
|
+
# teamsupport_error.from_response(body, headers) unless klass.nil?
|
74
|
+
#
|
75
|
+
# @param body [String]
|
76
|
+
# @param headers [Hash]
|
77
|
+
#
|
78
|
+
# @return [Teamsupport::Error]
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
def from_response(body, _headers)
|
82
|
+
message, code = parse_error(body)
|
83
|
+
new(message, code)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Parses response body for errors
|
89
|
+
#
|
90
|
+
# @param body [String]
|
91
|
+
#
|
92
|
+
# @return [Array, nil]
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
def parse_error(body)
|
96
|
+
if body.nil? || body.empty?
|
97
|
+
['', nil]
|
98
|
+
elsif body[:error]
|
99
|
+
[body[:error], nil]
|
100
|
+
elsif body[:errors]
|
101
|
+
extract_message_from_errors(body)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Extracts error messages from response body
|
106
|
+
#
|
107
|
+
# @param body [String]
|
108
|
+
#
|
109
|
+
# @return [Array]
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
def extract_message_from_errors(body)
|
113
|
+
first = Array(body[:errors]).first
|
114
|
+
if first.is_a?(Hash)
|
115
|
+
[first[:message].chomp, first[:code]]
|
116
|
+
else
|
117
|
+
[first.chomp, nil]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Initializes a new Error object
|
123
|
+
#
|
124
|
+
# @param message [Exception, String]
|
125
|
+
# @param code [Integer]
|
126
|
+
#
|
127
|
+
# @return [Teamsupport::Error]
|
128
|
+
#
|
129
|
+
# @api private
|
130
|
+
def initialize(message = '', code = nil)
|
131
|
+
super(message)
|
132
|
+
@code = code
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Teamsupport
|
5
|
+
class Headers
|
6
|
+
# Initializes a new Headers object
|
7
|
+
#
|
8
|
+
# @param client [Teamsupport::Client]
|
9
|
+
# @param request_method [String]
|
10
|
+
# @param url [String]
|
11
|
+
# @param options [Hash]
|
12
|
+
#
|
13
|
+
# @return [Teamsupport::Headers]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
def initialize(client, request_method, url, options = {})
|
17
|
+
@client = client
|
18
|
+
@request_method = request_method.to_sym
|
19
|
+
@uri = Addressable::URI.parse(url)
|
20
|
+
@options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns HTTP request headers for the client
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# teamsupport_client = Teamsupport::Client.new(api_key: 'AK', api_secret: 'AS')
|
27
|
+
# teamsupport_headers = Teamsupport::Headers.new(teamsupport_client, :get, 'https://app.teamsupport.com')
|
28
|
+
# teamsupport_headers.request_headers
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def request_headers
|
34
|
+
headers = {'Content-Type' => 'application/json'}
|
35
|
+
headers[:user_agent] = @client.user_agent
|
36
|
+
headers[:authorization] = auth_header
|
37
|
+
headers
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Generates authentication header for TeamSupport API's basic auth
|
43
|
+
#
|
44
|
+
# @return [String]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
def auth_header
|
48
|
+
"Basic #{Base64.strict_encode64("#{@client.api_key}:#{@client.api_secret}")}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'equalizer'
|
2
|
+
require 'teamsupport/base'
|
3
|
+
|
4
|
+
module Teamsupport
|
5
|
+
class Identity < Teamsupport::Base
|
6
|
+
include Equalizer.new(:ID)
|
7
|
+
# @return [Integer]
|
8
|
+
|
9
|
+
# Method for reading the TeamSupport ID of an object
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# teamsupport_object = Teamsupport::Identity.new(ID: 1)
|
13
|
+
# teamsupport_object.ID
|
14
|
+
#
|
15
|
+
# @return [Integer]
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
attr_reader :ID
|
19
|
+
|
20
|
+
# Initializes a new object
|
21
|
+
#
|
22
|
+
# @param attrs [Hash]
|
23
|
+
#
|
24
|
+
# @raise [ArgumentError] Error raised when supplied argument is missing an :ID key.
|
25
|
+
#
|
26
|
+
# @return [Teamsupport::Identity]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
def initialize(attrs = {})
|
30
|
+
# Workaround for dealing with TeamSupport API inconsistently sending ID for objects
|
31
|
+
unless attrs[:ID]
|
32
|
+
attrs[:ID] = attrs.fetch(:OrganizationID) if attrs[:OrganizationID]
|
33
|
+
|
34
|
+
attrs[:ID] = attrs.fetch(:ProductID) if attrs[:ProductID]
|
35
|
+
|
36
|
+
attrs[:ID] = attrs.fetch(:TicketID) if attrs[:TicketID]
|
37
|
+
end
|
38
|
+
|
39
|
+
attrs.fetch(:ID)
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'naught'
|
2
|
+
|
3
|
+
module Teamsupport
|
4
|
+
NullObject = Naught.build do |config|
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
config.black_hole
|
8
|
+
config.define_explicit_conversions
|
9
|
+
config.define_implicit_conversions
|
10
|
+
config.predicates_return false
|
11
|
+
|
12
|
+
def !
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond_to?(*)
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to?(*)
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def instance_of?(klass)
|
25
|
+
raise(TypeError, 'class or module required') unless klass.is_a?(Class)
|
26
|
+
self.class == klass
|
27
|
+
end
|
28
|
+
|
29
|
+
def kind_of?(mod)
|
30
|
+
raise(TypeError, 'class or module required') unless mod.is_a?(Module)
|
31
|
+
self.class.ancestors.include?(mod)
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :is_a?, :kind_of?
|
35
|
+
|
36
|
+
def <=>(other)
|
37
|
+
if other.is_a?(self.class)
|
38
|
+
0
|
39
|
+
else
|
40
|
+
-1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def nil?
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def as_json(*)
|
49
|
+
'null'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|