Skip to content

Commit 56bb874

Browse files
committed
Cleaned up the Ticket model for a first release with an eye toward future enhancement
Removed the account from the process of fetching tickets Changed the create_ticket example script to use the new model
1 parent 47a994b commit 56bb874

10 files changed

Lines changed: 113 additions & 134 deletions

File tree

examples/create_ticket.rb

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,44 @@
2424
require 'softlayer_api'
2525
require 'pp'
2626

27-
# We can use globals to establish our client's credentials
28-
$SL_API_USERNAME = "joecustomer" # enter your username here
29-
$SL_API_KEY = "feeddeadbeefbadf00d..." # enter your api key here
27+
softlayer_client = SoftLayer::Client.new(
28+
# :username => "joecustomer" # enter your username here
29+
# :api_key => "feeddeadbeefbadf00d..." # enter your api key here
30+
)
3031

31-
softlayer_client = SoftLayer::Client.new()
3232
begin
33-
# use an account service to get the account ID of my account
34-
account_service = softlayer_client.service_named("Account")
35-
my_account_id = account_service.getCurrentUser['id']
33+
# To create a ticket we have to assign the ticket to some user so
34+
# assign our new ticket to the current user
35+
account = SoftLayer::Account.account_for_client(softlayer_client)
36+
account_user = account.service.getCurrentUser
37+
my_user_id = account_user["id"]
38+
39+
# We also need a subject for the ticket. Subjects are specified by id
40+
# This code prints out a table of all the ticket subjects with their
41+
# ids:
42+
ticket_subjects = SoftLayer::Ticket.ticket_subjects(softlayer_client)
43+
ticket_subjects.each do |subject|
44+
puts "#{subject['id']}\t#{subject['name']}"
45+
end
46+
47+
# For this example we'll use 'Public Network Question' as the subject. That's id 1022
48+
public_network_question_id = 1022
3649

37-
# Use a ticket service to create a standard support ticket, assigned to me.
38-
# Note: calling for the Ticket service using the brackets is entirely equivalent
39-
# go calling service_named('Ticket')
40-
ticket_service = softlayer_client['Ticket']
41-
new_ticket = ticket_service.createStandardTicket(
42-
{
43-
"assignedUserId" => my_account_id,
44-
"subjectId" => 1022,
45-
"notifyUserOnUpdateFlag" => true
46-
},
47-
"This is a test ticket created from a Ruby client")
50+
# A title is optional, but we'll provide one and we offer the body of the ticket
51+
# remember to pass the client to create_standard_ticket
52+
new_ticket = SoftLayer::Ticket.create_standard_ticket(
53+
:client => softlayer_client,
54+
:title => "This is a test ticket, please simply close it",
55+
:body => "This test ticket was created to test the Ruby API client. Please ignore it.",
56+
:subject_id => public_network_question_id,
57+
:assigned_user_id => my_user_id
58+
)
4859

49-
puts "Created a new ticket : #{new_ticket['id']} - #{new_ticket['title']}"
60+
puts "Created a new ticket : #{new_ticket.id} - #{new_ticket.title}"
61+
62+
# we can also add an update to the ticket:
63+
new_ticket.update("This is a ticket update sent from the Ruby library")
5064

51-
# add an update to the newly created ticket.
52-
pp ticket_service.object_with_id(new_ticket['id']).edit({}, "This is a ticket update sent from the Ruby library")
5365
rescue Exception => exception
5466
$stderr.puts "An exception occurred while trying to complete the SoftLayer API calls #{exception}"
5567
end

examples/open_tickets.rb

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,22 @@
2424
require 'softlayer_api'
2525
require 'pp'
2626

27-
$SL_API_USERNAME = "joecustomer" # enter your username here
28-
$SL_API_KEY = "feeddeadbeefbadf00d..." # enter your api key here
27+
# One way to provide a username and api key is to provide them
28+
# as globals.
29+
# $SL_API_USERNAME = "joecustomer" # enter your username here
30+
# $SL_API_KEY = "feeddeadbeefbadf00d..." # enter your api key here
2931

30-
softlayer_client = SoftLayer::Client.new()
32+
# The client constructed here must get it's credentials from somewhere
33+
# In this script you might uncomment the globals above and assign your
34+
# credentials there
35+
SoftLayer::Client.default_client = SoftLayer::Client.new()
3136

