“New” Motorcycle!

< 4 Wheels — Jeff Eske on June 12, 2013 at 9:59 am

I got a “new” motorcycle over the weekend.  It’s a used 2001 Harley-Davidson XL1200C Sportster.  I wasn’t really in the market for a motorcycle, but the deal was too good to pass up.  My brother-in-law was interested in selling it, and he gave me a good deal on it.  It’s low miles (10k) and basically stock.

I’ve owned a few motorcycles over the years, but they’ve always been “vintage” japanese machines.  The Sporty is the closest I’ve come to a new bike.  All of the others basically required some resuscitation in order to be ride-able.   I previously owned a 60s Suzuki 250cc two-cycle Scrambler, a ’76 Kawasaki KZ900 (the original superbike!), a 70s Suzuki 750 ( a top-heavy pig), and an ’87 Yamaha Virago 1100.

The Sporty is taking a while to get used to.  Like the Suzuki 750, it seems like it’s slightly top-heavy.  In addition to that, it has a somewhat stretched fork so, when turning, the frontend wants to “fall” in the direction you’re turning.  Basically, when you start to turn, the handlebars really want to turn all the way in that direction.  I rode my other brother-in-law’s Heritage Softtail and, even though it’s a lot heavier bike, it doesn’t feel as top-heavy and the steering feels “lighter”.  These things aren’t deal-breakers, they’re just differences that I’ve noticed between the Sportster and the other bikes that I’ve ridden.

More to come, as it happens.

Jeff Eske

Microsoft Office365 is more popular than almost everything

Web Stuff — Jeff Eske on May 30, 2013 at 11:16 am

Office365 is more popular than just about everyone except for Instagram.  Sort of.  According to Microsoft.

http://blogs.office.com/b/office-news/archive/2013/05/29/thanks-a-million.aspx

My Hobby is Post-Apocalyptic Doomsday Gold

General — Jeff Eske on March 27, 2013 at 4:14 pm

It appears that, according to National Geographics “Doomsday Preppers” infographic (see the graphic and a link to the site below), my leatherworking hobby would put me in the top 10 Most Valuable Professions. You have to look pretty hard to find it (HINT: As far down and to the right as you can go).

Would You Survive Doomsday? An Infographic – Nat Geo TV Blogs

Infographic from National Geographic

Infographic from National Geographic

OTRS – Parsing Out the Variables in a SOAP Response

OTRS,Programming,Snippets,Web Services,Web Stuff — Jeff Eske on March 5, 2013 at 5:16 pm

Unlike some web services, the OTRS web services don’t return the values in specific xml tags; it uses generic “s-gensym” tags.  Also, it returns field name within a set of generic tags, followed by the field value in a set of generic tags.  Here’s part of the SOAP response:

<s-gensym1558 xsi:type="xsd:string">PriorityID</s-gensym1558>
<s-gensym1560 xsi:type="xsd:int">3</s-gensym1560>
<s-gensym1562 xsi:type="xsd:string">ServiceID</s-gensym1562>
<s-gensym1564 xsi:type="xsd:string" />
<s-gensym1566 xsi:type="xsd:string">Type</s-gensym1566>
<s-gensym1568 xsi:type="xsd:string">Failure</s-gensym1568>

Makes a lot of sense, doesn’t it?  Here’s an example of one that actually uses the field name as the enclosing tag name.  It makes it easier to understand:

<fusion:ServiceDown><fusion:v>false</fusion:v></fusion:ServiceDown>
<fusion:BusinessUnit><fusion:v>Some Business Unit</fusion:v></fusion:BusinessUnit>

In this example, you can see that the ServiceDown field(fusion:ServiceDown) has a value(fusion:v) of “false”.  With OTRS, every time you run your SOAP request, you some random-ass “s-gensym” field name for everything.

To actually pull the SOAP response data out, you can use a foreach() loop and dump the field names and values into a more useful array.  In addition to that, the array will be setup as a key/value pair, so you can actually get the field value by referring to the field name.  I’m sure that there’s a much better, more elegant method to do the same thing, but this way works.  First the code, then an explanation of what’s going on:

