Developer Blog

API - Creating and Listing Tickets

in API, Public

Here is another example using our API. This one shows how to create a user from an SSO token, then use that user to create a ticket. Finally we will then list out the tickets.

# helper method
def symbolize_hash(hash)
  symbolized_hash = {}  
  # puts hash.inspect
  
  hash.each do |key, value|
    symbolized_hash[key.to_sym] = value
  end
  return symbolized_hash
end

consumer = OAuth::Consumer.new(KEY, SECRET)

puts "Get request token"
response = consumer.request(:get, "#{SITE}/api/v1/oauth/request_token.json")
request_token_hash = JSON.parse(response.body)
puts request_token_hash

request_token = OAuth::RequestToken.from_hash(consumer, 
   symbolize_hash(request_token_hash["token"]))

# this is just a library we use to create SSO tokens, similar code 
# snippets can be found under the SSO docs here
encoder = Sso::Schemes::AesCbc128::Base64Encoder.new(SUBDOMAIN, API_KEY)

# create the SSO token setting the user to be an admin so 
# we can list the tickets back later
sso_token = encoder.process({ 
  :guid => "test@test.com",
  :expires => "2012-12-31",
  :email => "test@test.com",
  :avatar_url => "http://external.com/users/1.png",
  :display_name => "Testie McTest",
  :admin => "accept"
})

# get the access token for this new user
response = consumer.request(:post, "#{SITE}/api/v1/oauth/authorize.json", nil, {}, {
  :sso => sso_token, :request_token => request_token_hash["token"]["oauth_token"]
})
user_hash = JSON.parse(response.body)
access_token = OAuth::AccessToken.from_hash(consumer, symbolize_hash(user_hash["token"]))

# create the params for the ticket
ticket = {
  "ticket[message]" => "Everything is broken......",
  "ticket[subject]" => "Help!!!"
}

# create a ticket
response = access_token.request(:post, "#{SITE}/api/v1/tickets.json", ticket)
body = JSON.parse(response.body)

# get our ticket 
response = access_token.request(:get, "#{SITE}/api/v1/tickets.json?per_page=1")
body = JSON.parse(response.body)

puts body["tickets"][0].inspect

~ Scott


API - Creating a Forum

in API

A recent question to our support was how to use 2-legged OAuth to create a new forum, so as the first in a series of api examples here is some code to do exactly that:

#! /usr/bin/env ruby

require 'rubygems'
require "oauth"
require 'json'

# Trusted Client
KEY = 'CLIENT KEY'
SECRET = 'CLIENT SECRET'
SITE = 'http://your_subdomain.uservoice.com'

consumer = OAuth::Consumer.new(KEY, SECRET, :http_method => :post)
access_token = OAuth::AccessToken.new consumer

forum = {
  "forum[name]" => 'Exciting New Stuff'
}

response = access_token.post("#{SITE}/api/v1/forums.json", forum)
forum_hash = JSON.parse(response.body)

puts forum_hash.inspect

And that, as they say, is that!!! Simple huh?

~ Scott

API - Creating a User

in API, Public

Another question that has cropped up a few times is how to create a user and obtain an access token to then act on behalf on that user with. We have made this very simple (we hope) and here is an example:

#! /usr/bin/env ruby

require 'rubygems'
require "oauth"
require 'json'

def symbolize_hash(hash)
  symbolized_hash = {}  
  puts hash.inspect
  
  hash.each do |key, value|
    symbolized_hash[key.to_sym] = value
  end
  return symbolized_hash
end

# Trusted Client
KEY = 'CLIENT_KEY'
SECRET = 'CLIENT_SECRET'
SITE = 'http://your_subdomain.uservoice.com'

consumer = OAuth::Consumer.new(KEY, SECRET)

response = consumer.request(:get, "#{SITE}/api/v1/oauth/request_token.json")
request_token_hash = JSON.parse(response.body)
puts request_token_hash

request_token = OAuth::RequestToken.from_hash(consumer, 
   symbolize_hash(request_token_hash["token"]))

user = {
  "user[display_name]" => 'Scott Test',
  "user[email]" => "scott@test.com",
  "request_token" => request_token.token
}

