Skip to content

Commit

Permalink
store receiver, add groups, log messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Fuchs committed Mar 24, 2010
1 parent 840592a commit 1388b30
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 47 deletions.
2 changes: 1 addition & 1 deletion bin/bot.rb
Expand Up @@ -4,4 +4,4 @@

CouchPotato::Config.database_name = "http://localhost:5984/rugb"

bot.add_handler(:reply, Identity::Listener::Twitter.new(/#update/, :update))
bot.add_handler(:reply, Identity::Listener::Twitter.new('rugb', /#update/, :update))
5 changes: 5 additions & 0 deletions lib/couch_potato_namespace_fix.rb
@@ -0,0 +1,5 @@
CouchPotato::View::BaseViewSpec.class_eval do
def design_document
@design_document.gsub('/', '::') # TODO ask alex
end
end
6 changes: 5 additions & 1 deletion lib/identity.rb
@@ -1,9 +1,11 @@
require 'simply_stored/couch'
require 'active_support/core_ext/time/conversions' # twitter4r implicitely uses to_formatted_s
require 'active_support/core_ext/hash/keys' # simply_stored implicitely uses assert_valid_keys
require 'couch_potato_namespace_fix'

class Identity
autoload :Command, 'identity/command'
autoload :Message, 'identity/message'
autoload :Listener, 'identity/listener'
autoload :Poller, 'identity/poller'
autoload :Sources, 'identity/sources'
Expand All @@ -13,6 +15,7 @@ class Identity
# sanitize data ...

property :profiles
property :groups

view :by_handle, :key => :handle, :type => :custom, :map => <<-js
function(doc) {
Expand All @@ -28,13 +31,14 @@ class Identity

def initialize(profiles = {})
@profiles = profiles
@groups = []
end

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

def claim
profiles.each { |name, profile| profile['claimed_at'] = Time.now unless profile['claimed_at'] }
end
Expand Down
23 changes: 11 additions & 12 deletions lib/identity/command.rb
@@ -1,19 +1,22 @@
class Identity::Command
attr_reader :identity, :command, :args
attr_reader :identity, :command, :sender, :receiver, :args

def initialize(command, handle, args)
@identity = Identity.find_by_handle(handle) || Identity.new
@command = normalize_command(command)
def initialize(command, receiver, sender, args)
@receiver = receiver
@sender = Identity.find_by_handle(sender) || Identity.new
@command = command
@args = parse_args(args)
end

def join
update
update unless sender.created_at
sender.groups << receiver
sender.save
end

def update
Identity::Sources.update_all(identity, args)
identity.claim
Identity::Sources.update_all(sender, args)
sender.claim
end

def queue
Expand All @@ -22,11 +25,7 @@ def queue

def dispatch
send(command)
identity.save
end

def normalize_command(command)
command == 'update' && !identity.created_at ? 'join' : command
sender.save
end

def parse_args(string)
Expand Down
22 changes: 6 additions & 16 deletions lib/identity/listener/twitter.rb
Expand Up @@ -2,23 +2,13 @@
require 'twibot'

class Identity::Listener::Twitter < Twibot::Handler
# def initialize(bot = nil)
# bot.add_handler(:reply, handler(/#update/, :update)) if bot
# end

def initialize(pattern, callback)
def initialize(receiver, pattern, callback)
super(pattern) do |message, args|
handle = message.user.screen_name
text = "twitter:#{handle} #{message.text}"
Identity::Command.new(callback, handle, text).queue
Identity::Message.if_unprocessed(receiver, message) do
sender = message.user.screen_name
text = "twitter:#{sender} #{message.text}"
Identity::Command.new(callback, receiver, sender, text).queue
end
end
end

# def handler(pattern, callback)
# Twibot::Handler.new(pattern) do |message, args|
# handle = message.user.screen_name
# text = "twitter:#{handle} #{message.text}"
# Identity::Command.new(callback, handle, text).queue
# end
# end
end
30 changes: 30 additions & 0 deletions lib/identity/message.rb
@@ -0,0 +1,30 @@
class Identity::Message
class << self
def if_unprocessed(receiver, message)
raise 'message.id is nil' unless message.id
return if find_by_message_id(message.id)
yield
create :message_id => message.id,
:text => message.text,
:sender => message.user.screen_name,
:receiver => receiver,
:received_at => Time.now
end
end

include SimplyStored::Couch

# sanitize data ...

property :message_id
property :text
property :sender
property :receiver
property :received_at

view :by_message_id, :key => :message_id

def initialize(data = {})
data.each { |key, value| self.send("#{key}=", value) }
end
end
7 changes: 2 additions & 5 deletions lib/identity/poller/twitter.rb
@@ -1,7 +1,4 @@
# check twitter timeline for new replies
# process replies
# store processed tweet ids
# store ping timestamp
# checks for new replies only once

require 'twibot'

Expand All @@ -17,7 +14,7 @@ def initialize(type, pattern, callback, options = {})
super(Twibot::Config.default << options) # Twibot::FileConfig.new

# add a twitter handler
add_handler(type, Identity::Listener::Twitter.new(pattern, callback))
add_handler(type, Identity::Listener::Twitter.new(options[:login], pattern, callback))
end

def receive_replies
Expand Down
25 changes: 16 additions & 9 deletions test/command_test.rb
Expand Up @@ -9,35 +9,35 @@ def teardown
Identity.all.each { |identity| identity.delete }
end

def update!(handle, message)
Identity::Command.new('update', handle, message).dispatch
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 = Identity::Command.new('update', 'svenfuchs', 'github:foo me:http://tinyurl.com/yc7t8bv')
cmd = command('update', 'rugb', 'svenfuchs', 'github:foo me:http://tinyurl.com/yc7t8bv')
assert_equal cmd.args, {'github' => 'foo', 'me' => 'http://tinyurl.com/yc7t8bv'}

cmd = Identity::Command.new('update', 'svenfuchs', 'me foo')
cmd = command('update', 'rugb', 'svenfuchs', 'me foo')
assert_equal({}, cmd.args)
end

test 'updating w/ a twitter handle' do
update!('svenfuchs', 'twitter:svenfuchs')
command('update', 'rugb', 'svenfuchs', 'twitter:svenfuchs').dispatch

identity = Identity.find_by_handle('svenfuchs')
assert_equal 'svenfuchs', identity.twitter['handle']
assert_equal 'Berlin', identity.twitter['location']
end

test 'updating w/ a github handle' do
update!('svenfuchs', 'github:svenfuchs')
command('update', 'rugb', 'svenfuchs', 'github:svenfuchs').dispatch

identity = Identity.find_by_handle('svenfuchs')
assert_equal 'svenfuchs', identity.github['handle']
end

test 'updating w/ a me url' do
update!('svenfuchs', 'me:http://tinyurl.com/yc7t8bv')
command('update', 'rugb', 'svenfuchs', 'me:http://tinyurl.com/yc7t8bv').dispatch
identity = Identity.find_by_handle('svenphoox')
assert_equal 'svenphoox', identity.github['handle']
assert_equal 'Sven', identity.github['name']
Expand All @@ -48,15 +48,22 @@ def update!(handle, message)
github_at = Time.local(2010, 1, 2, 12, 0, 0)
Time.stubs(:now).returns(twitter_at)

update!('svenfuchs', 'twitter:svenfuchs')
command('update', 'rugb', 'svenfuchs', 'twitter:svenfuchs').dispatch
identity = Identity.find_by_handle('svenfuchs')
assert_equal twitter_at, Time.parse(identity.twitter['claimed_at'])

Time.stubs(:now).returns(Time.local(2010, 1, 2, 12, 0, 0))
update!('svenfuchs', 'github:svenfuchs')
command('update', 'rugb', 'svenfuchs', 'github:svenfuchs').dispatch
identity = Identity.find_by_handle('svenfuchs')
assert_equal twitter_at, Time.parse(identity.twitter['claimed_at'])
assert_equal github_at, Time.parse(identity.github['claimed_at'])
end

test 'joining a group' do
command('join', 'rugb', 'svenfuchs', 'twitter:svenfuchs').dispatch

identity = Identity.find_by_handle('svenfuchs')
assert identity.groups.include?('rugb')
end

end
23 changes: 23 additions & 0 deletions test/connect.rb
@@ -0,0 +1,23 @@
$: << File.expand_path('../lib', __FILE__)
require 'rubygems'
require 'identity'

module CouchPotato
def self.database=(database)
@@__database = database
end
end

ENV['couchdb_url'] = ...
ENV['twitter_login'] = 'rugb_test'
ENV['twitter_password'] = 'clubmate'

# gotta do this to use http auth
ENV['couchdb_url'] =~ /(.*)\/([^\/]*)$/
couchdb_url, couchdb_name = $1, $2

couchrest_server = CouchRest::Server.new(couchdb_url)
couchrest_db = CouchRest::Database.new(couchrest_server, couchdb_name)
CouchPotato.database = CouchPotato::Database.new(couchrest_db)

p Identity.find_by_handle('fritzek')
28 changes: 26 additions & 2 deletions test/listener_test.rb
Expand Up @@ -7,16 +7,17 @@ def setup

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

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

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

def sender(name)
Expand All @@ -30,5 +31,28 @@ def sender(name)
assert_equal 'svenphoox', identity.github['handle']
assert_equal 'Sven', identity.github['name']
end

test 'logs processed messages' do
now = Time.now
Time.stubs(:now).returns(now)

update!('svenfuchs', '#update')
Identity.find_by_handle('svenfuchs')
message = Identity::Message.find_by_message_id('12345')

assert_equal 'rugb_test', message.receiver
assert_equal 'svenfuchs', message.sender
assert_equal '#update', message.text
assert_equal '12345', message.message_id
assert_equal now.to_s, Time.parse(message.received_at).to_s
end

test 'does not process an already processed message' do
update!('svenfuchs', '#update')
Identity.find_by_handle('svenfuchs')

Identity::Command.expects(:new).never
Identity.find_by_handle('svenfuchs')
end
end

2 changes: 1 addition & 1 deletion test/poller_test.rb
Expand Up @@ -25,7 +25,7 @@ def capture_stdout
replies = [tweet('johndoe', '@svenfuchs #update')]
poller.twitter.expects(:status).with(:replies, { :since_id => 10623176300 }).returns(replies)

args = [:update, 'johndoe', 'twitter:johndoe @svenfuchs #update']
args = [:update, 'svenfuchs', 'johndoe', 'twitter:johndoe @svenfuchs #update']
command = Identity::Command.new(*args)
command.stubs(:queue)
Identity::Command.expects(:new).with(*args).returns(command)
Expand Down

0 comments on commit 1388b30

Please sign in to comment.