[code]
$ticketInfo = array();
$i = 0;
foreach ($TicketDetails as $name => $value){ 
 if (false !== strpos($name, "s-gensym")){
 $temp[$i] = $value; 
 $v = $temp[$i-1]; 
 if($i % 2 != 0){ 
 $ticketInfo[$v] = $value; 
 }
 $i++;
 }
}
[/code]

Basically, what this code does is take your SOAP response array ($ticketInfo) and run it through a foreach() loop.  The OTRS SOAP response includes to entries for each field.  The first entry is the field name and the second entry is the field value.  So, what I want to do is combine both entries into a key->value pair in an array.

The foreach() explodes the values of the s-gensym variables out and adds the value to 2 different arrays.  This is where the elegance is definitely lacking.  I’m first saving the value into the $temp[] array to refer back to it later.  Then, if the row is divisble by two – basically every other, or every second row, I grab the previous value from temp[] and write it to $ticketInfo[] as the key and write the current value as the value.  What I end up with in the end is an array ($ticketInfo[]) that has the field name as the key and the field value as the value.

You can then pull the desired value by referring to the appropriate key, such as:

$ticket_age = $ticketInfo[Age];
$ticket_title = $ticketInfo[Title];

A simple way to print out all of the values in your array is, again, with the foreach() loop.  All you need is this little piece of code:

[code]
foreach ($ticketInfo as $name => $value){
 echo "<b>".$name.":</b> ".$value."<br>";
}
[/code]

The foreach() will loop through the array and explode out the key/value pairs, then echo them out.  It can be handy for troubleshooting, to see what everything actually looks like in the array.

Jeff Eske

OTRS – Web Services Descriptions and Examples

OTRS,Web Services,Web Stuff — Jeff Eske on March 5, 2013 at 4:47 pm

The OTRS ticketing system comes with some basic web service functions included by default.  I’ve already done a post about using web services to create a new ticket via TicketCreate(), as well as a post about retrieving an existing ticket via TicketGet().  I’ve also created a page to allow you to search for a ticket using the TicketSearch() function, but I haven’t posted anything about that yet.  I’ve also posted a code snippet that actually helped me considerably when I was troubleshooting exactly what was going on.

What I’d like to do here is just note some observations that I’ve made while messing around trying to figure all of this out.  Hopefully it will be of some use to someone.  As with everything on this site, the Disclaimer holds here to – all I can guarantee is that this stuff worked for me.  What I have listed below is what I’ve determined from trial-and-error, so take it with a grain of salt.  This is almost more to document it for myself than anyone else.

===============

TicketCreate()
Purpose:
Used to create new tickets object (duh!).  Generally, you’ll want to do an ArticleCreate() also, to add some useful information to the ticket.
Required Input Values: TypeID(integer), QueueID(integer), LockID(integer), PriorityID(integer), State(text), CustomerUser(text), OwnerID(integer), UserID(integer).
Optional, but Recommended: Title(text). The title is required, but it seems logical to add one.
Returns: TicketID(integer)

[code]
// PHP code sample for TicketCreate().  Adjust the values as necessary
$TicketID = $client->__soapCall(
 "Dispatch",array($username, $password,
 "TicketObject", "TicketCreate",
 "Title", "Some Title",
 "TypeID", some_typeID_number,
 "QueueID",  some_queueID_number,
 "LockID", 1,
 "PriorityID", some_priorityID_number,
 "State", "new",
 "CustomerUser", "some_user@your_organization",
 "OwnerID", some_ownerID_number,
 "UserID", some_userID_number,
 )
 );
[/code]

===============

ArticleCreate()
Purpose: Add an article to a ticket.  The TicketCreate() function basically just creates a “wrapper” for articles.  The articles provide the content.
Required Input Values: TicketID(integer), ArticleType(text), SenderType(text), HistoryType(text), HistoryComment(text), ContentType(text), UserID(integer)
Optional, but Recommended: From(text), Subject(text), Body(text), Loop(integer), AutoRepsonseType(text), OrigHeader(array)
Returns: ArticleID(integer)