response = consumer.request(:post, "#{SITE}/api/v1/users.json", nil, {}, user)
user_hash = JSON.parse(response.body)

puts user_hash
access_token = OAuth::AccessToken.from_hash(consumer, symbolize_hash(user_hash["token"]))

puts "Create user: #{user.inspect}"
puts "Obtained accessToken: #{access_token.inspect}"
puts "Key: #{access_token.token}"
puts "Secret: #{access_token.secret}"

~ Scott

Ops Guy Corner: MySQL cloud backup solution

in Ops

I’m Kevin, and I wanted to take a couple minutes to introduce myself and talk a little about the state of operations when I first came to UserVoice. I was hired on as the sole Operations Engineer. It sounds like a fancy title, but it really means I wear many different hats. On top of handling the day-to-day operations of our systems, I’m the DBA (oh no!), the network guy, the office IT guy, and, of course, the resident geek. Whether it be the WiFi interference in our loft office, our MongoDB installation, or the water cooler that was oddly plugged into a battery-backed UPS, I’ve been fixing problems since I got here.

My first real task here at UserVoice was to come up with a backup solution for our MySQL database. To implement a quick hack, I wrote a bash script that would do the necessary work which would run from ‘cron’ once a day. As we already had a master/slave setup with our database, it was simple to take a ‘mysqldump’ of the slave database. The basics of the script are:

mysqldump thisisourdbname | gzip -9 > /backups/mysql_dump-`date +%m%d%y-%H%M`.sql.gz

This ran successfully from ‘cron’ for a few days, until I noticed the disk was filling up too quickly. I needed to come up with something better and more robust. I also needed a more permanent storage solution, as well as a rotation plan, so I wouldn’t have to manually rotate the backups.

We already use Amazon S3 for different things here at UserVoice, making it easy to create a new bucket in our existing account to dump our backups in. But, before I put our entire database in the cloud, I wanted to make sure it was encrypted with a password, split into multiple files for easy upload and retrieval, and compressed as much as possible. I chose the 7z archive file format, which uses the LZMA compression algorithm, because it met all these requirements and it’s free, open source, and cross-platform. I added the following to my existing bash script to include the needed compression/splitting/encrypting:

mysqldump thisisourdbname | 7z a -si -v250m -psillypass /backups/mysql_dump-`date +%m%d%y-%H%M`.sql.7z

This further compressed our dumps, and split them into nice 250 meg volumes (except that it took about 4.5 hours to complete the dump, during which the slave wouldn’t replicate any data from the master). This was obviously not good, so I tweaked it a bit. I fixed that by running the dump and compressing it a little bit first with:

DATETIME=`date +%m%d%y-%H%M` mysqldump thisisourdbname | gzip -1 > /backups/mysql_dump-$DATETIME.sql.gz

...then uncompressing it while compressing it again into 7z format:

gzcat /backups/mysql_dump-$DATETIME.sql.gz | 7z -si -v250m -psillypass /backups/mysql_dump-$DATETIME.sql.7z && rm -f /backups/mysql_dump-$DATETIME.sql.gz

This shortened the ‘mysqldump’ portion of the process to only 30-40 minutes. I was comfortable with these figures and ready to wrap it up, all the while including weekly uploads to Amazon S3.

I polished my Ruby skills and wrote a rudimentary script that uses the ‘aws-s3’ library to read a list of files as arguments from the command line that uploads to a bucket on our Amazon account. To easily run this script once a week from ‘cron’:

find /backups -name \*.7z.\* -type f -mtime -1 | xargs s3_backup.rb

This will find all the files modified in the last day, matching the 7z pattern used when creating volumes, then send it to my S3 script as command line arguments care of ‘xargs’. The S3 script handles the upload and notifies the rest of the team via a Campfire notification.

This isn’t a perfect solution yet, but works just fine if you monitor the disk usage. I have yet to implement the automatic rotation, but plan on using 'logrotate' to rotate and manage backup files on the database server. I will also create another host with more space and daily ‘rsync’ the /backups folder for archiving and weekly backups to S3.