32-
# use an account service to get a list of the open tickets and print their
33-
# IDs and titles
34-
account_service = softlayer_client.service_named("Account")
37+
# The openTickets routine will pick up the default client established above.
38+
open_tickets = SoftLayer::Ticket.open_tickets()
3539

36-
open_tickets = account_service.getOpenTickets
37-
open_tickets.each { |ticket| puts "#{ticket['id']} - #{ticket['title']}" }
38-
39-
# Now use the ticket service to get a each ticket (by ID) and a subset of the
40-
# information known about it. We've already collected this information above,
41-
# but this will demonstrate using an object mask to filter the results from
42-
# the server.
43-
ticket_service = softlayer_client["Ticket"]
40+
open_tickets.sort!{ |lhs, rhs| -(lhs.lastEditDate <=> rhs.lastEditDate) }
4441
open_tickets.each do |ticket|
45-
begin
46-
pp ticket_service.object_with_id(ticket["id"]).object_mask("mask[id,title,createDate,modifyDate,assignedUser[id,username,email]]").getObject
47-
rescue Exception => exception
48-
puts "exception #{exception}"
49-
end
42+
printf "#{ticket.id} - #{ticket.title}"
43+
44+
ticket.has_updates? ? printf("\t*\n") : printf("\n")
5045
end

lib/softlayer/Account.rb

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -113,30 +113,6 @@ class Account < SoftLayer::ModelBase
113113
end
114114
end
115115

116-
##
117-
# The tickets resource consists of all open tickets, and tickets closed
118-
# "recently". These refresh every 5 minutes.
119-
# :call-seq:
120-
# tickets(force_update=false)
121-
sl_dynamic_attr :tickets do |tickets|
122-
tickets.should_update? do
123-
@last_ticket_update ||= Time.at(0)
124-
(Time.now - @last_ticket_update) > 5 * 60 #update every 5 minutes
125-
end
126-
127-
tickets.to_update do
128-
@last_ticket_update = Time.now
129-
130-
open_ticket_data = self.softlayer_client["Account"].object_mask(Ticket.default_object_mask).getOpenTickets()
131-
recently_closed_data = self.softlayer_client["Account"].object_mask(Ticket.default_object_mask).getTicketsClosedInTheLastThreeDays()
132-
133-
open_tickets = open_ticket_data.collect { |ticket_data| Ticket.new(self.softlayer_client, ticket_data) }
134-
closed_tickets = recently_closed_data.collect { |ticket_data| Ticket.new(self.softlayer_client, ticket_data) }
135-
136-
open_tickets + closed_tickets
137-
end
138-
end
139-
140116
def service
141117
softlayer_client["Account"].object_with_id(self.id)
142118
end

lib/softlayer/Client.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class Client
5252
##
5353
# The client class maintains an (optional) default client. The default client
5454
# will be used by many methods if you do not provide an explicit client.
55+
@@default_client = nil
56+
5557
def self.default_client
5658
return @@default_client
5759
end

lib/softlayer/ObjectMaskProperty.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def add_children(new_children)
7575
new_children.each { |new_child| add_child(new_child) }
7676
end
7777

78+
# DANGER: assumes you've already checked can_merge_with? before calling this routine!
7879
def merge(other_property)
7980
add_children other_property.children
8081
end

lib/softlayer/Service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def call_softlayer_api_with_params(method_name, parameters, args)
287287
# If this is not defined for Service, then when you print a service object
288288
# the code will try to convert it to an array and end up calling method_missing
289289
#
290-
# We define this here to prevent odd calls to the Softlayer API
290+
# We define this here to prevent odd calls to the SoftLayer API
291291
def to_ary
292292
nil
293293
end

lib/softlayer/Ticket.rb

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,30 @@ module SoftLayer
2424
class Ticket < SoftLayer::ModelBase
2525

2626
##
27-
# :attr_reader: title
27+
# :attr_reader:
2828
# The title is an identifying string set when the ticket is created
2929
sl_attr :title
3030

3131
##
32-
# :attr_reader: subject
32+
# :attr_reader:
3333
# The ticket system maintains a fixed set of subjects for tickets that are used to ensure tickets make it to the right folks quickly
3434
sl_attr :subject
35+
36+
##
37+
# :attr_reader:
38+
# The date the ticket was last updated.
39+
sl_attr :lastEditDate
3540

3641
##
3742
# Returns true if the ticket has "unread" updates
3843
def has_updates?
39-
self["newUpdatesFlag"] != 0
44+
self["newUpdatesFlag"]
4045
end
4146