[code]
// PHP code sample for ArticleCreate().  Adjust the values as necessary
$ArticleID = $client->__soapCall("Dispatch", 
array($username, $password,
"TicketObject", "ArticleCreate",
"TicketID", some_ticketID_to_add_article_to,
"ArticleType", "webrequest",
"SenderType", "customer",
"HistoryType", "WebRequestCustomer",
"HistoryComment", "created from PHP",
"From", "some_customer@your_organization",
"Subject", "Some Subject",
"ContentType", "text/plain; charset=ISO-8859-1",
"Body", "Some Article Body text",
"UserID", some_userID_number,
"Loop", 0,
"AutoResponseType", 'auto reply',
"OrigHeader", array(
'From' => 'some_customer@your_organization',
'To' =>  'some_customer@your_organization',
'Subject' => 'Some Subject.  Probably the subject from above',
'Body' => 'Some Body text.  Probably the body from above'
),
)
);
[/code]

===============

TicketGet() 
Required Input Values: TicketID(integer)
Returns: Array of Age(integer), PriorityID(integer)ServiceID(integer), Type(text), Responsible(text), StateID(integer), ResponsibleID(integer), ChangeBy(integer), EscalationTime(integer), Changed(date/time), OwnerID(integer), RealTillTimeNotUsed(integer), GroupID(integer), Owner(text), CustomerID(text), TypeID(integer), Created(date/time), Priority(text), UntilTime(integer), EscalationUpdateTime(integer), QueueID(integer), Queue(text), State(text), Title(text), FirstLock(date/time), CreateBy(integer), TicketID(integer), StateType(text), EscalationResponseTime(integer), UnlockTimeout(integer), EscalationSolutionTime(integer), LockID(integer), TicketNumber(integer), ArchiveFlag(text), CreateTimeUnix(unixtime), Lock(text), SLAID(integer), CustomerUserID(text)

[code]
// PHP code sample for TicketGet().  Adjust the values as necessary
$TicketDetails = $client->__soapCall("Dispatch", 
array($username, $password,
"TicketObject", "TicketGet",
"TicketID", some_ticketID_number,
"Extended", 1,
));
[/code]

===============

TicketSearch()
Required Input Values: CustomerUserID(text)
Returns: Array of TicketID(integer), TicketNumber(integer)

[code]
// PHP code sample for TicketSearch().  Adjust the values as necessary
$TicketDetails = $client->__soapCall("Dispatch", 
array($username, $password,
"TicketObject", "TicketSearch",
"CustomerUserID", "some_customers_login",
));
[/code]

One additional thing to note.  Both of the last two functions return arrays of values, rather than a single value.  You might want to look at my post about how to parse the values into a usable array.

Jeff Eske

SEE ALSO:
OTRS – Simple Web Service Example Using PHP,

PHP Script to Display SOAP Requests and Responses,

OTRS – TicketGet() Web Service Example in PHP

OTRS – TicketGet() Web Service Example in PHP

OTRS,Web Services,Web Stuff — Jeff Eske on March 5, 2013 at 11:42 am

UPDATED:  I’ve changed employers and have moved on to other projects.  I no longer use OTRS, or have access to OTRS, so I won’t really be able to help you beyond what I’ve already posted here. 

Jeff

Continuing on with my studies of OTRS web services, I’ve created a page that will pull an OTRS ticket back when supplied with the ticket’s ID via GET.  Prior to this I posted how to create a ticket using the OTRS TicketCreate() SOAP function. Basically, you give the page the ticket ID via the URL – http://webserver/get_ticket.php?id=xx. I’ve included a complete ticketGet zip file at the end.  In addition to this example, I have another post explaining how to submit a ticket via web services.