This is all part of the excitement that goes on here at UserVoice. I’ll continue to update you on my progress and all fun problems I get to work out. I’d love to hear your feedback about this subject, or if you have any suggestions for further discussion topics.

~ Kevin

How To Build An eCommerce Site in 10 Minutes!

in

As the videos are now available of the keynotes from the excellent MIX11 conference in Las Vegas, we thought it would be good to highlight this one (demo starts at around 1:16) where Drew Robbins from Microsoft shows just how easy it is to use Orchard to build an online store (a flower store in fact) complete with a shopping cart from Amazon and a rather fantastic feedback and support tool from UserVoice...... So, why a flower store? I'll let Drew answer that:

"Well, it's spring and people are planting flowers, and so it's something we need to get online quickly so we can not miss the opportunity. Orchard CMS is going to let us focus on the business value rather than worrying about building all the infrastructure for our site."

If you don't have time to watch the whole video it is all transcribed lower on the page as well, pretty sure that's the fastest I've seen something like that created...... definitely worth a play!


-Scott Rutherford
Co-Founder, UserVoice

Microsoft Releases Orchard V1.1 Complete With UserVoice Widget

in

We are very excited today to be part of the launch of V1.1 of the Orchard web development platform taking place at Microsoft's MIX Conference at the Mandalay Bay in Las Vegas

Orchard is a free, open source project aimed at delivering a highly modular and extensible CMS (Content Management System) using the Razor syntax.

Orchard was originally shipped in January of this year by the OuterCurve Foundation who simultaneously released an online gallery for Orchard modules and themes. This gallery is itself open source and is used to power other .NET community websites such as NuGet and Blogengine.net

The UserVoice widget builds on the existing UserVoice WebMatrix libraries and code but adds the ability to switch between the new range of UserVoice products Feedback, Helpdesk and Full Service. The widgets module contains two widgets that let you add UserVoice functionality to your website built on Orchard CMS.

  1. Feedback - the feedback widget adds the feedback tab to your site. This allows visitors to click the UserVoice feedback tab to share ideas, ask questions or contact you via the UserVoice interface.
  2. Suggestions - the suggestions widget provides a list of recent/popular suggestions that you can display as content on a page.

The gallery page for the UserVoice widget can be found here

And the codeplex site can be found here

UserVoice Wordpress Plugin Updated - using our brand new API!

in API, Widgets

We had an API. It was ok. People built some things for it, including a Wordpress plugin. As time went on, Shane and Peter, the third-party developers of this plugin got busy (which is pretty reasonable) and the quality of the plugin declined. Nobody tackled it again because, well, our API was ok.

As you may have noticed, we’ve launched a new API. It’s awesome. We-built-our-whole-Facebook-app-with-it awesome. And we’re very excited to see third parties start to sink their teeth into it.

A company called Mediaslurp has done just that, and we’re delighted that thanks to their hard work the UserVoice Wordpress Plugin is updated and better than ever. MediaSlurp targets multimedia content such as real-time streams and audio and video podcasts, and brings them together in an interface for users to find content relative to them, and easily play that content. Getting customer feedback is key for them, and they decided to dive into the new API to see if they couldn’t get the Wordpress plugin working. Says Mediaslurp’s TJ Downes:

“Working with the UserVoice API is really straightforward. Anyone who has worked with REST APIs should be able to quickly and easily implement the UserVoice API. We've had no difficulty understanding the API and picking up where Shane and Peter left off. Given that the API is so simple to use, we expect to expand on the functionality included in the UserVoice Idea List Widget in the near future. Since the API also delivers the data in JSON format, we expect that it will be very simple to implement real-time updates of the UserVoice data via AJAX and Flash applications.”

Swing by the Wordpress plugin page to pick up your very own UserVoice Wordpress plugin. Interested in building your own UserVoice widget? Check out the documentation links right here on developer.uservoice.com, and drop us a line at support[at]uservoice.com if you have any questions, comments, or ideas. We want to help you do awesome stuff.

product screenshot

Create a UserVoice account

Discover how easy it can be to provide great customer service

Try it for free