tinder 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +7 -1
- data/Rakefile +0 -4
- data/VERSION +1 -1
- data/lib/tinder.rb +2 -2
- data/lib/tinder/campfire.rb +29 -130
- data/lib/tinder/connection.rb +21 -0
- data/lib/tinder/multipart.rb +1 -2
- data/lib/tinder/room.rb +93 -134
- data/spec/campfire_spec.rb +30 -30
- data/spec/spec_helper.rb +0 -1
- data/test/remote/remote_campfire_test.rb +14 -14
- data/test/test_helper.rb +1 -2
- data/tinder.gemspec +7 -8
- metadata +4 -13
data/README.txt
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
= Tinder - get the Campfire started
|
2
2
|
|
3
|
+
|
4
|
+
This branch is a rewrite of Tinder to use the official Campfire API. The API is intended to be backwards compatible so consumers can easily migrate off the HTML API.
|
5
|
+
|
6
|
+
-- Joshua Peek (Programmer, 37signals)
|
7
|
+
|
8
|
+
|
3
9
|
Tinder is a library for interfacing with Campfire, the chat application from 37Signals. Unlike Marshmallow, it is designed to be a full-featured API (since 37Signals doesn't provide a real one), allowing you to programatically manage and speak/listen in chat rooms.
|
4
10
|
|
5
11
|
== Usage
|
6
12
|
|
7
|
-
campfire = Campfire.new 'mysubdomain'
|
13
|
+
campfire = Tinder::Campfire.new 'mysubdomain'
|
8
14
|
campfire.login 'myemail@example.com', 'mypassword'
|
9
15
|
|
10
16
|
room = campfire.create_room 'New Room', 'My new campfire room to test tinder'
|
data/Rakefile
CHANGED
@@ -9,14 +9,10 @@ begin
|
|
9
9
|
gem.homepage = 'http://github.com/collectiveidea/tinder'
|
10
10
|
gem.rubyforge_project = "tinder"
|
11
11
|
gem.add_dependency "activesupport"
|
12
|
-
gem.add_dependency "hpricot"
|
13
12
|
gem.add_dependency "mime-types"
|
14
13
|
gem.add_development_dependency "rspec"
|
15
14
|
end
|
16
15
|
Jeweler::GemcutterTasks.new
|
17
|
-
Jeweler::RubyforgeTasks.new do |rubyforge|
|
18
|
-
rubyforge.doc_task = "rdoc"
|
19
|
-
end
|
20
16
|
rescue LoadError
|
21
17
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
22
18
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/lib/tinder.rb
CHANGED
@@ -4,8 +4,8 @@ require 'uri'
|
|
4
4
|
require 'net/http'
|
5
5
|
require 'net/https'
|
6
6
|
require 'open-uri'
|
7
|
-
require 'hpricot'
|
8
7
|
|
8
|
+
require 'tinder/connection'
|
9
9
|
require 'tinder/multipart'
|
10
10
|
require 'tinder/campfire'
|
11
11
|
require 'tinder/room'
|
@@ -13,4 +13,4 @@ require 'tinder/room'
|
|
13
13
|
module Tinder
|
14
14
|
class Error < StandardError; end
|
15
15
|
class SSLRequiredError < Error; end
|
16
|
-
end
|
16
|
+
end
|
data/lib/tinder/campfire.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Tinder
|
2
|
-
|
2
|
+
|
3
3
|
# == Usage
|
4
4
|
#
|
5
5
|
# campfire = Tinder::Campfire.new 'mysubdomain'
|
@@ -12,7 +12,9 @@ module Tinder
|
|
12
12
|
# room = campfire.find_room_by_guest_hash 'abc123', 'John Doe'
|
13
13
|
# room.speak 'Hello world!'
|
14
14
|
class Campfire
|
15
|
-
|
15
|
+
HOST = "campfirenow.com"
|
16
|
+
|
17
|
+
attr_reader :connection, :subdomain, :uri
|
16
18
|
|
17
19
|
# Create a new connection to the campfire account with the given +subdomain+.
|
18
20
|
#
|
@@ -24,9 +26,11 @@ module Tinder
|
|
24
26
|
# c = Tinder::Campfire.new("mysubdomain", :ssl => true)
|
25
27
|
def initialize(subdomain, options = {})
|
26
28
|
options = { :ssl => false }.merge(options)
|
29
|
+
@connection = Connection.new
|
27
30
|
@cookie = nil
|
28
31
|
@subdomain = subdomain
|
29
|
-
@uri = URI.parse("#{options[:ssl] ? 'https' : 'http' }://#{subdomain}
|
32
|
+
@uri = URI.parse("#{options[:ssl] ? 'https' : 'http' }://#{subdomain}.#{HOST}")
|
33
|
+
connection.base_uri @uri.to_s
|
30
34
|
if options[:proxy]
|
31
35
|
uri = URI.parse(options[:proxy])
|
32
36
|
@http = Net::HTTP::Proxy(uri.host, uri.port, uri.user, uri.password)
|
@@ -35,173 +39,68 @@ module Tinder
|
|
35
39
|
end
|
36
40
|
@logged_in = false
|
37
41
|
end
|
38
|
-
|
42
|
+
|
39
43
|
# Log in to campfire using your +email+ and +password+
|
40
|
-
def login(
|
41
|
-
|
42
|
-
raise Error, "Campfire login failed"
|
43
|
-
end
|
44
|
-
# ensure that SSL is set if required on this account
|
45
|
-
raise SSLRequiredError, "Your account requires SSL" unless verify_response(get, :success)
|
44
|
+
def login(username, password)
|
45
|
+
connection.basic_auth(username, password)
|
46
46
|
@logged_in = true
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
# Returns true when successfully logged in
|
50
50
|
def logged_in?
|
51
51
|
@logged_in == true
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def logout
|
55
|
-
|
56
|
-
|
57
|
-
end
|
55
|
+
connection.default_options.delete(:basic_auth)
|
56
|
+
@logged_in = false
|
58
57
|
end
|
59
|
-
|
58
|
+
|
60
59
|
# Get an array of all the available rooms
|
61
60
|
# TODO: detect rooms that are full (no link)
|
62
61
|
def rooms
|
63
|
-
|
64
|
-
|
65
|
-
name = a.search("//h2").inner_html.strip if name.empty?
|
66
|
-
Room.new(self, room_id_from_element(a.attributes['id']), name)
|
62
|
+
connection.get('/rooms.json')['rooms'].map do |room|
|
63
|
+
Room.new(self, room)
|
67
64
|
end
|
68
65
|
end
|
69
|
-
|
66
|
+
|
70
67
|
# Find a campfire room by name
|
71
68
|
def find_room_by_name(name)
|
72
|
-
rooms.detect {|room| room.name == name }
|
69
|
+
rooms.detect { |room| room.name == name }
|
73
70
|
end
|
74
71
|
|
75
72
|
# Find a campfire room by its guest hash
|
76
73
|
def find_room_by_guest_hash(hash, name)
|
77
|
-
|
78
|
-
|
79
|
-
Room.new(self, room_id_from_url(res['location'])) if verify_response(res, :redirect)
|
74
|
+
rooms.detect { |room| room.guest_invite_code == hash }
|
80
75
|
end
|
81
|
-
|
76
|
+
|
82
77
|
# Creates and returns a new Room with the given +name+ and optionally a +topic+
|
83
78
|
def create_room(name, topic = nil)
|
84
|
-
|
79
|
+
connection.post('/rooms.json', :body => { :room => { :name => name, :topic => topic } }.to_json)
|
80
|
+
find_room_by_name(name)
|
85
81
|
end
|
86
|
-
|
82
|
+
|
87
83
|
def find_or_create_room_by_name(name)
|
88
84
|
find_room_by_name(name) || create_room(name)
|
89
85
|
end
|
90
|
-
|
86
|
+
|
91
87
|
# List the users that are currently chatting in any room
|
92
88
|
def users(*room_names)
|
93
|
-
users
|
94
|
-
if room_names.empty? || room_names.include?((room/"h2/a").inner_html)
|
95
|
-
room.search("//li.user").collect { |user| user.inner_html }
|
96
|
-
end
|
97
|
-
end
|
98
|
-
users.flatten.compact.uniq.sort
|
89
|
+
rooms.map(&:users).flatten.compact.uniq.sort
|
99
90
|
end
|
100
|
-
|
91
|
+
|
101
92
|
# Get the dates of the available transcripts by room
|
102
93
|
#
|
103
94
|
# campfire.available_transcripts
|
104
95
|
# #=> {"15840" => [#<Date: 4908311/2,0,2299161>, #<Date: 4908285/2,0,2299161>]}
|
105
96
|
#
|
106
97
|
def available_transcripts(room = nil)
|
107
|
-
|
108
|
-
url += "?room_id#{room}" if room
|
109
|
-
transcripts = (Hpricot(get(url).body) / ".transcript").inject({}) do |result,transcript|
|
110
|
-
link = (transcript / "a").first.attributes['href']
|
111
|
-
(result[room_id_from_url(link)] ||= []) << Date.parse(link.scan(/\/transcript\/(\d{4}\/\d{2}\/\d{2})/).to_s)
|
112
|
-
result
|
113
|
-
end
|
114
|
-
room ? transcripts[room.to_s] : transcripts
|
98
|
+
raise NotImplementedError
|
115
99
|
end
|
116
|
-
|
100
|
+
|
117
101
|
# Is the connection to campfire using ssl?
|
118
102
|
def ssl?
|
119
103
|
uri.scheme == 'https'
|
120
104
|
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def room_id_from_url(url)
|
125
|
-
url.scan(/room\/(\d*)/).to_s
|
126
|
-
end
|
127
|
-
|
128
|
-
def room_id_from_element(element)
|
129
|
-
element.split("_").last
|
130
|
-
end
|
131
|
-
|
132
|
-
def url_for(*args)
|
133
|
-
options = {:only_path => true}.merge(args.last.is_a?(Hash) ? args.pop : {})
|
134
|
-
path = args.shift
|
135
|
-
"#{options[:only_path] ? '' : uri}/#{path}"
|
136
|
-
end
|
137
|
-
|
138
|
-
def post(path, data = {}, options = {})
|
139
|
-
perform_request(options) do
|
140
|
-
returning Net::HTTP::Post.new(url_for(path)) do |request|
|
141
|
-
if options[:multipart]
|
142
|
-
request.body = data
|
143
|
-
else
|
144
|
-
request.set_form_data(flatten(data))
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def get(path = nil, options = {})
|
151
|
-
perform_request(options) { Net::HTTP::Get.new(url_for(path)) }
|
152
|
-
end
|
153
|
-
|
154
|
-
def prepare_request(request, options = {})
|
155
|
-
returning request do
|
156
|
-
request.add_field 'User-Agent', "Tinder (http://tinder.rubyforge.org)"
|
157
|
-
request.add_field 'Cookie', @cookie if @cookie
|
158
|
-
request.add_field 'X-Requested-With', 'XMLHttpRequest'
|
159
|
-
if options[:ajax]
|
160
|
-
request.add_field 'X-Prototype-Version', '1.5.1.1'
|
161
|
-
end
|
162
|
-
if options[:multipart]
|
163
|
-
request.add_field 'Content-Type', 'multipart/form-data, boundary=' + Multipart::MultipartPost::BOUNDARY + " "
|
164
|
-
else
|
165
|
-
request.add_field 'Content-Type', 'application/x-www-form-urlencoded'
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def perform_request(options = {}, &block)
|
171
|
-
@request = prepare_request(yield, options)
|
172
|
-
http = @http.new(uri.host, uri.port)
|
173
|
-
http.use_ssl = ssl?
|
174
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ssl?
|
175
|
-
@response = returning http.request(@request) do |response|
|
176
|
-
@cookie = response['set-cookie'] if response['set-cookie']
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# flatten a nested hash (:room => {:name => 'foobar'} to 'user[name]' => 'foobar')
|
181
|
-
def flatten(params)
|
182
|
-
params = params.dup
|
183
|
-
params.stringify_keys!.each do |k,v|
|
184
|
-
if v.is_a? Hash
|
185
|
-
params.delete(k)
|
186
|
-
v.each {|subk,v| params["#{k}[#{subk}]"] = v }
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def verify_response(response, options = {})
|
192
|
-
if options.is_a?(Symbol)
|
193
|
-
codes = case options
|
194
|
-
when :success; [200]
|
195
|
-
when :redirect; 300..399
|
196
|
-
else raise(ArgumentError, "Unknown response #{options}")
|
197
|
-
end
|
198
|
-
codes.include?(response.code.to_i)
|
199
|
-
elsif options[:redirect_to]
|
200
|
-
verify_response(response, :redirect) && response['location'] == options[:redirect_to]
|
201
|
-
else
|
202
|
-
false
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
105
|
end
|
207
106
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Tinder
|
4
|
+
class Connection
|
5
|
+
def initialize
|
6
|
+
class << self
|
7
|
+
include HTTParty
|
8
|
+
|
9
|
+
headers 'Content-Type' => 'application/json'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def metaclass
|
14
|
+
class << self; self; end
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(*args, &block)
|
18
|
+
metaclass.send(*args, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/tinder/multipart.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'mime/types'
|
3
2
|
require 'net/http'
|
4
3
|
require 'cgi'
|
@@ -41,7 +40,7 @@ module Multipart #:nodoc:
|
|
41
40
|
@content + "\r\n"
|
42
41
|
end
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
class MultipartPost #:nodoc:
|
46
45
|
BOUNDARY = 'campfire-is-awesome'
|
47
46
|
HEADER = {"Content-type" => "multipart/form-data, boundary=" + BOUNDARY + " "}
|
data/lib/tinder/room.rb
CHANGED
@@ -3,118 +3,96 @@ module Tinder
|
|
3
3
|
class Room
|
4
4
|
attr_reader :id, :name
|
5
5
|
|
6
|
-
def initialize(campfire,
|
6
|
+
def initialize(campfire, attributes = {})
|
7
7
|
@campfire = campfire
|
8
|
-
@id = id
|
9
|
-
@name = name
|
8
|
+
@id = attributes['id']
|
9
|
+
@name = attributes['name']
|
10
|
+
@loaded = false
|
10
11
|
end
|
11
|
-
|
12
|
+
|
12
13
|
# Join the room. Pass +true+ to join even if you've already joined.
|
13
14
|
def join(force = false)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@user_id = room.body.scan(/\"userID\":\s?(\d+)/).to_s
|
18
|
-
@last_cache_id = room.body.scan(/\"lastCacheID\":\s?(\d+)/).to_s
|
19
|
-
@timestamp = room.body.scan(/\"timestamp\":\s?(\d+)/).to_s
|
20
|
-
@idle_since = Time.now
|
21
|
-
end if @room.nil? || force
|
22
|
-
ping
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
15
|
+
post 'join'
|
16
|
+
end
|
17
|
+
|
26
18
|
# Leave a room
|
27
19
|
def leave
|
28
|
-
|
29
|
-
@room, @membership_key, @user_id, @last_cache_id, @timestamp, @idle_since = nil
|
30
|
-
end
|
20
|
+
post 'leave'
|
31
21
|
end
|
32
22
|
|
33
23
|
# Toggle guest access on or off
|
34
24
|
def toggle_guest_access
|
35
|
-
|
36
|
-
verify_response(post("room/#{id}/toggle_guest_access"), :success) && join(true)
|
25
|
+
raise NotImplementedError
|
37
26
|
end
|
38
27
|
|
39
28
|
# Get the url for guest access
|
40
29
|
def guest_url
|
41
|
-
|
42
|
-
|
43
|
-
|
30
|
+
if guest_access_enabled?
|
31
|
+
"http://#{@campfire.subdomain}.campfirenow.com/#{guest_invite_code}"
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
44
35
|
end
|
45
|
-
|
36
|
+
|
46
37
|
def guest_access_enabled?
|
47
|
-
|
38
|
+
load
|
39
|
+
@open_to_guests ? true : false
|
48
40
|
end
|
49
41
|
|
50
42
|
# The invite code use for guest
|
51
43
|
def guest_invite_code
|
52
|
-
|
44
|
+
load
|
45
|
+
@active_token_value
|
53
46
|
end
|
54
47
|
|
55
48
|
# Change the name of the room
|
56
49
|
def name=(name)
|
57
|
-
|
50
|
+
connection.post("/room/#{@id}.json", :body => { :room => { :name => name } })
|
58
51
|
end
|
59
52
|
alias_method :rename, :name=
|
60
53
|
|
61
54
|
# Change the topic
|
62
55
|
def topic=(topic)
|
63
|
-
|
56
|
+
connection.post("/room/#{@id}.json", :body => { :room => { :topic => name } })
|
64
57
|
end
|
65
|
-
|
58
|
+
|
66
59
|
# Get the current topic
|
67
60
|
def topic
|
68
|
-
|
69
|
-
|
70
|
-
if h
|
71
|
-
(h/:span).remove
|
72
|
-
h.inner_text.strip
|
73
|
-
end
|
61
|
+
load
|
62
|
+
@topic
|
74
63
|
end
|
75
|
-
|
64
|
+
|
76
65
|
# Lock the room to prevent new users from entering and to disable logging
|
77
66
|
def lock
|
78
|
-
|
67
|
+
post :lock
|
79
68
|
end
|
80
69
|
|
81
70
|
# Unlock the room
|
82
71
|
def unlock
|
83
|
-
|
72
|
+
post :unlock
|
84
73
|
end
|
85
74
|
|
86
75
|
def ping(force = false)
|
87
|
-
|
88
|
-
@idle_since = Time.now
|
89
|
-
end if @idle_since < 1.minute.ago || force
|
76
|
+
raise NotImplementedError
|
90
77
|
end
|
91
78
|
|
92
79
|
def destroy
|
93
|
-
|
80
|
+
raise NotImplementedError
|
94
81
|
end
|
95
82
|
|
96
83
|
# Post a new message to the chat room
|
97
84
|
def speak(message, options = {})
|
98
|
-
|
99
|
-
:message => message,
|
100
|
-
:t => Time.now.to_i
|
101
|
-
}.merge(options)
|
102
|
-
|
103
|
-
post_options.delete(:paste) unless post_options[:paste]
|
104
|
-
response = post("room/#{id}/speak", post_options, :ajax => true)
|
105
|
-
|
106
|
-
if verify_response(response, :success)
|
107
|
-
message
|
108
|
-
end
|
85
|
+
send_message(message)
|
109
86
|
end
|
110
87
|
|
111
88
|
def paste(message)
|
112
|
-
|
89
|
+
send_message(message, 'PasteMassage')
|
113
90
|
end
|
114
|
-
|
91
|
+
|
115
92
|
# Get the list of users currently chatting for this room
|
116
93
|
def users
|
117
|
-
|
94
|
+
reload!
|
95
|
+
@users
|
118
96
|
end
|
119
97
|
|
120
98
|
# Get and array of the messages that have been posted to the room. Each
|
@@ -136,26 +114,22 @@ module Tinder
|
|
136
114
|
# end
|
137
115
|
#
|
138
116
|
def listen(interval = 5)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
end
|
149
|
-
else
|
150
|
-
self.messages
|
117
|
+
require 'yajl/http_stream'
|
118
|
+
|
119
|
+
auth = connection.default_options[:basic_auth]
|
120
|
+
url = URI.parse("http://#{auth[:username]}:#{auth[:password]}@streaming.#{Campfire::HOST}/room/#{@id}/live.json")
|
121
|
+
Yajl::HttpStream.get(url) do |message|
|
122
|
+
{ :id => message['id'],
|
123
|
+
:user_id => message['user_id'],
|
124
|
+
:message => message['body'] }
|
151
125
|
end
|
152
126
|
end
|
153
|
-
|
127
|
+
|
154
128
|
# Get the dates for the available transcripts for this room
|
155
129
|
def available_transcripts
|
156
|
-
|
130
|
+
raise NotImplementedError
|
157
131
|
end
|
158
|
-
|
132
|
+
|
159
133
|
# Get the transcript for the given date (Returns a hash in the same format as #listen)
|
160
134
|
#
|
161
135
|
# room.transcript(room.available_transcripts.first)
|
@@ -168,79 +142,64 @@ module Tinder
|
|
168
142
|
# The timestamp slot will typically have a granularity of five minutes.
|
169
143
|
#
|
170
144
|
def transcript(transcript_date)
|
171
|
-
url = "room/#{id}/transcript/#{transcript_date.to_date.strftime('%Y/%m/%d')}"
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
person = (message / '.person').first
|
178
|
-
end
|
179
|
-
body = (message / '.body div').first
|
180
|
-
if d = (message / '.date span').first
|
181
|
-
date = d.inner_html
|
182
|
-
end
|
183
|
-
if t = (message / '.time div').first
|
184
|
-
time = t.inner_html
|
185
|
-
end
|
186
|
-
{:id => message.attributes['id'].scan(/message_(\d+)/).to_s,
|
187
|
-
:person => person ? person.inner_html : nil,
|
188
|
-
:user_id => message.attributes['class'].scan(/user_(\d+)/).to_s,
|
189
|
-
:message => body ? body.inner_html : nil,
|
190
|
-
# Use the transcript_date to fill in the correct year
|
191
|
-
:timestamp => Time.parse("#{date} #{time}", transcript_date)
|
192
|
-
}
|
145
|
+
url = "/room/#{@id}/transcript/#{transcript_date.to_date.strftime('%Y/%m/%d')}.json"
|
146
|
+
connection.get(url)['messages'].map do |room|
|
147
|
+
{ :id => room['id'],
|
148
|
+
:user_id => room['user_id'],
|
149
|
+
:message => room['body'],
|
150
|
+
:timestamp => Time.parse(room['created_at']) }
|
193
151
|
end
|
194
152
|
end
|
195
|
-
|
153
|
+
|
196
154
|
def upload(filename)
|
197
155
|
File.open(filename, "rb") do |file|
|
198
|
-
params = Multipart::MultipartPost.new(
|
199
|
-
|
156
|
+
params = Multipart::MultipartPost.new('upload' => file)
|
157
|
+
connection.post("/room/#{@id}/uploads.json", :body => params.query)
|
200
158
|
end
|
201
159
|
end
|
202
|
-
|
160
|
+
|
203
161
|
# Get the list of latest files for this room
|
204
162
|
def files(count = 5)
|
205
|
-
|
206
|
-
(Hpricot(@room.body)/"#file_list li a").to_a[0,count].map do |link|
|
207
|
-
@campfire.send :url_for, link.attributes['href'][1..-1], :only_path => false
|
208
|
-
end
|
163
|
+
connection.get(room_url_for(:uploads))['uploads'].map { |u| u['full_url'] }
|
209
164
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
returning [] do |messages|
|
215
|
-
response = post("poll.fcgi", {:l => @last_cache_id, :m => @membership_key,
|
216
|
-
:s => @timestamp, :t => "#{Time.now.to_i}000"}, :ajax => true)
|
217
|
-
if response.body.length > 1
|
218
|
-
lines = response.body.split("\r\n")
|
219
|
-
|
220
|
-
if lines.length > 0
|
221
|
-
@last_cache_id = lines.pop.scan(/chat.poller.lastCacheID = (\d+)/).to_s
|
222
|
-
lines.each do |msg|
|
223
|
-
unless msg.match(/timestamp_message/)
|
224
|
-
if msg.length > 0
|
225
|
-
messages << {
|
226
|
-
:id => msg.scan(/message_(\d+)/).to_s,
|
227
|
-
:user_id => msg.scan(/user_(\d+)/).to_s,
|
228
|
-
:person => msg.scan(/\\u003Ctd class=\\"person\\"\\u003E(?:\\u003Cspan\\u003E)?(.+?)(?:\\u003C\/span\\u003E)?\\u003C\/td\\u003E/).to_s,
|
229
|
-
:message => msg.scan(/\\u003Ctd class=\\"body\\"\\u003E\\u003Cdiv\\u003E(.+?)\\u003C\/div\\u003E\\u003C\/td\\u003E/).to_s
|
230
|
-
}
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
165
|
+
|
166
|
+
protected
|
167
|
+
def load
|
168
|
+
reload! unless @loaded
|
236
169
|
end
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
@
|
170
|
+
|
171
|
+
def reload!
|
172
|
+
attributes = connection.get("/room/#{@id}.json")['room']
|
173
|
+
|
174
|
+
@id = attributes['id']
|
175
|
+
@name = attributes['name']
|
176
|
+
@topic = attributes['topic']
|
177
|
+
@full = attributes['full']
|
178
|
+
@open_to_guests = attributes['open-to-guests']
|
179
|
+
@active_token_value = attributes['active-token-value']
|
180
|
+
@users = attributes['users'].map { |u| u['name'] }
|
181
|
+
|
182
|
+
@loaded = true
|
242
183
|
end
|
243
|
-
end
|
244
184
|
|
185
|
+
def send_message(message, type = 'Textmessage')
|
186
|
+
post 'speak', :body => {:message => {:body => message, :type => type}}.to_json
|
187
|
+
end
|
188
|
+
|
189
|
+
def get(action, options = {})
|
190
|
+
connection.get(room_url_for(action), options)
|
191
|
+
end
|
192
|
+
|
193
|
+
def post(action, options = {})
|
194
|
+
connection.post(room_url_for(action), options)
|
195
|
+
end
|
196
|
+
|
197
|
+
def room_url_for(action)
|
198
|
+
"/room/#{@id}/#{action}.json"
|
199
|
+
end
|
200
|
+
|
201
|
+
def connection
|
202
|
+
@campfire.connection
|
203
|
+
end
|
245
204
|
end
|
246
205
|
end
|
data/spec/campfire_spec.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Preparing a campfire request" do
|
4
4
|
before do
|
5
5
|
@campfire = Tinder::Campfire.new("foobar")
|
6
6
|
@request = Net::HTTP::Get.new("does_not_matter")
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def prepare_request
|
10
10
|
@campfire.send(:prepare_request, @request)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "should return the request" do
|
14
14
|
prepare_request.should equal(@request)
|
15
15
|
end
|
@@ -18,14 +18,14 @@ describe "Preparing a campfire request" do
|
|
18
18
|
@campfire.instance_variable_set("@cookie", "foobar")
|
19
19
|
prepare_request['Cookie'].should == 'foobar'
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it "should set the user agent" do
|
23
23
|
prepare_request['User-Agent'].should =~ /^Tinder/
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
# describe "Performing a campfire request" do
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# before do
|
30
30
|
# @response = mock("response")
|
31
31
|
# Net::HTTP.any_instance.stubs(:request).returns(response)
|
@@ -33,56 +33,56 @@ end
|
|
33
33
|
# response.expects(:[]).with('set-cookie').and_return('foobar')
|
34
34
|
# @campfire.send(:perform_request) { request }
|
35
35
|
# end
|
36
|
-
#
|
36
|
+
#
|
37
37
|
# it "should set cookie" do
|
38
38
|
# @campfire.instance_variable_get("@cookie").should == 'foobar'
|
39
39
|
# end
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# end
|
42
42
|
|
43
43
|
describe "Verifying a 200 response" do
|
44
|
-
|
44
|
+
|
45
45
|
before do
|
46
46
|
@campfire = Tinder::Campfire.new("foobar")
|
47
47
|
@response = mock("response")
|
48
48
|
@response.should_receive(:code).and_return(200)
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
it "should return true when expecting success" do
|
52
52
|
@campfire.send(:verify_response, @response, :success).should equal(true)
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
it "should return false when expecting a redirect" do
|
56
56
|
@campfire.send(:verify_response, @response, :redirect).should equal(false)
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
it "should return false when expecting a redirect to a specific path" do
|
60
60
|
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(false)
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
end
|
64
64
|
|
65
65
|
describe "Verifying a 302 response" do
|
66
|
-
|
66
|
+
|
67
67
|
before do
|
68
68
|
@campfire = Tinder::Campfire.new("foobar")
|
69
69
|
@response = mock("response")
|
70
70
|
@response.should_receive(:code).and_return(302)
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
it "should return true when expecting redirect" do
|
74
74
|
@campfire.send(:verify_response, @response, :redirect).should equal(true)
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
it "should return false when expecting success" do
|
78
78
|
@campfire.send(:verify_response, @response, :success).should equal(false)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it "should return true when expecting a redirect to a specific path" do
|
82
82
|
@response.should_receive(:[]).with('location').and_return("/foobar")
|
83
83
|
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(true)
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it "should return false when redirecting to a different path than expected" do
|
87
87
|
@response.should_receive(:[]).with('location').and_return("/baz")
|
88
88
|
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(false)
|
@@ -91,7 +91,7 @@ describe "Verifying a 302 response" do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
describe "A failed login" do
|
94
|
-
|
94
|
+
|
95
95
|
before do
|
96
96
|
@campfire = Tinder::Campfire.new 'foobar'
|
97
97
|
@response = mock("response")
|
@@ -99,18 +99,18 @@ describe "A failed login" do
|
|
99
99
|
@response.should_receive(:code).and_return("302")
|
100
100
|
@response.should_receive(:[]).with("location").and_return("/login")
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
it "should raise an error" do
|
104
104
|
lambda do
|
105
105
|
@campfire.login "doesn't", "matter"
|
106
106
|
end.should raise_error(Tinder::Error)
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
it "should not set logged in status" do
|
110
110
|
@campfire.login 'foo', 'bar' rescue
|
111
111
|
@campfire.logged_in?.should equal(false)
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
end
|
115
115
|
|
116
116
|
describe "Accessing a room with guest access" do
|
@@ -151,40 +151,40 @@ describe "Accessing a room" do
|
|
151
151
|
end
|
152
152
|
|
153
153
|
describe "when the room is full" do
|
154
|
-
|
154
|
+
|
155
155
|
before do
|
156
156
|
@html = File.read(File.dirname(__FILE__) + '/html/full_lobby.html')
|
157
157
|
@response.stub!(:body).and_return(@html)
|
158
158
|
@campfire = Tinder::Campfire.new 'foobar'
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
it "should return a room" do
|
162
162
|
@campfire.rooms.should_not be_empty
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
it "should find a room by name" do
|
166
166
|
@campfire.find_room_by_name("Just Fishin").class.should == Tinder::Room
|
167
167
|
end
|
168
|
-
|
168
|
+
|
169
169
|
end
|
170
170
|
|
171
171
|
describe "when the room is not full" do
|
172
|
-
|
172
|
+
|
173
173
|
before do
|
174
174
|
@html = File.read(File.dirname(__FILE__) + '/html/normal_lobby.html')
|
175
175
|
@response.stub!(:body).and_return(@html)
|
176
176
|
@campfire = Tinder::Campfire.new 'foobar'
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
it "should return a room" do
|
180
180
|
@campfire.rooms.should_not be_empty
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
it "should find a room by name" do
|
184
184
|
@campfire.find_room_by_name("Just Fishin").class.should == Tinder::Room
|
185
185
|
end
|
186
186
|
end
|
187
|
-
|
187
|
+
|
188
188
|
end
|
189
189
|
|
190
190
|
describe "Accessing a room's transcript" do
|
@@ -216,7 +216,7 @@ describe "Accessing a room's transcript" do
|
|
216
216
|
@transcript.second[:timestamp].should == Time.parse("2009-05-05 09:35")
|
217
217
|
end
|
218
218
|
end
|
219
|
-
|
219
|
+
|
220
220
|
describe "when entering the room" do
|
221
221
|
it "a transcript message should include the person who entered" do
|
222
222
|
@transcript.second[:person].should == "Marcel"
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'test_helper'
|
2
|
+
require 'remote/credentials'
|
3
3
|
|
4
4
|
class RemoteCampfireTest < Test::Unit::TestCase
|
5
|
-
|
5
|
+
|
6
6
|
def setup
|
7
7
|
@subdomain = SUBDOMAIN
|
8
8
|
@user, @pass = USER, PASS
|
@@ -10,7 +10,7 @@ class RemoteCampfireTest < Test::Unit::TestCase
|
|
10
10
|
raise "Set your campfire credentials in /test/remote/credentials.rb before running the remote tests" unless @user && @pass && @subdomain
|
11
11
|
@campfire = Tinder::Campfire.new @subdomain, :ssl => @ssl
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def test_ssl_required
|
15
15
|
if @ssl
|
16
16
|
campfire = Tinder::Campfire.new @subdomain
|
@@ -19,32 +19,32 @@ class RemoteCampfireTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def test_create_and_delete_room
|
24
24
|
assert login
|
25
25
|
assert @campfire.logged_in?
|
26
|
-
|
26
|
+
|
27
27
|
room = @campfire.create_room("Testing#{Time.now.to_i}")
|
28
|
-
|
28
|
+
|
29
29
|
assert_instance_of Tinder::Room, room
|
30
30
|
assert_not_nil room.id
|
31
|
-
|
31
|
+
|
32
32
|
room.name = "new name"
|
33
33
|
assert_equal "new name", room.name
|
34
|
-
|
34
|
+
|
35
35
|
room.destroy
|
36
36
|
assert_nil @campfire.find_room_by_name(room.name)
|
37
|
-
|
37
|
+
|
38
38
|
assert @campfire.logout
|
39
39
|
ensure
|
40
40
|
room.destroy rescue nil
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def test_failed_login
|
44
44
|
assert_raises(Tinder::Error) { @campfire.login(@user, 'notmypassword') }
|
45
45
|
assert !@campfire.logged_in?
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def test_find_nonexistent_room
|
49
49
|
login
|
50
50
|
assert_nil @campfire.find_room_by_name('No Room Should Have This Name')
|
@@ -55,5 +55,5 @@ private
|
|
55
55
|
def login(user = @user, pass = @pass)
|
56
56
|
@campfire.login(user, pass)
|
57
57
|
end
|
58
|
-
|
59
|
-
end
|
58
|
+
|
59
|
+
end
|
data/test/test_helper.rb
CHANGED
data/tinder.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tinder}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brandon Keepers"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-17}
|
13
13
|
s.description = %q{An API for interfacing with Campfire, the 37Signals chat application.}
|
14
14
|
s.email = %q{brandon@opensoul.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"init.rb",
|
26
26
|
"lib/tinder.rb",
|
27
27
|
"lib/tinder/campfire.rb",
|
28
|
+
"lib/tinder/connection.rb",
|
28
29
|
"lib/tinder/multipart.rb",
|
29
30
|
"lib/tinder/room.rb",
|
30
31
|
"site/index.html",
|
@@ -44,7 +45,7 @@ Gem::Specification.new do |s|
|
|
44
45
|
s.rdoc_options = ["--charset=UTF-8"]
|
45
46
|
s.require_paths = ["lib"]
|
46
47
|
s.rubyforge_project = %q{tinder}
|
47
|
-
s.rubygems_version = %q{1.3.
|
48
|
+
s.rubygems_version = %q{1.3.5}
|
48
49
|
s.summary = %q{An (unofficial) Campfire API}
|
49
50
|
s.test_files = [
|
50
51
|
"spec/campfire_spec.rb",
|
@@ -59,19 +60,17 @@ Gem::Specification.new do |s|
|
|
59
60
|
|
60
61
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
61
62
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
62
|
-
s.add_runtime_dependency(%q<hpricot>, [">= 0"])
|
63
63
|
s.add_runtime_dependency(%q<mime-types>, [">= 0"])
|
64
64
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
65
65
|
else
|
66
66
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
67
|
-
s.add_dependency(%q<hpricot>, [">= 0"])
|
68
67
|
s.add_dependency(%q<mime-types>, [">= 0"])
|
69
68
|
s.add_dependency(%q<rspec>, [">= 0"])
|
70
69
|
end
|
71
70
|
else
|
72
71
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
73
|
-
s.add_dependency(%q<hpricot>, [">= 0"])
|
74
72
|
s.add_dependency(%q<mime-types>, [">= 0"])
|
75
73
|
s.add_dependency(%q<rspec>, [">= 0"])
|
76
74
|
end
|
77
75
|
end
|
76
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tinder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Keepers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-17 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,16 +22,6 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: hpricot
|
27
|
-
type: :runtime
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: "0"
|
34
|
-
version:
|
35
25
|
- !ruby/object:Gem::Dependency
|
36
26
|
name: mime-types
|
37
27
|
type: :runtime
|
@@ -70,6 +60,7 @@ files:
|
|
70
60
|
- init.rb
|
71
61
|
- lib/tinder.rb
|
72
62
|
- lib/tinder/campfire.rb
|
63
|
+
- lib/tinder/connection.rb
|
73
64
|
- lib/tinder/multipart.rb
|
74
65
|
- lib/tinder/room.rb
|
75
66
|
- site/index.html
|
@@ -108,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
99
|
requirements: []
|
109
100
|
|
110
101
|
rubyforge_project: tinder
|
111
|
-
rubygems_version: 1.3.
|
102
|
+
rubygems_version: 1.3.5
|
112
103
|
signing_key:
|
113
104
|
specification_version: 3
|
114
105
|
summary: An (unofficial) Campfire API
|