Basically, all that’s required is passing one argument, the TicketID, and you can get back ALL of the ticket details.  It’s actually much more straightforward than I assumed that it would be.  One thing that I noticed is that reading through the OTRS dev documentation, the order that the ticket details are returned is different than what actually comes back.  That’s not really a big deal, since I moved everything into an array, with the various ticket details saved as a key/value pair.  More on that later.  The example that I have here only returns the ticket, but it is possible to return the associated articles also, but that will be for a later post.

The actual soapCall() function looks like this:

[code]
$TicketDetails = $client->__soapCall("Dispatch", 
array($username, $password,
"TicketObject", "TicketGet",
"TicketID", $TicketID,
));
[/code]

All I’m passing in is the SOAP username and password, along with the TicketID.  What it returns then is an XML-formatted response.  My page parses all of the returned values into an array, by using a foreach loop.  There are probably much more elegant solutions, but this works. Because of the way OTRS returns things, my foreach loop is a little janky.  Like I said, there’s probably a more elegant solution.

Without further ado, here’s the foreach loop:

[code]

$ticketInfo = array();
$i = 0;
foreach ($TicketDetails as $name => $value){
    if (false !== strpos($name, "s-gensym")){
        $temp[$i] = $value;
        $v = $temp[$i-1];
        //echo $value."<br>";
        if($i % 2 != 0){
            $ticketInfo[$v] = $value;
        }
        $i++;
    }
}
[/code]

As I said – a little janky.  Anyway, basically what OTRS does it returns the detail’s name as a variable, then the detail’s value as the NEXT variable like: “Age”, “123421”, “Title”, “This is my ticket title”, “TicketID”, “2”, so basically, you get the detail name, then the detail value.  To get these into a usable format, I’m basically creating 2 arrays, $temp[] and $ticketinfo[].  Since I’m simple-minded, the easiest thing for me to do was to create the $temp[] array so that I could basically use it as the “key” array when populating the $ticketinfo[] array.  Then what I’m doing is basically putting things into the $ticketinfo[] array as key/value pairs.  I take the current value – $value and put it in as the value and use the previously returned value, from $temp[], as the key.

I’ve included the complete commented code for the page below.  You can copy/paste it into a new, blank page, or you can download the zipped version of the file below.

[code]
<?PHP
error_reporting(E_ALL);
#### OTRS specific information ####
$url = "http://your_otrs_server/otrs/rpc.pl"; // URL for OTRS server
$username = "SOAP_username"; // SOAP username set in sysconfig
$password = "SOAP_password"; // SOAP password set in sysconfig
$TicketID = $_GET[id];
########################################################################
#### You don't have to change anything below here, although you can ####
########################################################################
#### Initialize new client session ####
$client = new SoapClient(
 null, 
 array(
 'location' => $url,
 'uri' => "Core",
 'trace' => 1,
 'login' => $username,
 'password' => $password,
 'style' => SOAP_RPC,
 'use' => SOAP_ENCODED
 )
);
#### Create and send the SOAP Function Call ####
$TicketDetails = $client->__soapCall("Dispatch", 
array($username, $password,
"TicketObject", "TicketGet",
"TicketID", $TicketID,
));
#### Get the SOAP response into an array as key/value pairs ####
# This is kind of janky, but what it does is parse out the #
# detail values in the SOAP response and writes them as a key/value #
# pair in the $ticketInfo[] array. #
$ticketInfo = array();
$i = 0;
foreach ($TicketDetails as $name => $value){ // explode the xml response
 if (false !== strpos($name, "s-gensym")){
 $temp[$i] = $value; 
 $v = $temp[$i-1]; 
 if($i % 2 != 0){ 
 $ticketInfo[$v] = $value; 
 }
 $i++;
 }
}
##############################################################################
#### The code below here is just to provide viewable proof that it worked ####
#### It can all be commented out or removed ####
##############################################################################
#### Return the SOAP request and response as xml-formatted text ####
print "<pre>\n"; 
print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n"; 
print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n"; 
print "</pre>";
echo"<hr width='200'>";
// Spew out the key/value pairs from the $ticketInfo[] array
foreach ($ticketInfo as $name => $value){
 echo "<b>".$name.":</b> ".$value."<br>";
}
?>
[/code]

