tessera 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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.overcommit.yml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +179 -0
- data/Rakefile +6 -0
- data/_config.yml +1 -0
- data/bin/console +6 -0
- data/bin/setup +8 -0
- data/lib/tessera.rb +55 -0
- data/lib/tessera/api/session.rb +27 -0
- data/lib/tessera/api/ticket_create.rb +36 -0
- data/lib/tessera/api/ticket_get.rb +37 -0
- data/lib/tessera/api/ticket_list.rb +37 -0
- data/lib/tessera/api/ticket_search.rb +35 -0
- data/lib/tessera/configuration.rb +46 -0
- data/lib/tessera/model/base.rb +28 -0
- data/lib/tessera/model/session.rb +11 -0
- data/lib/tessera/model/ticket.rb +58 -0
- data/lib/tessera/otrs/article.rb +21 -0
- data/lib/tessera/otrs/attachment.rb +13 -0
- data/lib/tessera/otrs/base.rb +11 -0
- data/lib/tessera/otrs/ticket.rb +18 -0
- data/lib/tessera/request.rb +57 -0
- data/lib/tessera/ticket.rb +76 -0
- data/lib/tessera/utils/errors.rb +25 -0
- data/lib/tessera/version.rb +3 -0
- data/templates/ticket.yml +72 -0
- data/tessera.gemspec +42 -0
- data/wercker.yml +7 -0
- metadata +220 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Tessera
|
6
|
+
module Api
|
7
|
+
class TicketCreate
|
8
|
+
def initialize(body_content)
|
9
|
+
@body = body.merge(body_content)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.call(body_content)
|
13
|
+
new(body_content).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
response = Tessera::Request.new(:POST, 'Ticket', @body).send
|
18
|
+
JSON.parse(response.body)
|
19
|
+
end
|
20
|
+
|
21
|
+
def session_id
|
22
|
+
session = Session.create
|
23
|
+
# TODO: solve token creation failure with error
|
24
|
+
session.session_id
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def body
|
30
|
+
{
|
31
|
+
SessionID: session_id
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Tessera
|
6
|
+
module Api
|
7
|
+
class TicketGet
|
8
|
+
def initialize(ticket_id)
|
9
|
+
@ticket_id = ticket_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.call(ticket_id)
|
13
|
+
new(ticket_id).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
response = Tessera::Request.new(:GET, "Ticket/#{@ticket_id}", body).send
|
18
|
+
JSON.parse(response.body)
|
19
|
+
end
|
20
|
+
|
21
|
+
def session_id
|
22
|
+
session = Session.create
|
23
|
+
# TODO: solve token creation failure with error
|
24
|
+
session.session_id
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def body
|
30
|
+
{
|
31
|
+
TicketID: @ticket_id,
|
32
|
+
SessionID: session_id
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Tessera
|
6
|
+
module Api
|
7
|
+
class TicketList
|
8
|
+
def self.call(ticket_ids)
|
9
|
+
new(ticket_ids).call
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(ticket_ids)
|
13
|
+
@ticket_ids = ticket_ids
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
response = Tessera::Request.new(:GET, 'TicketList', body).send
|
18
|
+
JSON.parse(response.body)
|
19
|
+
end
|
20
|
+
|
21
|
+
def session_id
|
22
|
+
session = Session.create
|
23
|
+
# TODO: solve token creation failure with error
|
24
|
+
session.session_id
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def body
|
30
|
+
{
|
31
|
+
TicketID: @ticket_ids,
|
32
|
+
SessionID: session_id
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
##
|
2
|
+
# Class for searching through tickets
|
3
|
+
# as params hash any of these in official docs could be used:
|
4
|
+
# http://doc.otrs.com/doc/api/otrs/5.0/Perl/Kernel/GenericInterface/Operation/Ticket/TicketSearch.pm.html
|
5
|
+
#
|
6
|
+
module Tessera
|
7
|
+
module Api
|
8
|
+
class TicketSearch
|
9
|
+
def self.call(params = nil)
|
10
|
+
new(params).call
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(params)
|
14
|
+
@params = params
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
response = Tessera::Request.new(:GET, 'Ticket', body).send
|
19
|
+
JSON.parse(response.body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def session_id
|
23
|
+
session = Session.create
|
24
|
+
# TODO: solve token creation failure with error
|
25
|
+
session.session_id
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def body
|
31
|
+
@params.to_h.merge(SessionID: session_id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# This is configuration class that allows you to set your config like so:
|
4
|
+
#
|
5
|
+
# Tessera.configure do |config|
|
6
|
+
# config.username = 'jon'
|
7
|
+
# config.password = 'SuperSecret'
|
8
|
+
# config.base_url = 'https://otrs.com/otrs/nph-genericinterface.pl/Webservice/rest/'
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# or
|
12
|
+
#
|
13
|
+
# by simply assigning params by themself:
|
14
|
+
#
|
15
|
+
# config = Tessera::Configuration.new
|
16
|
+
# config.username = 'jon'
|
17
|
+
# config.password = 'SuperSecret'
|
18
|
+
# config.base_url = 'https://otrs.com/otrs/nph-genericinterface.pl/Webservice/rest/'
|
19
|
+
# Tessera.configuration = config
|
20
|
+
#
|
21
|
+
module Tessera
|
22
|
+
class Configuration
|
23
|
+
attr_writer :username, :password, :base_url
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@username = nil
|
27
|
+
@password = nil
|
28
|
+
@base_url = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def username
|
32
|
+
raise ConfigNotSet, 'username' unless @username
|
33
|
+
@username
|
34
|
+
end
|
35
|
+
|
36
|
+
def password
|
37
|
+
raise ConfigNotSet, 'password' unless @password
|
38
|
+
@password
|
39
|
+
end
|
40
|
+
|
41
|
+
def base_url
|
42
|
+
raise ConfigNotSet, 'base_url' unless @base_url
|
43
|
+
@base_url
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tessera
|
2
|
+
module Model
|
3
|
+
class Base
|
4
|
+
attr_accessor :response, :errors, :code
|
5
|
+
|
6
|
+
def initialize(response)
|
7
|
+
@response = response
|
8
|
+
@code = @response.code
|
9
|
+
parse_errors if parsed_body
|
10
|
+
parse_attributes if parsed_body
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def parse_errors
|
16
|
+
@errors = parsed_body['Error']
|
17
|
+
end
|
18
|
+
|
19
|
+
def parsed_body
|
20
|
+
JSON.parse(@response.body) if @response.body
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_attributes
|
24
|
+
raise NotImplementedError, 'Model must implement attribute mapping'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Tessera
|
2
|
+
module Model
|
3
|
+
class Ticket < Base
|
4
|
+
attr_accessor :ticket_id, :lock_id, :real_till_time_not_used, :changed,
|
5
|
+
:customer_user_id, :queue_id, :escalation_solution_time, :owner_id,
|
6
|
+
:unlock_timeout, :priority_id, :escalation_time, :type, :queue,
|
7
|
+
:escalation_response_time, :escalation_update_time, :customer_id,
|
8
|
+
:age, :until_time, :responsible, :lock, :priority, :state_id,
|
9
|
+
:created_by, :state, :type_id, :ticket_number, :group_id, :created,
|
10
|
+
:service_id, :owner, :slaid, :state_type, :title, :responsible_id,
|
11
|
+
:create_tim_nix, :changed_by, :archive_flag
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/MethodLength
|
14
|
+
# rubocop:disable Metrics/AbcSize
|
15
|
+
def initialize(params)
|
16
|
+
@ticket_id = params['TicketID']
|
17
|
+
@lock_id = params['LockID']
|
18
|
+
@real_till_time_not_used = params['RealTillTimeNotUsed']
|
19
|
+
@changed = params['Changed']
|
20
|
+
@customer_user_id = params['CustomerUserID']
|
21
|
+
@queue_id = params['QueueID']
|
22
|
+
@escalation_solution_time = params['EscalationSolutionTime']
|
23
|
+
@owner_id = params['OwnerID']
|
24
|
+
@unlock_timeout = params['UnlockTimeout']
|
25
|
+
@priority_id = params['PriorityID']
|
26
|
+
@escalation_time = params['EscalationTime']
|
27
|
+
@type = params['Type']
|
28
|
+
@queue = params['Queue']
|
29
|
+
@escalation_response_time = params['EscalationResponseTime']
|
30
|
+
@escalation_update_time = params['EscalationUpdateTime']
|
31
|
+
@customer_id = params['CustomerID']
|
32
|
+
@age = params['Age']
|
33
|
+
@until_time = params['UntilTime']
|
34
|
+
@responsible = params['Responsible']
|
35
|
+
@lock = params['Lock']
|
36
|
+
@priority = params['Priority']
|
37
|
+
@state_id = params['StateID']
|
38
|
+
@created_by = params['CreateBy']
|
39
|
+
@state = params['State']
|
40
|
+
@type_id = params['TypeID']
|
41
|
+
@ticket_number = params['TicketNumber']
|
42
|
+
@group_id = params['GroupID']
|
43
|
+
@created = params['Created']
|
44
|
+
@service_id = params['ServiceID']
|
45
|
+
@owner = params['Owner']
|
46
|
+
@slaid = params['SLAID']
|
47
|
+
@state_type = params['StateType']
|
48
|
+
@title = params['Title']
|
49
|
+
@responsible_id = params['ResponsibleID']
|
50
|
+
@create_tim_nix = params['CreateTimeUnix']
|
51
|
+
@changed_by = params['ChnageBy']
|
52
|
+
@archive_flag = params['ArchiveFlag']
|
53
|
+
end
|
54
|
+
# rubocop:enable Metrics/AbcSize
|
55
|
+
# rubocop:enable Metrics/MethodLength
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tessera
|
2
|
+
module Otrs
|
3
|
+
class Article < Base
|
4
|
+
attr_accessor :From, :To, :Subject, :Body, :ContentType, :CommunicationChannel,
|
5
|
+
:ArticleSend
|
6
|
+
|
7
|
+
# rubocop:disable Metrics/ParameterLists
|
8
|
+
def initialize(from:, to: nil, subject:, body:, communication_channel: 'Email',
|
9
|
+
article_send: 0)
|
10
|
+
@From = from
|
11
|
+
@To = to
|
12
|
+
@Subject = subject
|
13
|
+
@Body = body
|
14
|
+
@ContentType = 'text/plain; charset=utf8'
|
15
|
+
@CommunicationChannel = communication_channel
|
16
|
+
@ArticleSend = article_send
|
17
|
+
end
|
18
|
+
# rubocop:enable Metrics/ParameterLists
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Tessera
|
2
|
+
module Otrs
|
3
|
+
class Attachment < Base
|
4
|
+
attr_accessor :Content, :ContentType, :Filename
|
5
|
+
|
6
|
+
def initialize(tempfile:)
|
7
|
+
@Content = Base64.encode64(tempfile.read)
|
8
|
+
@ContentType = tempfile.content_type
|
9
|
+
@Filename = tempfile.original_filename
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Tessera
|
2
|
+
module Otrs
|
3
|
+
class Ticket < Base
|
4
|
+
attr_accessor :Title, :QueueID, :State, :PriorityID, :CustomerUser, :CustomerID
|
5
|
+
|
6
|
+
# rubocop:disable Metrics/ParameterLists
|
7
|
+
def initialize(title:, queue:, state:, priority:, customer_user:, customer_id:)
|
8
|
+
@Title = title
|
9
|
+
@QueueID = queue
|
10
|
+
@State = state
|
11
|
+
@PriorityID = priority
|
12
|
+
@CustomerUser = customer_user
|
13
|
+
@CustomerID = customer_id
|
14
|
+
end
|
15
|
+
# rubocop:enable Metrics/ParameterLists
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Request class
|
4
|
+
#
|
5
|
+
# Methods acepted:
|
6
|
+
# GET
|
7
|
+
# POST
|
8
|
+
# PATCH
|
9
|
+
#
|
10
|
+
# (basically it uses Net::HTTP, but other methods are not supported by API anyway...)
|
11
|
+
#
|
12
|
+
# Endpoint is based on you yaml setting
|
13
|
+
# You can find a template in templates directory here in repository
|
14
|
+
#
|
15
|
+
# Body gets assembled in (put name of class here) class :) (not here yet) TODO
|
16
|
+
#
|
17
|
+
# return value is Net::HTTPResponse which has to be parsed TODO (put name of class here)
|
18
|
+
#
|
19
|
+
module Tessera
|
20
|
+
class Request
|
21
|
+
def initialize(method, endpoint, body)
|
22
|
+
@method = method
|
23
|
+
@endpoint = endpoint
|
24
|
+
@body = body
|
25
|
+
end
|
26
|
+
|
27
|
+
def send
|
28
|
+
net_http_send
|
29
|
+
# Response.new(net_http_send)
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def net_http_send
|
35
|
+
uri = URI("#{Tessera.configuration.base_url}#{@endpoint}")
|
36
|
+
|
37
|
+
request = net_http_class.new(uri)
|
38
|
+
headers.each { |k, v| request[k] = v }
|
39
|
+
request.body = @body.to_json
|
40
|
+
|
41
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
|
42
|
+
http.request(request)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def net_http_class
|
47
|
+
Kernel.const_get("Net::HTTP::#{@method.capitalize}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def headers
|
51
|
+
{
|
52
|
+
'Accept-Encoding' => 'application/json',
|
53
|
+
'Content-Type' => 'application/json'
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Tessera
|
2
|
+
class Ticket
|
3
|
+
class << self
|
4
|
+
# rubocop:disable Metrics/AbcSize
|
5
|
+
# rubocop:disable Metrics/MethodLength
|
6
|
+
def find(ticket_id)
|
7
|
+
ticket = if ticket_id.is_a? Array
|
8
|
+
::Tessera::Api::TicketList.call(ticket_id)
|
9
|
+
else
|
10
|
+
::Tessera::Api::TicketGet.call(ticket_id)
|
11
|
+
end
|
12
|
+
if ticket['Error']
|
13
|
+
raise TicketNotFound.new(ticket['Error']['ErrorMessage'],
|
14
|
+
ticket['Error']['ErrorCode'])
|
15
|
+
elsif ticket['Ticket'] && ticket['Ticket'].count > 1
|
16
|
+
ticket['Ticket'].map do |ticket_json|
|
17
|
+
::Tessera::Model::Ticket.new(ticket_json)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
::Tessera::Model::Ticket.new(ticket['Ticket'].first)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# rubocop:enable Metrics/MethodLength
|
24
|
+
# rubocop:enable Metrics/AbcSize
|
25
|
+
|
26
|
+
def where(params)
|
27
|
+
result = Tessera::Api::TicketSearch.call(params)
|
28
|
+
ticket_ids = result['TicketID'] ? result['TicketID'] : []
|
29
|
+
new(ticket_ids)
|
30
|
+
end
|
31
|
+
|
32
|
+
# rubocop:disable Metrics/AbcSize
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
34
|
+
def create(params)
|
35
|
+
ticket = Tessera::Otrs::Ticket.new(params[:ticket]).to_hash
|
36
|
+
article = Tessera::Otrs::Article.new(params[:article]).to_hash
|
37
|
+
attachment = if params[:attachment]
|
38
|
+
case params[:attachment].class
|
39
|
+
when Hash
|
40
|
+
Tessera::Otrs::Attachment.new(params[:attachment]).to_hash
|
41
|
+
when Array
|
42
|
+
params[:attachment].map do |a|
|
43
|
+
Tessera::Otrs::Attachment.new(a).to_hash
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
body = { Ticket: ticket }
|
48
|
+
body = body.merge(Article: article)
|
49
|
+
body = body.merge(Attachment: attachment) if attachment
|
50
|
+
|
51
|
+
Tessera::Api::TicketCreate.call(body)
|
52
|
+
end
|
53
|
+
# rubocop:enable Metrics/MethodLength
|
54
|
+
# rubocop:enable Metrics/AbcSize
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize(result)
|
58
|
+
@result = result
|
59
|
+
end
|
60
|
+
|
61
|
+
def count
|
62
|
+
@result.size
|
63
|
+
end
|
64
|
+
|
65
|
+
def ticket_ids
|
66
|
+
@result.map(&:to_i)
|
67
|
+
end
|
68
|
+
|
69
|
+
def tickets
|
70
|
+
return [] if @result.empty?
|
71
|
+
@tickets ||= @result.map do |id|
|
72
|
+
::Tessera::Ticket.find(id)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|