4247
##
4348
# Returns true if the ticket is a server admin ticket
4449
def server_admin_ticket?
50+
# note that serverAdministrationFlag comes from the server as an Integer (0, or 1)
4551
self["serverAdministrationFlag"] != 0
4652
end
4753

@@ -89,9 +95,9 @@ def self.default_object_mask
8995
'status.id',
9096
'createDate',
9197
'lastEditDate',
92-
'newUpdatesFlag',
93-
'awaitingUserResponseFlag',
94-
'serverAdministrationFlag',
98+
'newUpdatesFlag', # This comes in from the server as a Boolean value
99+
'awaitingUserResponseFlag', # This comes in from the server as a Boolean value
100+
'serverAdministrationFlag', # This comes in from the server as an integer :-(
95101
]
96102
}
97103
end
@@ -112,6 +118,29 @@ def self.ticket_subjects(client = nil)
112118
@ticket_subjects
113119
end
114120

121+
##
122+
# Returns the set of currently open tickets
123+
#
124+
# Options should contain:
125+
#
126+
# <b>+:client+</b> - the client in which to search for the ticket
127+
#
128+
# If a client is not provided then the routine will search Client::default_client
129+
# If Client::default_client is also nil the routine will raise an error.
130+
def self.open_tickets(options = {})
131+
softlayer_client = options[:client] || Client.default_client
132+
raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
133+
134+
if options.has_key?(:object_mask)
135+
object_mask = options[:object_mask]
136+
else
137+
object_mask = default_object_mask.to_sl_object_mask
138+
end
139+
140+
open_tickets_data = softlayer_client["Account"].object_mask(object_mask).getOpenTickets
141+
open_tickets_data.collect { |ticket_data| new(softlayer_client, ticket_data) }
142+
end
143+
115144
##
116145
# Find the ticket with the given ID and return it
117146
#
@@ -132,7 +161,7 @@ def self.ticket_with_id(ticket_id, options = {})
132161
object_mask = default_object_mask.to_sl_object_mask
133162
end
134163

135-
ticket_data = softlayer_client["Ticket"].object_with_id(server_id).object_mask(object_mask).getObject()
164+
ticket_data = softlayer_client["Ticket"].object_with_id(ticket_id).object_mask(object_mask).getObject()
136165

137166
return new(softlayer_client, ticket_data)
138167
end
@@ -153,7 +182,7 @@ def self.ticket_with_id(ticket_id, options = {})
153182
# * <b>+:body+</b> (String) - The content of the ticket
154183
# * <b>+:subject_id+</b> (Int) - The id of a subject to use for the ticket. A list of ticket subjects can be returned by SoftLayer::Ticket.ticket_subjects
155184
# * <b>+:assigned_user_id+</b> (Int) - The id of a user to whom the ticket should be assigned
156-
def self.create_ticket(options = {})
185+
def self.create_standard_ticket(options = {})
157186
softlayer_client = options[:client] || SoftLayer::Client.default_client
158187
raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
159188

lib/softlayer/object_mask_helpers.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __sl_object_mask_properties_for_keys
8080
end
8181

8282
##
83-
# Softlayer Extensions to the Array class to support using arrays to create
83+
# SoftLayer Extensions to the Array class to support using arrays to create
8484
# object masks
8585
class Array
8686
# Returns a string representing the object mask content represented by the
@@ -95,7 +95,7 @@ def _to_sl_object_mask_property()
9595
end
9696

9797
##
98-
# Softlayer Extensions to the String class to support using strings to create
98+
# SoftLayer Extensions to the String class to support using strings to create
9999
# object masks
100100
class String
101101
# Returns a string representing the object mask content represented by the
@@ -109,7 +109,7 @@ def _to_sl_object_mask_property()
109109
end
110110

111111
##
112-
# Softlayer Extensions to the Symbol class to support using symbols to create
112+
# SoftLayer Extensions to the Symbol class to support using symbols to create
113113
# object masks
114114
class Symbol
115115
# Converts the Symbol to a string, then converts the string to an

spec/Account_spec.rb

Lines changed: 11 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,18 @@
9898

