Skip to content

Commit

Permalink
add html and json views
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Fuchs committed Mar 27, 2010
1 parent 9c25ba2 commit 677c9aa
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 51 deletions.
1 change: 1 addition & 0 deletions .gems
@@ -1,4 +1,5 @@
sinatra
rack-respond_to
httparty
mbbx6spp-twitter4r --source gems.github.com
twibot
Expand Down
13 changes: 12 additions & 1 deletion app.rb
Expand Up @@ -11,10 +11,21 @@
Dir[File.expand_path('../app/**/*', __FILE__)].each { |file| require file }

configure :production do
# set :public, File.dirname('../static', __FILE__)
end

helpers do
include Sinatra::Authorization
include Identity::Helpers
end

get '/' do
identities = Identity.all

respond_to do |format|
format.html { erb :identities, :locals => { :identities => identities } }
format.json { identities.to_json }
end
end

get '/ping' do
Expand All @@ -23,5 +34,5 @@
:login => ENV['twitter_login'],
:password => ENV['twitter_password'],
:process => Identity::Message.max_message_id || 10420650959
}).run! && "ok"
}).run!
end
17 changes: 17 additions & 0 deletions app/respond_to.rb
@@ -0,0 +1,17 @@
require 'rack/respond_to'

class Sinatra::Application
include Rack::RespondTo

def respond_to
env['HTTP_ACCEPT'] ||= 'text/html'
Rack::RespondTo.env = env

super { |format|
yield(format).tap do |response|
type = Rack::RespondTo::Helpers.match(Rack::RespondTo.media_types, format).first
content_type(type) if type
end
}
end
end
28 changes: 26 additions & 2 deletions lib/identity.rb
Expand Up @@ -5,6 +5,7 @@

class Identity
autoload :Command, 'identity/command'
autoload :Helpers, 'identity/helpers'
autoload :Message, 'identity/message'
autoload :Listener, 'identity/listener'
autoload :Poller, 'identity/poller'
Expand Down Expand Up @@ -36,16 +37,39 @@ def initialize(profiles = {})

Sources.each_name do |name|
define_method(name) { profiles[name] || {} }
define_method(:"#{name}=") { |profile| profiles[name] = profile }
define_method(:"#{name}=") { |profile| profile[name] = profile }
end

def handles
@handles ||= profiles.map { |name, profile| profile['handle'] }.compact.uniq
end

def avatar
@avatar ||= begin
profiles['twitter'] && "http://headhunter.heroku.com/#{profiles['twitter']['handle']}" ||
profiles.map { |name, profile| profile['avatar'] }.compact.first
end
end

def url
@url ||= profiles.map { |name, profile| profile['url'] }.compact.first
end

def name
@name ||= profiles.map { |name, profile| profile['name'] }.compact.first
end

def claim
profiles.each { |name, profile| p profile.class; profile['claimed_at'] = Time.now unless profile['claimed_at'] }
profiles.each { |name, profile| profile['claimed_at'] = Time.now unless profile['claimed_at'] }
end

def set_profile(name, profile)
claimed_at = send(name)['claimed_at']
profile.merge!('claimed_at' => claimed_at) if claimed_at
profiles[name] = profile
end

def to_json(*args)
{ :handles => handles, :profiles => profiles, :groups => groups, :created_at => created_at }.to_json
end
end
1 change: 1 addition & 0 deletions lib/identity/command.rb
Expand Up @@ -17,6 +17,7 @@ def join
def update
Identity::Sources.update_all(sender, args)
sender.claim
sender.save
end