Here’s the ticketGet zip file.  The formatting is obviously better in that version than what you see above.

Jeff Eske

 

PHP Script to Display SOAP Requests and Responses

Programming,Web Services,Web Stuff — Jeff Eske on March 5, 2013 at 10:15 am

Some time back, while working out web services on another project, I put together a janky little snippet of PHP code that’s actually pretty handy when dealing with SOAP-based web services.  For me, the hardest part of working with web services is trying to figure out exactly what the request needs to look like to work correctly.  The other thing is figuring out exactly what I got back!  This little snippet actually shows you what the xml-formatted SOAP request and SOAP response each look like.  The REALLY nice thing is that it only takes 4 lines of code.

Here’s what it looks like:

[code]
print "<pre>\n";
print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n";
print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n";
print "</pre>";
[/code]

Basically, all you do is plug this in after you’ve created your new SoapClient() object and performed the soapCall().  A basic example would look like the code below.  Please note, this isn’t a working piece of code, just an illustration of how it would look.

[code]
$client = new SoapClient(
 some client specifics here
);
$SomeSoap = $client->__soapCall(
  do some SOAP function
);
print "<pre>\n";
print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n";
print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n";
print "</pre>";

[code]

What this should get you, when you run the script, is two separate, preformatted lines of text.  The first line will be the XML-formatted request that PHP sent to the web service.  The second line should be the XML-formatted response returned.  Granted, this doesn’t necessarily give you the final format that you need, but it will get you names of all of the XML variables that have been returned.  With that information, you can proceed to find a way to extract the information that you need.

Stay tuned for more on this subject.

Jeff Eske

Dogbert Ergonomic Consulting Co. on Standing Desks

General — Jeff Eske on February 28, 2013 at 8:55 am

Dilbert 2013-02-27

Dogbert got it right.  It’s not that complicated.  Over a year and a half in and still standing.

Jeff Eske

OTRS – Mobile Front-end

OTRS,Programming,Web Stuff — Jeff Eske on February 19, 2013 at 1:30 pm

I’m in the process of creating a mobile front-end for OTRS.  There are a couple of decent apps out there that can be used on iOS and Android, but I decided to create a completely HTML-based version, just because I can.  I’ll post a video of the progress so far.

Stay tuned.

UPDATE: I have a link to a short video that shows it in action below.  Click on the image to view the video.

In the video, I’m accessing the mobile pages on my old Motorola Droid X.  I’ve tested it on the Droid, as well as an iPhone 4S (being used to take the video) and an iPad.  Since it’s really basic HTML, it works great on all of them.

 

OTRS Mobile front-end walkthrough

OTRS Mobile front-end walkthrough

It’s still very much a work-in-progress.  Currently, it’s “read-only”.  I’m in the process of adding two-way functionality, utilizing OTRS web services.

Jeff Eske

Homemade Leather iPhone Case

General — Jeff Eske on February 6, 2013 at 5:10 pm

When I got my iPhone 4s for work, I needed to get some type of case for it.  What I started out with, was a basic case from Incipio.  The case worked great, but after a while, I realized that I needed a case that could actually carry some ID cards as well.  There are doors, as well as parking lot access gates here at work that require a swipe card for access.  I originally just carried the cards in my fancy homemade leather wallet, but that meant that I had to pull my wallet out every time.

Rather than buying an iPhone case that included a card pocket, I decided to make one.  I had already made a watch band and a wallet, so why not a phone case?  The band and the wallet were both hand-stitched, since the leather was pretty thick, but phone case leather was thin enough that I decided to give my old (OLD) Singer a run at it.  It worked perfectly.  Now, I can keep my work-related access cards together with my work-related phone.  It will comfortably hold the phone, plus a couple plastic cards and a business card or two.

Jeff Eske

iPhone case with the iPhone and cars in it.

iPhone case with the iPhone and cards in it.

 

iPhone case empty.

iPhone case empty.

 

« Previous PageNext Page »
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. | Jeff's Blog