campfire_export 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ rspec = RSpec::Core::RakeTask.new
6
+ rspec.rspec_opts = '-f Fuubar --color'
data/bin/campfire_export CHANGED
@@ -53,5 +53,14 @@ ensure_config_for(config, 'subdomain',
53
53
  ensure_config_for(config, 'api_token',
54
54
  "Your Campfire API token (see 'My Info' on your Campfire site)")
55
55
 
56
- account = CampfireExport::Account.new(config['subdomain'], config['api_token'])
57
- account.export(config_date(config, 'start_date'), config_date(config, 'end_date'))
56
+ begin
57
+ account = CampfireExport::Account.new(config['subdomain'],
58
+ config['api_token'])
59
+ account.find_timezone
60
+ account.rooms.each do |room|
61
+ room.export(config_date(config, 'start_date'),
62
+ config_date(config, 'end_date'))
63
+ end
64
+ rescue => e
65
+ puts "Unable to export account: #{e}"
66
+ end
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.required_ruby_version = '>= 1.8.7'
18
18
 
19
19
  s.add_development_dependency "bundler", "~> 1.0.15"
20
+ s.add_development_dependency "fuubar", "~> 0.0.5"
21
+ s.add_development_dependency "rspec", "~> 2.6.0"
20
22
  s.add_development_dependency "tzinfo", "~> 0.3.29"
21
23
  s.add_development_dependency "httparty", "~> 0.7.8"
22
24
  s.add_development_dependency "nokogiri", "~> 1.4.5"
@@ -162,7 +162,7 @@ module CampfireExport
162
162
  MAPPING.freeze
163
163
 
164
164
  def find_tzinfo(name)
165
- TZInfo::TimezoneProxy.new(MAPPING[name] || name)
165
+ TZInfo::Timezone.get(MAPPING[name] || name)
166
166
  end
167
167
  end
168
168
  end
@@ -1,3 +1,3 @@
1
1
  module CampfireExport
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -51,14 +51,10 @@ module CampfireExport
51
51
  def zero_pad(number)
52
52
  "%02d" % number
53
53
  end
54
-
55
- def account_dir
56
- "campfire/#{CampfireExport::Account.subdomain}"
57
- end
58
-
54
+
59
55
  # Requires that room and date be defined in the calling object.
60
56
  def export_dir
61
- "#{account_dir}/#{room.name}/" +
57
+ "campfire/#{Account.subdomain}/#{room.name}/" +
62
58
  "#{date.year}/#{zero_pad(date.mon)}/#{zero_pad(date.day)}"
63
59
  end
64
60
 
@@ -66,6 +62,7 @@ module CampfireExport
66
62
  def export_file(content, filename, mode='w')
67
63
  # Check to make sure we're writing into the target directory tree.
68
64
  true_path = File.expand_path(File.join(export_dir, filename))
65
+
69
66
  unless true_path.start_with?(File.expand_path(export_dir))
70
67
  raise CampfireExport::Exception.new("#{export_dir}/#{filename}",
71
68
  "can't export file to a directory higher than target directory; " +
@@ -133,45 +130,28 @@ module CampfireExport
133
130
  @subdomain = ""
134
131
  @api_token = ""
135
132
  @base_url = ""
136
- @timezone = ""
133
+ @timezone = nil
137
134
 
138
135
  class << self
139
136
  attr_accessor :subdomain, :api_token, :base_url, :timezone
140
137
  end
141
138
 
142
139
  def initialize(subdomain, api_token)
143
- CampfireExport::Account.subdomain = subdomain
144
- CampfireExport::Account.api_token = api_token
145
- CampfireExport::Account.base_url = "https://#{subdomain}.campfirenow.com"
146
-
147
- # Make the base directory immediately so we can start logging errors.
148
- FileUtils.mkdir_p account_dir
149
-
150
- CampfireExport::Account.timezone = parse_timezone
140
+ Account.subdomain = subdomain
141
+ Account.api_token = api_token
142
+ Account.base_url = "https://#{subdomain}.campfirenow.com"
151
143
  end
152
-
153
- def parse_timezone
154
- begin
155
- settings_html = Nokogiri::HTML get('/account/settings').body
156
- selected_zone = settings_html.css('select[id="account_time_zone_id"] ' +
157
- '> option[selected="selected"]')
158
- find_tzinfo(selected_zone.attribute("value").text)
159
- rescue => e
160
- log(:error, "couldn't find timezone setting (using GMT instead)", e)
161
- find_tzinfo("Etc/GMT")
162
- end
144
+
145
+ def find_timezone
146
+ settings = Nokogiri::HTML get('/account/settings').body
147
+ selected_zone = settings.css('select[id="account_time_zone_id"] ' +
148
+ '> option[selected="selected"]')
149
+ Account.timezone = find_tzinfo(selected_zone.attribute("value").text)
163
150
  end
164
-
165
- def export(start_date=nil, end_date=nil)
166
- begin
167
- doc = Nokogiri::XML get('/rooms.xml').body
168
- doc.css('room').each do |room_xml|
169
- room = CampfireExport::Room.new(room_xml)
170
- room.export(start_date, end_date)
171
- end
172
- rescue => e
173
- log(:error, "room list download failed", e)
174
- end
151
+
152
+ def rooms
153
+ doc = Nokogiri::XML get('/rooms.xml').body
154
+ doc.css('room').map {|room_xml| Room.new(room_xml) }
175
155
  end
176
156
  end
177
157
 
@@ -180,30 +160,21 @@ module CampfireExport
180
160
  attr_accessor :id, :name, :created_at, :last_update
181
161
 
182
162
  def initialize(room_xml)
183
- @id = room_xml.css('id').text
184
- @name = room_xml.css('name').text
185
-
186
- created_utc = DateTime.parse(room_xml.css('created-at').text)
187
- @created_at = CampfireExport::Account.timezone.utc_to_local(created_utc)
188
-
189
- begin
190
- last_message = Nokogiri::XML get("/room/#{id}/recent.xml?limit=1").body
191
- update_utc = DateTime.parse(last_message.css('created-at').text)
192
- @last_update = CampfireExport::Account.timezone.utc_to_local(update_utc)
193
- rescue => e
194
- log(:error, "couldn't get last update in #{room} (defaulting to today)", e)
195
- @last_update = Time.now
196
- end
163
+ @id = room_xml.css('id').text
164
+ @name = room_xml.css('name').text
165
+ created_utc = DateTime.parse(room_xml.css('created-at').text)
166
+ @created_at = Account.timezone.utc_to_local(created_utc)
197
167
  end
198
-
168
+
199
169
  def export(start_date=nil, end_date=nil)
200
170
  # Figure out how to do the least amount of work while still conforming
201
171
  # to the requester's boundary dates.
172
+ find_last_update
202
173
  start_date.nil? ? date = created_at : date = [start_date, created_at].max
203
174
  end_date.nil? ? end_date = last_update : end_date = [end_date, last_update].min
204
175
 
205
176
  while date <= end_date
206
- transcript = CampfireExport::Transcript.new(self, date)
177
+ transcript = Transcript.new(self, date)
207
178
  transcript.export
208
179
 
209
180
  # Ensure that we stay well below the 37signals API limits.
@@ -211,6 +182,20 @@ module CampfireExport
211
182
  date = date.next
212
183
  end
213
184
  end
185
+
186
+ private
187
+ def find_last_update
188
+ begin
189
+ last_message = Nokogiri::XML get("/room/#{id}/recent.xml?limit=1").body
190
+ update_utc = DateTime.parse(last_message.css('created-at').text)
191
+ @last_update = Account.timezone.utc_to_local(update_utc)
192
+ rescue Exception => e
193
+ log(:error,
194
+ "couldn't get last update in #{room} (defaulting to today)",
195
+ e)
196
+ @last_update = Time.now
197
+ end
198
+ end
214
199
  end
215
200
 
216
201
  class Transcript
@@ -242,7 +227,7 @@ module CampfireExport
242
227
  log(:info, "exporting transcripts\n")
243
228
  begin
244
229
  FileUtils.mkdir_p export_dir
245
- rescue => e
230
+ rescue Exception => e
246
231
  log(:error, "Unable to create #{export_dir}", e)
247
232
  else
248
233
  export_xml
@@ -260,7 +245,7 @@ module CampfireExport
260
245
  begin
261
246
  export_file(xml, 'transcript.xml')
262
247
  verify_export('transcript.xml', xml.to_s.length)
263
- rescue => e
248
+ rescue Exception => e
264
249
  log(:error, "XML transcript export for #{export_dir} failed", e)
265
250
  end
266
251
  end
@@ -273,7 +258,7 @@ module CampfireExport
273
258
  messages.each {|message| plaintext << message.to_s }
274
259
  export_file(plaintext, 'transcript.txt')
275
260
  verify_export('transcript.txt', plaintext.length)
276
- rescue => e
261
+ rescue Exception => e
277
262
  log(:error, "Plaintext transcript export for #{export_dir} failed", e)
278
263
  end
279
264
  end
@@ -293,7 +278,7 @@ module CampfireExport
293
278
 
294
279
  export_file(transcript_html, 'transcript.html')
295
280
  verify_export('transcript.html', transcript_html.length)
296
- rescue => e
281
+ rescue Exception => e
297
282
  log(:error, "HTML transcript export for #{export_dir} failed", e)
298
283
  end
299
284
  end
@@ -303,7 +288,7 @@ module CampfireExport
303
288
  if message.is_upload?
304
289
  begin
305
290
  message.upload.export
306
- rescue => e
291
+ rescue Exception => e
307
292
  path = "#{message.upload.export_dir}/#{message.upload.filename}"
308
293
  log(:error, "Upload export for #{path} failed", e)
309
294
  end
@@ -339,7 +324,7 @@ module CampfireExport
339
324
  @@usernames ||= {}
340
325
  @@usernames[user_id] ||= begin
341
326
  doc = Nokogiri::XML get("/users/#{user_id}.xml").body
342
- rescue
327
+ rescue Exception => e
343
328
  "[unknown user]"
344
329
  else
345
330
  # Take the first name and last initial, if there is more than one name.
@@ -0,0 +1,76 @@
1
+ require 'campfire_export'
2
+ require 'tzinfo'
3
+
4
+ module CampfireExport
5
+ describe Account do
6
+ before(:each) do
7
+ @subdomain = "test-subdomain"
8
+ @api_token = "test-apikey"
9
+ @account = Account.new(@subdomain, @api_token)
10
+
11
+ @good_timezone = '<select id="account_time_zone_id">' +
12
+ '<option selected="selected" value="America/Los_Angeles">' +
13
+ '</option></select>'
14
+ @bad_timezone = @good_timezone.gsub('America/Los_Angeles',
15
+ 'No Such Timezone')
16
+ @timezone_html = stub("timezone HTML block")
17
+ @timezone_html.stub(:body).and_return(@good_timezone)
18
+ end
19
+
20
+ context "when it is created" do
21
+ it "sets up the account config variables" do
22
+ Account.subdomain.should equal(@subdomain)
23
+ Account.api_token.should equal(@api_token)
24
+ Account.base_url.should == "https://#{@subdomain}.campfirenow.com"
25
+ end
26
+ end
27
+
28
+ context "when timezone is loaded" do
29
+ it "determines the user's timezone" do
30
+ @account.should_receive(:get).with("/account/settings"
31
+ ).and_return(@timezone_html)
32
+ @account.find_timezone
33
+ Account.timezone.to_s.should == "America - Los Angeles"
34
+ end
35
+
36
+ it "raises an error if it gets a bad time zone identifier" do
37
+ @timezone_html.stub(:body).and_return(@bad_timezone)
38
+ @account.stub(:get).with("/account/settings"
39
+ ).and_return(@timezone_html)
40
+ expect {
41
+ @account.find_timezone
42
+ }.to raise_error(TZInfo::InvalidTimezoneIdentifier)
43
+ end
44
+
45
+ it "raises an error if it can't get the account settings at all" do
46
+ @account.stub(:get).with("/account/settings"
47
+ ).and_raise(CampfireExport::Exception.new("/account/settings",
48
+ "Not Found", 404))
49
+ expect {
50
+ @account.find_timezone
51
+ }.to raise_error(CampfireExport::Exception)
52
+ end
53
+ end
54
+
55
+ context "when rooms are requested" do
56
+ it "returns an array of rooms" do
57
+ room_xml = "<rooms><room>1</room><room>2</room><room>3</room></rooms>"
58
+ room_doc = mock("room doc")
59
+ room_doc.should_receive(:body).and_return(room_xml)
60
+ @account.should_receive(:get).with('/rooms.xml').and_return(room_doc)
61
+ room = mock("room")
62
+ Room.should_receive(:new).exactly(3).times.and_return(room)
63
+ @account.rooms.should have(3).items
64
+ end
65
+
66
+ it "raises an error if it can't get the room list" do
67
+ @account.stub(:get).with('/rooms.xml'
68
+ ).and_raise(CampfireExport::Exception.new('/rooms.xml',
69
+ "Not Found", 404))
70
+ expect {
71
+ @account.rooms
72
+ }.to raise_error(CampfireExport::Exception)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,29 @@
1
+ require 'campfire_export'
2
+ require 'campfire_export/timezone'
3
+
4
+ require 'nokogiri'
5
+
6
+ module CampfireExport
7
+ describe Room do
8
+ include TimeZone
9
+
10
+ before :each do
11
+ @room_xml = Nokogiri::XML "<room><name>Test Room</name><id>666</id>" +
12
+ "<created-at>2009-11-17T19:41:38Z</created-at></room>"
13
+ Account.timezone = find_tzinfo("America/Los_Angeles")
14
+ end
15
+
16
+ context "when it is created" do
17
+ it "sets up basic properties" do
18
+ room = Room.new(@room_xml)
19
+ room.name.should == "Test Room"
20
+ room.id.should == "666"
21
+ room.created_at.should == DateTime.parse("2009-11-17T11:41:38Z")
22
+ end
23
+ end
24
+
25
+ context "when it finds the last update" do
26
+ it "loads the last update from the most recent message"
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: campfire_export
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 1
9
- - 0
10
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - Marc Hedlund
@@ -15,17 +14,16 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-07-09 00:00:00 Z
17
+ date: 2011-08-04 00:00:00 -04:00
18
+ default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: bundler
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
24
  requirements:
26
25
  - - ~>
27
26
  - !ruby/object:Gem::Version
28
- hash: 9
29
27
  segments:
30
28
  - 1
31
29
  - 0
@@ -34,53 +32,75 @@ dependencies:
34
32
  type: :development
35
33
  version_requirements: *id001
36
34
  - !ruby/object:Gem::Dependency
37
- name: tzinfo
35
+ name: fuubar
38
36
  prerelease: false
39
37
  requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
38
  requirements:
42
39
  - - ~>
43
40
  - !ruby/object:Gem::Version
44
- hash: 41
41
+ segments:
42
+ - 0
43
+ - 0
44
+ - 5
45
+ version: 0.0.5
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 2
57
+ - 6
58
+ - 0
59
+ version: 2.6.0
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: tzinfo
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
45
69
  segments:
46
70
  - 0
47
71
  - 3
48
72
  - 29
49
73
  version: 0.3.29
50
74
  type: :development
51
- version_requirements: *id002
75
+ version_requirements: *id004
52
76
  - !ruby/object:Gem::Dependency
53
77
  name: httparty
54
78
  prerelease: false
55
- requirement: &id003 !ruby/object:Gem::Requirement
56
- none: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
57
80
  requirements:
58
81
  - - ~>
59
82
  - !ruby/object:Gem::Version
60
- hash: 19
61
83
  segments:
62
84
  - 0
63
85
  - 7
64
86
  - 8
65
87
  version: 0.7.8
66
88
  type: :development
67
- version_requirements: *id003
89
+ version_requirements: *id005
68
90
  - !ruby/object:Gem::Dependency
69
91
  name: nokogiri
70
92
  prerelease: false
71
- requirement: &id004 !ruby/object:Gem::Requirement
72
- none: false
93
+ requirement: &id006 !ruby/object:Gem::Requirement
73
94
  requirements:
74
95
  - - ~>
75
96
  - !ruby/object:Gem::Version
76
- hash: 13
77
97
  segments:
78
98
  - 1
79
99
  - 4
80
100
  - 5
81
101
  version: 1.4.5
82
102
  type: :development
83
- version_requirements: *id004
103
+ version_requirements: *id006
84
104
  description: Export transcripts and uploaded files from your 37signals' Campfire account.
85
105
  email:
86
106
  - marc@precipice.org
@@ -101,6 +121,9 @@ files:
101
121
  - lib/campfire_export.rb
102
122
  - lib/campfire_export/timezone.rb
103
123
  - lib/campfire_export/version.rb
124
+ - spec/campfire_export/account_spec.rb
125
+ - spec/campfire_export/room_spec.rb
126
+ has_rdoc: true
104
127
  homepage: https://github.com/precipice/campfire_export
105
128
  licenses:
106
129
  - Apache 2.0
@@ -110,31 +133,28 @@ rdoc_options: []
110
133
  require_paths:
111
134
  - lib
112
135
  required_ruby_version: !ruby/object:Gem::Requirement
113
- none: false
114
136
  requirements:
115
137
  - - ">="
116
138
  - !ruby/object:Gem::Version
117
- hash: 57
118
139
  segments:
119
140
  - 1
120
141
  - 8
121
142
  - 7
122
143
  version: 1.8.7
123
144
  required_rubygems_version: !ruby/object:Gem::Requirement
124
- none: false
125
145
  requirements:
126
146
  - - ">="
127
147
  - !ruby/object:Gem::Version
128
- hash: 3
129
148
  segments:
130
149
  - 0
131
150
  version: "0"
132
151
  requirements: []
133
152
 
134
153
  rubyforge_project: campfire_export
135
- rubygems_version: 1.8.5
154
+ rubygems_version: 1.3.6
136
155
  signing_key:
137
156
  specification_version: 3
138
157
  summary: Export transcripts and uploaded files from your 37signals' Campfire account.
139
- test_files: []
140
-
158
+ test_files:
159
+ - spec/campfire_export/account_spec.rb
160
+ - spec/campfire_export/room_spec.rb