Hubboard/hubboard.rb

217 lines
5.9 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require 'rubygems'
require 'cgi'
require 'json'
require 'httparty'
require 'resin/app'
API_URL = 'https://api.github.com'
CONFIG_FILE = File.expand_path(File.dirname(__FILE__) + '/config/config.yml')
INPROGRESS_LABEL = 'in-progress'
COMMENT_FOOTER = "(*This message brought to you by [Hub board](http://hubboard.herokuapp.com/about)*)"
if Resin.development?
MYSELF = 'http://localhost:4567'
else
MYSELF = 'http://hubboard.herokuapp.com'
end
if File.exists? CONFIG_FILE
$config = YAML::load(File.open(File.expand_path(File.dirname(__FILE__) + '/config/config.yml')))
else
$config = {}
$config['github'] = {'id' => ENV['GITHUB_OAUTH_ID'], 'secret' => ENV['GITHUB_OAUTH_SECRET']}
end
module Hubboard
module Helpers
def validate_token
token = session[:access_token]
if token.nil? or token.empty?
halt 400
end
token
end
def call_github(token, method, url, body=nil)
headers = {'Authorization' => "token #{token}"}
method_map = {:post => Net::HTTP::Post,
:get => Net::HTTP::Get,
:delete => Net::HTTP::Delete}
if body.instance_of?(Hash) || body.instance_of?(Array)
body = JSON.dump(body)
end
if Resin.development?
puts ">> Calling GitHub[#{method}] -> #{url}"
puts body
end
request = HTTParty::Request.new(method_map[method], url,
:headers => headers,
:body => body)
request.perform
end
def parse_post_json
raw = request.body.read
data = JSON.parse(raw, {:symbolize_names => true})
return {:raw => raw, :data => data}
end
def validate_project(data)
if data[:project].nil? or data[:project].empty?
halt 500
end
end
end
class Server < Resin::Server
include Helpers
set :sessions, true
set :session_secret, 'the-secret-hubboard-project'
get '/oauth/?' do
unless params.has_key? 'code'
halt 401, 'Failed to receive a valid OAuth code from GitHub'
end
response = HTTParty.post('https://github.com/login/oauth/access_token',
:query => {:client_id => $config['github']['id'],
:code => params['code'],
:client_secret => $config['github']['secret']})
unless response.code == 200
halt 418, 'We somehow got an invalid response from GitHub when trying to authenticate'
end
returned = CGI.parse(response.body)
access_token = returned["access_token"]
unless access_token
halt 401, 'Failed to pull an access token :('
end
session[:access_token] = access_token.first
redirect '/'
end
get '/login/?' do
token = session[:access_token]
if token.nil? or token.empty?
redirect "https://github.com/login/oauth/authorize?client_id=#{$config['github']['id']}&scope=public_repo&redirect_uri=#{MYSELF}/oauth"
end
redirect '/'
end
get '/logout/?' do
session[:access_token] = nil
redirect '/intro'
end
get '/' do
token = session[:access_token]
if token.nil? or token.empty?
redirect '/intro'
end
haml :index, :locals => {:access_token => token}
end
post '/issues/create' do
token = validate_token
data = parse_post_json
validate_project(data[:data])
call_github(token, :post, API_URL + "/repos/#{data[:data][:project]}/issues", data[:raw])
'{}'
end
post '/issues/:number/comment' do |number|
token = validate_token
data = parse_post_json
validate_project(data[:data])
call_github(token, :post, API_URL + "/repos/#{data[:data][:project]}/issues/#{number}/comments", data[:raw])
'{}'
end
post '/issues/:number/close' do |number|
token = validate_token
data = parse_post_json
validate_project(data[:data])
issue_url = API_URL + "/repos/#{data[:data][:project]}/issues/#{number}"
call_github(token, :post, issue_url + '/comments', {:body => <<-END
This work is complete.
#{COMMENT_FOOTER}
END
})
call_github(token, :post, issue_url, {:state => 'closed'})
'{}'
end
post '/issues/:number/label' do |number|
token = validate_token
data = parse_post_json
validate_project(data[:data])
project = data[:data][:project]
# First make sure the label exists in this repo
response = call_github(token, :get, API_URL + "/repos/#{project}/labels/#{INPROGRESS_LABEL}")
unless response.code == 200
# We couldn't find the label so let's make it!
call_github(token, :post, API_URL + "/repos/#{project}/labels",
{:name => INPROGRESS_LABEL, :color => '02e10c'})
end
# Second, let's add the label to the issue
issue_url = API_URL + "/repos/#{project}/issues/#{number}"
response = call_github(token, :post, issue_url + '/labels', [INPROGRESS_LABEL])
unless response.code == 200
puts response.inspect
halt 500
end
# Now that it's labelled appropriately, let's post a comment
call_github(token, :post, issue_url + '/comments',
{:body => <<-END
Starting work on this now.
#{COMMENT_FOOTER}
END
})
'{}'
end
post '/issues/:number/revert' do |number|
token = validate_token
data = parse_post_json
validate_project(data[:data])
issue_url = API_URL + "/repos/#{data[:data][:project]}/issues/#{number}"
response = call_github(token, :delete, issue_url + "/labels/#{INPROGRESS_LABEL}")
unless response.code == 200
halt 500
end
# Add a comment to let people know this is going back on the back-burner
call_github(token, :post, issue_url + '/comments',
{:body => <<-END
Putting this issue back on the back-burner.
#{COMMENT_FOOTER}
END
})
'{}'
end
end
end
if $0 == __FILE__
Hubboard::Server.run!
end