def queue
Expand Down
28 changes: 28 additions & 0 deletions lib/identity/helpers.rb
@@ -0,0 +1,28 @@
module Identity::Helpers
def identity_link_or_name(identity)
identity.url ?
%(<a class="name" href="#{identity.url}">#{identity.name}</a>) :
%(<span class="name">#{identity.name}</span>)
end

def identity_links(identity)
links = [identity_link(identity)] + profile_links(identity)
links.compact
end

def identity_link(identity)
%(<a class="name" href="#{identity.url}">#{identity.url}</a>) if identity.url
end

def profile_links(identity)
identity.profiles.map { |name, profile| profile_link(name, profile_url(name, profile)) }.compact
end

def profile_link(name, url)
%(<a href="#{url}" class="profile #{name}">#{url}</a>) if url
end

def profile_url(name, profile)
Identity::Sources[name].profile_url(profile)
end
end
12 changes: 10 additions & 2 deletions lib/identity/sources.rb
Expand Up @@ -12,14 +12,22 @@ def all
@sources ||= { 'me' => Me.new, 'twitter' => Twitter.new, 'github' => Github.new }
end

def [](name)
all[name]
end

def update_all(identity, args)
each { |name, source| source.update(identity, args[name]) if args.key?(name) }
end


def map(&block) # use Numerable
all.map(&block)
end

def each(&block)
all.each(&block)
end

def each_name(&block)
all.keys.each(&block)
end
Expand Down
10 changes: 5 additions & 5 deletions lib/identity/sources/base.rb
Expand Up @@ -5,7 +5,10 @@ module Identity::Sources
class Base
class << self
def get(url)
HTTParty.get(url)
data = HTTParty.get(url)
data = JSON.parse(data) rescue {} if data.is_a?(String) # TODO somehow communicate parsing errors
data['source_url'] = url
data
end
end

Expand All @@ -16,14 +19,11 @@ def name
end

def update(identity, handle)
identity.set_profile(name, fetch(url(handle))) if handle
identity.set_profile(name, fetch(source_url(handle))) if handle
end

def fetch(url)
data = Base.get(url)
p data
p data.class
data = JSON.parse(data) if data.is_a?(String)
data = remap(data) if map
data
end
Expand Down
10 changes: 7 additions & 3 deletions lib/identity/sources/github.rb
Expand Up @@ -12,12 +12,16 @@ def initialize
}
end

def url(handle)
def profile_url(profile)
"http://github.com/#{profile['handle']}"
end

def source_url(handle)
"http://github.com/api/v2/json/user/show/#{handle}"
end

def fetch(url)
remap(Base.get(url)['user'])
def fetch(source_url)
remap(Base.get(source_url)['user'])
end
end
end
4 changes: 4 additions & 0 deletions lib/identity/sources/me.rb
Expand Up @@ -7,5 +7,9 @@ def update(identity, url)
source.update(identity, identity.me[name]) if identity.me[name]
end if identity.me
end

def profile_url(profile)
profile['source_url']
end
end
end
6 changes: 5 additions & 1 deletion lib/identity/sources/twitter.rb
Expand Up @@ -11,7 +11,11 @@ def initialize
}
end

def url(handle)
def profile_url(profile)
"http://twitter.com/#{profile['handle']}"
end

def source_url(handle)
"http://api.twitter.com/1/users/show/#{handle}.json"
end
end
Expand Down
68 changes: 68 additions & 0 deletions test/app_test.rb
@@ -0,0 +1,68 @@
require File.expand_path('../test_helper', __FILE__)

require 'app'

set :environment, :test

class AppTest < Test::Unit::TestCase
include Rack::Test::Methods

def setup
setup_stubs
end

test '/ping is protected through http auth' do
Identity::Poller::Twitter.stubs(:new).returns(Object.new.tap { |o| o.stubs(:run!) })
authorized_get '/ping'
assert_equal 200, last_response.status

unauthorized_get '/ping'
assert_equal 401, last_response.status
end

test '/ping is runs a twitter poller' do
poller = Identity::Poller::Twitter.new(:reply, /#update/, :update, { :login => 'login', :process => 1 })
Identity::Poller::Twitter.stubs(:new).returns(poller)
poller.twitter.expects(:timeline_for).with(:replies, :since_id => 1).returns([status('rugb_test', '3update')])

log = capture_stdout { authorized_get '/ping' }

assert_match /imposing as @login/, log
assert_match /Received 1 reply/, log
end

test '/ responding to :html' do
setup_stubs
command('update', 'rugb', 'svenfuchs', 'twitter:svenfuchs github:svenphoox').dispatch
get '/'

assert_equal 'text/html', last_response['Content-Type']
assert_match /svenfuchs/, last_response.body # TODO use some tag matcher
end

test '/ responding to :json' do
Identity.new(:twitter => { :handle => 'svenfuchs' }).save
get '/', {}, { 'HTTP_ACCEPT' => 'application/json' }

assert_equal 'application/json', last_response['Content-Type']
assert_equal({ 'twitter' => { 'handle' => 'svenfuchs' } }, JSON.parse(last_response.body).first['profiles'])
end

protected

def app
Sinatra::Application
end

def authorized_get(path)
get path, {}, { 'HTTP_AUTHORIZATION' => encode_credentials(ENV['twitter_login'], ENV['twitter_password']) }
end

def unauthorized_get(path)
get path, {}, { 'HTTP_AUTHORIZATION' => encode_credentials('go', 'away') }
end

def encode_credentials(username, password)
"Basic " + Base64.encode64("#{username}:#{password}")
end
end
8 changes: 0 additions & 8 deletions test/command_test.rb
Expand Up @@ -5,14 +5,6 @@ def setup
setup_stubs
end

def teardown
Identity.all.each { |identity| identity.delete }
end

def command(command, receiver, sender, message)
Identity::Command.new(command, receiver, sender, message)
end

test '#parse_args parses a message for foo:bar arguments' do
cmd = command('update', 'rugb', 'svenfuchs', 'github:foo me:http://tinyurl.com/yc7t8bv')
assert_equal cmd.args, {'github' => 'foo', 'me' => 'http://tinyurl.com/yc7t8bv'}
Expand Down
21 changes: 4 additions & 17 deletions test/listener_test.rb
Expand Up @@ -5,31 +5,18 @@ def setup
setup_stubs
end

def teardown
Identity.all.each { |identity| identity.delete }
Identity::Message.all.each { |message| message.delete }
end

def update!(from, message, id = '12345')
message = message(from, message, id)
status = status(from, message, id)
listener = Identity::Listener::Twitter.new('rugb_test', /#update/, :update)
listener.dispatch(message)
end

def message(from, message, id = '12345')
Twitter::Status.new(:id => id, :user => sender(from), :text => message)
end

def sender(name)
Twitter::User.new(:screen_name => name)
listener.dispatch(status)
end

test 'updating w/ a me url and a github handle' do
update!('svenfuchs', '#update me:http://tinyurl.com/yc7t8bv github:svenphoox')
identity = Identity.find_by_handle('svenphoox')

assert_equal 'svenphoox', identity.github['handle']
assert_equal 'Sven', identity.github['name']
assert_equal 'svenphoox', identity.github['handle']
assert_equal 'Sven', identity.github['name']
end

test 'updating an existing profile' do
Expand Down
4 changes: 0 additions & 4 deletions test/message_test.rb
@@ -1,10 +1,6 @@
require File.expand_path('../test_helper', __FILE__)

class MessageTwitterTest < Test::Unit::TestCase
def teardown
# Identity::Message.all.each { |message| message.delete }
end

def message(id, text = 'da message', sender = 'svenfuchs', receiver = 'rugb_test')
Identity::Message.new :message_id => id,
:text => text,
Expand Down
7 changes: 0 additions & 7 deletions test/poller_test.rb
Expand Up @@ -11,13 +11,6 @@ def tweet(from, text)
)
end

def capture_stdout
@stdout, $stdout = $stdout, (io = StringIO.new)
yield
$stdout = @stdout
io.string
end

test "Poller::Twitter polls from twitter once and handles new replies by queueing commands" do
config = { :login => 'svenfuchs', :process => 10623176300 }
poller = Identity::Poller::Twitter.new(:reply, /#update/, :update, config)
Expand Down

0 comments on commit 677c9aa

Please sign in to comment.