<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">

<channel>
    
<title>Developer Blog</title>
<link>http://developer.uservoice.com//blog</link>
<description />
<dc:language>en</dc:language>
<dc:creator>raimo@uservoice.com</dc:creator>
<dc:rights>Copyright 2012</dc:rights>
<dc:date>2012-02-06T20:50:23+00:00</dc:date>
<admin:generatorAgent rdf:resource="http://expressionengine.com/" />
    

<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/uservoice/GxpH" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="uservoice/gxph" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
<title>Upgrading to Rails 3: Printing Escaped Strings</title>
<link>http://developer.uservoice.com/blog/post/upgrading-to-rails-3-printing-escaped-strings</link>
<guid>http://developer.uservoice.com/blog/post/upgrading-to-rails-3-printing-escaped-strings</guid>
<description>
<![CDATA[
<p>As the release of Rails 4 is <a href="http://weblog.rubyonrails.org/2011/12/20/rails-master-is-now-4-0-0-beta">coming closer</a>, many people are still considering to upgrade from Rails 2 to 3. One the most challenging issues in this upgrade is handling the issues arising from the XSS protection in Rails 3. According to OWASP, <a href="https://www.owasp.org/index.php/Top_10_2010-A2">XSS was the second-largest security risk of web applications in 2010</a>. Therefore Rails 3 defaulting to escape all custom strings is a really useful pattern. However, if your application is large and you have plenty of places you are printing HTML, you need to figure out a good process for ensuring all the strings get printed as expected after the upgrade.</p>

<p>Installing rails_xss in Rails 2 is a very good method to see how the XSS protection is going to change things after the upgrade to Rails 3. Depending what kind of content management system solutions, asset packaging tools or helper methods you are using, you can have problems in a plethora of different places. As a developer solving these issues in UserVoice, I would like to share my process for the XSS protected strings handling.</p>

<p>Typically problems that arise look like this. To solve them all, first step is to identify the different types of problems. Reserve some time for this, as there might be tens of different problem patterns, which all might not be easy to find.</p>

<p><img src="http://developer.uservoice.com/resources/votes.png" /></p>

<h1> The Process </h1>

<p>Here I explain how I approached the problem and present some lessons learned during the process. This is not a definitive guide on the subject, but a rather a set of principles which I recommend to be applied during and after the rails_xss installation. </p>

<h2>1. Install rails_xss</h2><p> </p>

<p>Install <a href="http://rubygems.org/gems/rails_xss">rails_xss</a> and its dependency (<a href="a href="http://rubygems.org/gems/erubis">erubis</a>). After this, your Rails 2 application escapes all your &#8220;unsafe&#8221; strings by default. Explore your application and run tests to see on a general level how serious problems the default HTML escaping causes.</p>

<h2>2. Identify the Problems</h2>

<p>You should identify all the different types of problems and address each problem with a solution. While testing and reviewing the codebase of UserVoice, I identified many different problem patterns. I have described some of the most common ones:</p>

<h3>2.1 Custom Helpers</h3>

<p>For example, the return value of these kind of helpers can be marked html_safe by calling .html_safe. In this case it&#8217;s even better to use the Rails helper link_to, whose return value is html_safe by default. Additionally, you don&#8217;t have to worry about escaping the name of the user separately using the <strong>h</strong> method.
</p><pre>
  def user_link(user)
    "&lt;a href=#{user.url}&gt;#{<strong>h(</strong>user.name<strong>)</strong>}&lt;/a&gt;"<strong style='color: green;'>.html_safe</strong>
  end

  # better:<strong style='color: green;'>
  def user_link(user)
    link_to(user.name, user.url)
  end</strong>
</pre>

<h3>2.2 Printing Conditional Strings in Views</h3>

<p>Often you want to print a certain string depending on some condition. In these cases the resulting string must be marked html_safe. Possibly you also want to extract a commonly occurring pattern in your codebase to its own helper.
</p><pre>
  &lt;span &lt;%= 'style="display: none"'<strong style='color: green;'>.html_safe</strong> unless content.visible? %&gt; &gt;
    Content shown if content.visible?
  &lt;/span&gt;
</pre>

<h3>2.3 Concatenating Strings in Views</h3>

<p>Your view files might include concatenation of unsafe and safe strings like this.</p>

<pre>
  &lt;%= '&lt;hr /&gt;'<strong style='color: green;'>.html_safe</strong> + link_to('User Information', user_path(user)) %&gt;
</pre>

<p>By default, unsafe + safe results in an unsafe string, which means that the link above gets unexpectedly escaped. To prevent this, &#8216;&lt;hr /&gt;&#8217; can be marked html_safe or even better, just extract it out side the ERB interpolation tag. </p>

<h3>2.4 Printing Custom User-Defined HTML</h3>

<pre>
  &lt;%= user.custom_html<strong style='color: green;'>.html_safe</strong> %&gt;
</pre>

<p>In these cases you need to mark the user-defined HTML html_safe. At the same time, you should also ensure that the user input is sanitized, because you do not want to allow printing arbitrary HTML in your views. A good sanitizing includes defining the set of allowed tags and denying any others. Using a good and well-tested library for sanitizing HTML is also a good idea, unless you really know what you are doing, which you most probably are not.</p>

<h2>3. Design a Strategy</h2>

<p>When identifying all the various cases of printing HTML, JSON and HTML entities, you might start to wonder how to cover all the cases in all your application&#8217;s views. The short is answer is that 100% coverage requires probably too much effort. However, there are many ways how you can come close to that. <a href="https://www.owasp.org/index.php/Top_10_2010-A2">OWASP</a> states about XSS vulnerability finding: &#8220;complete coverage requires a combination of manual code review and manual penetration testing, in addition to any automated approaches in use&#8221;.</p>

<h3>3.1 Custom Automated Tool</h3>

<p>Now that rails_xss had escaped all the output strings by default, I needed to find the places where HTML has been doubly-escaped. So I thought it wouldn&#8217;t hurt to write a utility method for matching the doubly-escaped HTML strings:</p>

<pre>
class HtmlDoubleEscapeReporter
  def self.assert_sane(str)
    if (str.match(/&amp;lt;[a-z]/) || str.match(/&amp;amp;(quot|rarr|larr|amp|#)/)) &amp;&amp; 
        !str.match(/looks something you do not want to print/
      send_problem_report('#{str}' looks something you do not want to print")
    end
    return str
  end
end
</pre>

<p>This basically recognizes some commonly occurring strings when HTML has been accidentally escaped twice (as usually you don&#8217;t want to print this). Depending on the application, the regular expressions might be much different but the basic idea stays the same. The idea is not to have a fully-functional problem analysis tool, but to just report about any suspicious strings which the team can check and fix if necessary. The method <strong>send_problem_report</strong> represents a method which reports the problem using e.g. Airbrake or ExceptionNotifier if it happens on a deployed application instance. It could also open a debugger using <a href="http://rubygems.org/gems/ruby-debug">ruby-debug</a> by calling <strong>debugger</strong>. When the debugger line is reached when running tests, you are immediately able to see the backtrace to determine if there is a problem or not. Another way is of course throwing an exception, which would print nice error in your CI system and send an exception report in testing environments. This is useful during manual testing, as testers might not notice all the problems.</p>

<p>Notice also the <strong>!str.match(/looks something you do not want to print/</strong> part in the if condition. This prevents situations where the error message is used in another sanity check causing an infine loop. Whether this is possible or not, depends on your codebase, however, this occurred to me a couple of times. This check prevents that from happening.</p>

<p>The tricky part is, when to call this method? One solution is to hook it in all HTML printing code by alias_method_chaining <strong>simple_format</strong>, <strong>content_tag_string</strong> and  <strong>link_to</strong>, which are the ones rails_xss also chained.</p>

<pre>

module ActionView
  module Helpers
    module TextHelper

      def simple_format_with_double_escape_reporting(*args)
        HtmlDoubleEscapeReporter.assert_sane(simple_format_without_double_escape_reporting(*args))
      end
      alias_method_chain :simple_format, :double_escape_reporting
    end

    module TagHelper
      private
      def content_tag_string_with_double_escape_reporting(*args)
        HtmlDoubleEscapeReporter.assert_sane(content_tag_string_without_double_escape_reporting(*args))
      end
      alias_method_chain :content_tag_string, :double_escape_reporting
    end
    module UrlHelper
      def link_to_with_double_escape_reporting(*args, &amp;block)
        HtmlDoubleEscapeReporter.assert_sane(link_to_without_double_escape_reporting(*args, &amp;block))
      end
      alias_method_chain :link_to, :double_escape_reporting
    end
  end
end
</pre>

<p>Remember, that this kind of hooking might not work for your application, so plan and test carefully.</p>

<h3>3.2 Manual Testing</h3>

<p>In addition to this automated check, you most definitely want to run adequate manual regression tests on your application and involve several people in testing. Additionally, every time you find a problem, you want to grep the whole application for similar cases, as usually these problems exist in many places.</p>

<h3>3.3 Code Review</h3>

<p>Grepping all the code for suspicious patterns might not always be enough. Therefore you should review the code as much as possible. After seeing various problem situations, you have the best knowledge and &#8220;eye&#8221; for the problems that might still be hidden in the code. Therefore reading as much code through as possible is a highly recommendable practice in addition to automated and manual testing. Just because testing everything is often impossible.</p>

<h2>4. Execute your Strategy</h2>

<p>Follow your strategy and make notes on the progress. After completing all the planned steps, instruct your whole team on how to keep the application XSS safe using the new tools which you installed. This helps to keep the application both functional and secure in the future.</p>

<p><b>~ Raimo</b></p>
<p><br/>
</p>
]]>
</description>
<dc:date>2012-02-06T20:50+00:00</dc:date>
</item>

<item>
<title>Customizing colors in the iOS SDK</title>
<link>http://developer.uservoice.com/blog/post/customizing-colors-in-the-ios-sdk</link>
<guid>http://developer.uservoice.com/blog/post/customizing-colors-in-the-ios-sdk</guid>
<description>
<![CDATA[
<img src="http://developer.uservoice.com/resources/uservoice_iphone_colors.png" style="float: right; width: 270px; height: 404px;"><p>Today I wanted to talk about another feature we've added to the <a href="https://github.com/uservoice/uservoice-iphone-sdk">iOS
SDK</a> that I didn't cover
before: custom stylesheets. Since you are integrating UserVoice into your app,
we thought it would be good for you to have an easy way to tweak the look and
feel to match your existing UI a bit better. To do this, we extracted most of
the colors that our UI works with into a UVStyleSheet class, and added a simple
API that allows you to substitute your own stylesheet.</p>

<p>To create a custom stylesheet, add a new Objective-C class to your project and
call it something like <code>CustomUVStyleSheet</code>. Make it a subclass of <code>UVStyleSheet</code>.
Then you can override any of the instance methods of UVStyleSheet to provide
your own colors. Here's a simple example:</p>

<p><pre><code>
#import "CustomUVStyleSheet.h"

@implementation CustomUVStyleSheet

- (UIColor *)backgroundColor {
    return [UIColor colorWithRed:0.15f green:0.15f blue:0.15f alpha:1.0f];
}

- (UIColor *)darkZebraBgColor {
    return [UIColor colorWithRed:0.1f green:0.1f blue:0.1f alpha:1.0f];
}

- (UIColor *)lightZebraBgColor {
    return [UIColor colorWithRed:0.15f green:0.15f blue:0.15f alpha:1.0f];
}

@end
</code></pre></p>

<p>Then, all you have to do is to pass your stylesheet to the SDK before launching UserVoice.</p>

<p><pre><code>
[UVStyleSheet setStyleSheet:[[[CustomUVStyleSheet alloc] init] autorelease]];
</code></pre></p>

<p>And with that, you should be able to run your app and see custom colors
throughout the UserVoice UI! You can find a complete list of the colors you can
override in <code>UVStyleSheet.h</code>, with explanations of how they are used.</p>
<p><strong>-Austin Taylor<br />
Developer, UserVoice</strong></p>

]]>
</description>
<dc:date>2012-01-18T16:00+00:00</dc:date>
</item>

<item>
<title>iOS SDK hits 1.0</title>
<link>http://developer.uservoice.com/blog/post/ios-sdk-hits-1.0</link>
<guid>http://developer.uservoice.com/blog/post/ios-sdk-hits-1.0</guid>
<description>
<![CDATA[
<p>Our <a href="https://github.com/uservoice/uservoice-iphone-sdk">iOS SDK</a> has been
available as a public beta for quite a while. We've gotten some great feedback
from you guys, and I've been working hard over the last few weeks to fix all of
the known bugs and layout issues. We're finally ready to make it 1.0!</p>

<p>At the same time we are announcing that the SDK now supports the iPad!
Landscape mode on the iPhone is now ready to use as well.</p>

<p>In addition to polishing the SDK itself, we have released an <a href="https://github.com/uservoice/uservoice-iphone-example">example iOS
app</a> on GitHub showing
how to use it. We think this will make it a lot easier for you to get
everything set up correctly in XCode.</p>

<p>To get started, download the example project and pull down the SDK. Replace the
demo URL with your own UserVoice site. Log into your UserVoice account and add
an iOS app under Settings -&gt; Channels -&gt; iOS Apps. Copy the API key and secret
into the example codebase. That should be all you need to do to see your own
feedback forum in the example app.</p>

<p>To set up the SDK in your existing app, you will need to do the following things.</p>

<ul>
  <li>Run XCode 4.2 (there is an XCode 3 branch, but it is not up to date)</li>
  <li>Have your project inside an XCode workspace</li>
  <li>Download the SDK and drag it into your workspace</li>
  <li>Add <code>libUserVoice.a</code> under the <code>Link Binary With Libraries</code> build phase</li>
  <li>Set <code>User Heading Search Paths</code> to <code>$(BUILD_PRODUCTS_DIR)</code></li>
  <li>Set <code>Always Search User Paths</code> to <code>Yes</code></li>
  <li>Add <code>-ObjC</code> and <code>-all_load</code> to the <code>Other Linker Flags</code> setting</li>
  <li>
    Drag the <code>Include</code> group from the SDK into your project
    <ul>
      <li><code>Create groups for any added subfolders</code> should be selected</li>
      <li>Uncheck any targets</li>
      <li>You may want to rename the group something like <code>UVHeaders</code></li>
    </ul>
  </li>
  <li>
    Drag the <code>Resources</code> group from the SDK into your project
    <ul>
      <li><code>Create groups for any added subfolders</code> should be selected</li>
      <li>Add to your target</li>
      <li>You may want to rename the group something like <code>UVResources</code></li>
    </ul>
  </li>
</ul>

<p>Once you have completed these steps, you are ready to launch the UserVoice UI
from your code. Import <code>UserVoice.h</code> and call one of the three methods on the
UserVoice class.</p>

<p><strong>1. Standard Login:</strong> This is the most basic option, which will allow users to
either sign in, or create a UserVoice account, from inside the UserVoice UI.
This is ideal if your app does not have any information about the user.</p>

<p><pre><code>
[UserVoice presentUserVoiceModalViewControllerForParent:self
                                                andSite:@"YOUR_USERVOICE_URL"
                                                 andKey:@"YOUR_KEY"
                                              andSecret:@"YOUR_SECRET"];
</code></pre></p>

<p><strong>2. SSO for local users:</strong> This will find or create a new user by passing a name,
email, and unique id.  However, it will only find users that were previously
created using this method. It will not allow you to log the user in as an
existing UserVoice account. This is ideal if you only want to use UserVoice
with your iOS app.</p>

<p><pre><code>
[UserVoice presentUserVoiceModalViewControllerForParent:self
                                                andSite:@"YOUR_USERVOICE_URL"
                                                 andKey:@"YOUR_KEY"
                                              andSecret:@"YOUR_SECRET"
                                               andEmail:@"USER_EMAIL"
                                         andDisplayName:@"USER_DISPLAY_NAME"
                                                andGUID:@"GUID"];
</code></pre></p>

<p><strong>3. UserVoice SSO:</strong> This is the most flexible option. It allows you to log the
user in using a <a href="http://developer.uservoice.com/docs/single-sign-on-how-to">UserVoice SSO
  token</a>. This is
ideal if you are planning to use single signon with UserVoice across multiple
platforms. We recommend you encrypt the token on your servers and pass it to
the iOS app.</p>

<p><pre><code>
[UserVoice presentUserVoiceModalViewControllerForParent:self
                                                andSite:@"YOUR_USERVOICE_URL"
                                                 andKey:@"YOUR_KEY"
                                              andSecret:@"YOUR_SECRET",
                                            andSSOToken:@"SOME_BIG_LONG_SSO_TOKEN"];
</code></pre></p>

<p>We can't wait to see what you guys do with this! As always, we are eager to
hear your feedback on the <a href="http://feedback.uservoice.com/forums/64519-iphone-sdk-feedback">iOS SDK feedback forum</a>.</p>
<p><strong>-Austin Taylor<br />
Developer, UserVoice</strong></p>

]]>
</description>
<dc:date>2012-01-18T16:00+00:00</dc:date>
</item>

<item>
<title>UserVoice and JIRA 5.0 Preview</title>
<link>http://developer.uservoice.com/blog/post/uservoice-and-jira-5.0-preview</link>
<guid>http://developer.uservoice.com/blog/post/uservoice-and-jira-5.0-preview</guid>
<description>
<![CDATA[
<p>Thanks to the lovely people over at <a href="http://appfusions.com">AppFusions</a> we will soon have an awesome integration into Jira 5.0. To wet your appetite for that they have put together this video</p>

<p><iframe width="420" height="315" src="http://www.youtube.com/embed/2cuho9EvUwo" frameborder="0" allowfullscreen></iframe></p>

<p><b>~ Scott</b></p>
<br/>
]]>
</description>
<dc:date>2011-10-25T19:27+00:00</dc:date>
</item>

<item>
<title>Issues using RestSharp with UserVoice API</title>
<link>http://developer.uservoice.com/blog/post/issues-using-restsharp-with-uservoice-api</link>
<guid>http://developer.uservoice.com/blog/post/issues-using-restsharp-with-uservoice-api</guid>
<description>
<![CDATA[
<p>I've recently had a few people having issues with the <a href="http://restsharp.org">RestSharp</a> library for DotNet. Digging into the code for RestSharp if found that during the encoding process the values of parameters are correctly encoded but the names where being left. You can solve this by change line 161 in OAuth1Authenticator.cs from:</p>

<pre>
parameters.Add(new WebPair(p.Name, p.Value.ToString()));
</pre>
<br/>
<p>to</p>

<pre>
var encodedName = OAuthTools.UrlEncodeStrict(p.Name.ToString());
parameters.Add(new WebPair(encodedName, p.Value.ToString()));
</pre>
<br/>
<p>and recompiling RestSharp. The value is encoding later in the OAuth workflow in OAuthTools.cs. I suspect there is a neater solution, which I'll have a think about before submitting a pull request. In the meantime this will get you going. The part of the <a href="http://tools.ietf.org/html/rfc5849#page-18">spec</a> that refers to this states:</p>

<pre>
3.4.1.3.2.  Parameters Normalization

   The parameters collected in Section 3.4.1.3 are normalized into a
   single string as follows:

   1.  First, the name and value of each parameter are encoded
       (Section 3.6).
</pre>

<p><b>~ Scott</b></p>


]]>
</description>
<dc:date>2011-09-22T02:58+00:00</dc:date>
</item>

<item>
<title>Using Pivotal Tracker With UserVoice</title>
<link>http://developer.uservoice.com/blog/post/using-pivotal-tracker-with-uservoice</link>
<guid>http://developer.uservoice.com/blog/post/using-pivotal-tracker-with-uservoice</guid>
<description>
<![CDATA[
Our friends over at <a href="http://blogpig.com">BlogPig</a> have created a great integration between <a href="uservoice.com">UserVoice</a> and <a href="pivotaltracker.com">Pivotal Tracker</a>. You can see the code and some docs over on their GitHub page <a href="https://github.com/blogpig/uservoice-pivotal">here</a>. They also created this short video walk through showing the main features and how easy it is to setup:

<br/><br/>
<p><iframe width="560" height="315" src="http://www.youtube.com/embed/no_xwntzmF8" frameborder="0" allowfullscreen></iframe></p>
<p><b>~ Scott</b></p>
]]>
</description>
<dc:date>2011-09-20T20:14+00:00</dc:date>
</item>

<item>
<title>API - Creating and Listing Tickets</title>
<link>http://developer.uservoice.com/blog/post/api-creating-and-listing-tickets</link>
<guid>http://developer.uservoice.com/blog/post/api-creating-and-listing-tickets</guid>
<description>
<![CDATA[
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.

<br/><br/>
<pre>
# 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 <a href="http://developer.uservoice.com/docs/single-sign-on-how-to">here</a>
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
</pre>

<br/>
<p><b>~ Scott</b></p>
<br/>
]]>
</description>
<dc:date>2011-09-16T01:16+00:00</dc:date>
</item>

<item>
<title>API - Creating a Forum</title>
<link>http://developer.uservoice.com/blog/post/api-creating-a-forum</link>
<guid>http://developer.uservoice.com/blog/post/api-creating-a-forum</guid>
<description>
<![CDATA[
<p>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:</p>

<pre>
#! /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
</pre>

<br/>
<p>And that, as they say, is that!!! Simple huh?</p>

<p><b>~ Scott</b></p>


]]>
</description>
<dc:date>2011-09-07T23:46+00:00</dc:date>
</item>

<item>
<title>API - Creating a User</title>
<link>http://developer.uservoice.com/blog/post/api-creating-a-user</link>
<guid>http://developer.uservoice.com/blog/post/api-creating-a-user</guid>
<description>
<![CDATA[
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:

<pre>

#! /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}"
</pre>
<br/>
<p><b>~ Scott</b></p>
]]>
</description>
<dc:date>2011-09-07T23:03+00:00</dc:date>
</item>

<item>
<title>Ops Guy Corner: MySQL cloud backup solution</title>
<link>http://developer.uservoice.com/blog/post/mysql-cloud-backup-solution</link>
<guid>http://developer.uservoice.com/blog/post/mysql-cloud-backup-solution</guid>
<description>
<![CDATA[
<img src="http://developer.uservoice.com/resources/kevin.jpg" style="margin: 5px; float: right;"><p>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.</p>
<p>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:</p>
<p><code>
mysqldump thisisourdbname | gzip -9 > /backups/mysql_dump-`date +%m%d%y-%H%M`.sql.gz
</code></p>
<p>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.</p>
<p>We already use <a href="http://aws.amazon.com/s3/">Amazon S3</a> 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 <a href="http://en.wikipedia.org/wiki/7z">7z archive file format</a>, which uses the <a href="http://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm">LZMA compression algorithm</a>, 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:</p>
<p><code>
mysqldump thisisourdbname | 7z a -si -v250m -psillypass /backups/mysql_dump-`date +%m%d%y-%H%M`.sql.7z
</code></p>
<p>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:</p>
<p><code>
DATETIME=`date +%m%d%y-%H%M`
mysqldump thisisourdbname | gzip -1 > /backups/mysql_dump-$DATETIME.sql.gz
</code><p>
<p>...then uncompressing it while compressing it again into 7z format:<br /></p>
<p><code>
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
</code></p>
<p>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.</p>
<p>I polished my Ruby skills and wrote a rudimentary script that uses the <a href="http://amazon.rubyforge.org/">‘aws-s3’ library</a> 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’:</p>
<p><code>
find /backups -name \*.7z.\* -type f -mtime -1 | xargs s3_backup.rb
</code></p>
<p>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 <a href="http://campfirenow.com/">Campfire</a> notification.</p>
<p>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 <a href="http://linuxcommand.org/man_pages/logrotate8.html">'logrotate'</a> to rotate and manage backup files on the database server.  I will also create another host with more space and daily <a href="http://en.wikipedia.org/wiki/Rsync">‘rsync’</a> the /backups folder for archiving and weekly backups to S3.</p>
<p>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.</p>
<p><strong>~ Kevin</strong></p>
]]>
</description>
<dc:date>2011-06-03T21:46+00:00</dc:date>
</item>

    
</channel>
</rss>