9999
describe "relationship to servers" do
100100
it "should respond to a request for servers" do
101-
fixture_account_data = fixture_from_json("test_account")
102-
fixture_bare_metal_data = fixture_from_json("test_bare_metal.json")
103-
fixture_virtual_server_data = fixture_from_json("test_virtual_servers")
104-
105101
mock_client = SoftLayer::Client.new(:username => "fakeuser", :api_key => "fake_api_key")
106-
allow(mock_client).to receive(:[]) do |service_name|
107-
expect(service_name).to eq "Account"
108-
109-
if(!@mock_service)
110-
@mock_service = SoftLayer::Service.new("SoftLayer_Account", :client => mock_client)
111-
allow(@mock_service).to receive(:getObject).and_return(fixture_account_data)
112-
113-
expect(@mock_service).to receive(:getHardware).and_return(fixture_bare_metal_data)
114-
expect(@mock_service).to receive(:getVirtualGuests).and_return(fixture_virtual_server_data)
115-
allow(@mock_service).to receive(:object_mask).and_return(@mock_service)
116-
117-
# if we've stubbed everything out correctly... we shouldn't actually be calling the API
118-
expect(@mock_service).to_not receive(:call_softlayer_api_with_params)
119-
end
120-
121-
@mock_service
102+
account_service = mock_client["Account"]
103+
allow(account_service).to receive(:getObject).and_return(fixture_from_json("test_account"))
104+
allow(account_service).to receive(:call_softlayer_api_with_params) do |api_method, api_filter, arguments|
105+
case api_method
106+
when :getHardware
107+
fixture_bare_metal_data = fixture_from_json("test_bare_metal")
108+
when :getVirtualGuests
109+
fixture_from_json("test_virtual_servers")
110+
when :getObject
111+
fixture_from_json("test_account")
112+
end
122113
end
123114

124115
test_account = SoftLayer::Account.account_for_client(mock_client)
@@ -131,43 +122,6 @@
131122
end
132123
end
133124

134-
describe "fetching tickets" do
135-
before do
136-
fixture_account_data = fixture_from_json("test_account")
137-
fixture_open_tickets = fixture_from_json("test_tickets")
138-
fixture_closed_tickets = fixture_from_json("test_tickets.json")
139-
140-
@mock_client = SoftLayer::Client.new(:username => "fakeuser", :api_key => "fake_api_key")
141-
allow(@mock_client).to receive(:[]) do |service_name|
142-
expect(service_name).to eq "Account"
143-
144-
if !@mock_service
145-
146-
@mock_service = SoftLayer::Service.new("SoftLayer_Account", :client => @mock_client)
147-
allow(@mock_service).to receive(:getObject).and_return(fixture_account_data)
148-
allow(@mock_service).to receive(:object_mask).and_return(@mock_service)
149-
allow(@mock_service).to receive(:call_softlayer_api_with_params)
150-
151-
expect(@mock_service).to receive(:getOpenTickets).and_return(fixture_open_tickets)
152-
expect(@mock_service).to receive(:getTicketsClosedInTheLastThreeDays).and_return(fixture_closed_tickets)
153-
154-
# if we've stubbed everything out correctly... we shouldn't actually be calling the API
155-
expect(@mock_service).to_not receive(:call_softlayer_api_with_params)
156-
end
157-
158-
@mock_service
159-
end
160-
end
161-
162-
it "responds to a tickets request" do
163-
test_account = SoftLayer::Account.account_for_client(@mock_client)
164-
expect(test_account).to respond_to(:tickets)
165-
expect(test_account).to_not respond_to(:tickets=)
166-
167-
tickets = test_account.tickets
168-
end
169-
end
170-
171125
describe "Account.account_for_client" do
172126
it "raises an error if there is no client available" do
173127
SoftLayer::Client.default_client = nil
@@ -188,5 +142,4 @@
188142
expect(mock_account.id).to be(12345)
189143
end
190144
end
191-
192145
end

spec/Ticket_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@
3333
SoftLayer::Ticket.instance_eval { @ticket_subjects = nil }
3434
end
3535

36+
it "fetches a list of open tickets" do
37+
mock_client = SoftLayer::Client.new(:username => "fakeuser", :api_key => "fake_api_key")
38+
account_service = mock_client["Account"]
39+
40+
expect(account_service).to receive(:call_softlayer_api_with_params).with(:getOpenTickets, instance_of(SoftLayer::APIParameterFilter),[]) do
41+
fixture_from_json("test_tickets")
42+
end
43+
44+
SoftLayer::Ticket.open_tickets(:client => mock_client)
45+
end
46+
3647
it "retrieves ticket subjects from API once" do
3748
fakeTicketSubjects = fixture_from_json("ticket_subjects")
3849

0 commit comments

Comments
 (0)