stackbuilders-campfire_export 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +160 -0
- data/README.md +114 -0
- data/Rakefile +12 -0
- data/bin/campfire_export +66 -0
- data/campfire_export.gemspec +36 -0
- data/lib/campfire_export/account.rb +32 -0
- data/lib/campfire_export/exception.rb +16 -0
- data/lib/campfire_export/message.rb +95 -0
- data/lib/campfire_export/room.rb +44 -0
- data/lib/campfire_export/timezone.rb +168 -0
- data/lib/campfire_export/transcript.rb +100 -0
- data/lib/campfire_export/upload.rb +78 -0
- data/lib/campfire_export/version.rb +3 -0
- data/lib/campfire_export.rb +133 -0
- data/spec/campfire_export/account_spec.rb +85 -0
- data/spec/campfire_export/message_spec.rb +60 -0
- data/spec/campfire_export/room_spec.rb +27 -0
- data/spec/spec_helper.rb +4 -0
- metadata +174 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Upload
|
3
|
+
include CampfireExport::IO
|
4
|
+
attr_accessor :message, :room, :date, :id, :filename, :content_type, :byte_size, :full_url
|
5
|
+
|
6
|
+
def initialize(message)
|
7
|
+
@message = message
|
8
|
+
@room = message.room
|
9
|
+
@date = message.date
|
10
|
+
@deleted = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def deleted?
|
14
|
+
@deleted
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_image?
|
18
|
+
content_type.start_with?("image/")
|
19
|
+
end
|
20
|
+
|
21
|
+
def upload_dir
|
22
|
+
"uploads/#{id}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Image thumbnails are used to inline image uploads in HTML transcripts.
|
26
|
+
def thumb_dir
|
27
|
+
"thumbs/#{id}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def export
|
31
|
+
begin
|
32
|
+
log(:info, " #{message.body} ... ")
|
33
|
+
|
34
|
+
# Get the upload object corresponding to this message.
|
35
|
+
upload_path = "/room/#{room.id}/messages/#{message.id}/upload.xml"
|
36
|
+
upload = Nokogiri::XML get(upload_path).body
|
37
|
+
|
38
|
+
# Get the upload itself and export it.
|
39
|
+
@id = upload.xpath('/upload/id').text
|
40
|
+
@byte_size = upload.xpath('/upload/byte-size').text.to_i
|
41
|
+
@content_type = upload.xpath('/upload/content-type').text
|
42
|
+
@filename = upload.xpath('/upload/name').text
|
43
|
+
@full_url = upload.xpath('/upload/full-url').text
|
44
|
+
|
45
|
+
export_content(upload_dir)
|
46
|
+
export_content(thumb_dir, path_component="thumb/#{id}", verify=false) if is_image?
|
47
|
+
|
48
|
+
log(:info, "ok\n")
|
49
|
+
rescue CampfireExport::Exception => e
|
50
|
+
if e.code == 404
|
51
|
+
# If the upload 404s, that should mean it was subsequently deleted.
|
52
|
+
@deleted = true
|
53
|
+
log(:info, "deleted\n")
|
54
|
+
else
|
55
|
+
raise e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def export_content(content_dir, path_component=nil, verify=true)
|
61
|
+
# If the export directory name is different than the URL path component,
|
62
|
+
# the caller can define the path_component separately.
|
63
|
+
path_component ||= content_dir
|
64
|
+
|
65
|
+
# Write uploads to a subdirectory, using the upload ID as a directory
|
66
|
+
# name to avoid overwriting multiple uploads of the same file within
|
67
|
+
# the same day (for instance, if 'Picture 1.png' is uploaded twice
|
68
|
+
# in a day, this will preserve both copies). This path pattern also
|
69
|
+
# matches the tail of the upload path in the HTML transcript, making
|
70
|
+
# it easier to make downloads functional from the HTML transcripts.
|
71
|
+
content_path = "/room/#{room.id}/#{path_component}/#{CGI.escape(filename)}"
|
72
|
+
content = get(content_path).body
|
73
|
+
FileUtils.mkdir_p(File.join(export_dir, content_dir))
|
74
|
+
export_file(content, "#{content_dir}/#{filename}", 'wb')
|
75
|
+
verify_export("#{content_dir}/#{filename}", byte_size) if verify
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Portions copyright 2011 Marc Hedlund <marc@precipice.org>.
|
4
|
+
# Adapted from https://gist.github.com/821553 and ancestors.
|
5
|
+
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
# campfire_export.rb -- export Campfire transcripts and uploaded files.
|
19
|
+
#
|
20
|
+
# Since Campfire (www.campfirenow.com) doesn't provide an export feature,
|
21
|
+
# this script implements one via the Campfire API.
|
22
|
+
|
23
|
+
require 'rubygems'
|
24
|
+
|
25
|
+
require 'cgi'
|
26
|
+
require 'fileutils'
|
27
|
+
require 'httparty'
|
28
|
+
require 'nokogiri'
|
29
|
+
require 'retryable'
|
30
|
+
require 'time'
|
31
|
+
require 'yaml'
|
32
|
+
|
33
|
+
module CampfireExport
|
34
|
+
module IO
|
35
|
+
MAX_RETRIES = 5
|
36
|
+
|
37
|
+
def api_url(path)
|
38
|
+
"#{CampfireExport::Account.base_url}#{path}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(path, params = {})
|
42
|
+
url = api_url(path)
|
43
|
+
|
44
|
+
response = Retryable.retryable(:tries => MAX_RETRIES) do |retries, exception|
|
45
|
+
if retries > 0
|
46
|
+
msg = "Attempt ##{retries} to fetch #{path} failed, " +
|
47
|
+
"#{MAX_RETRIES - retries} attempts remaining"
|
48
|
+
log :error, msg, exception
|
49
|
+
end
|
50
|
+
|
51
|
+
HTTParty.get(url, :query => params, :basic_auth =>
|
52
|
+
{:username => CampfireExport::Account.api_token, :password => 'X'})
|
53
|
+
end
|
54
|
+
|
55
|
+
if response.code >= 400
|
56
|
+
raise CampfireExport::Exception.new(url, response.message, response.code)
|
57
|
+
end
|
58
|
+
response
|
59
|
+
end
|
60
|
+
|
61
|
+
def zero_pad(number)
|
62
|
+
"%02d" % number
|
63
|
+
end
|
64
|
+
|
65
|
+
# Requires that room and date be defined in the calling object.
|
66
|
+
def export_dir
|
67
|
+
"campfire/#{Account.subdomain}/#{room.name}/" +
|
68
|
+
"#{date.year}/#{zero_pad(date.mon)}/#{zero_pad(date.day)}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Requires that room_name and date be defined in the calling object.
|
72
|
+
def export_file(content, filename, mode='w')
|
73
|
+
# Check to make sure we're writing into the target directory tree.
|
74
|
+
true_path = File.expand_path(File.join(export_dir, filename))
|
75
|
+
|
76
|
+
unless true_path.start_with?(File.expand_path(export_dir))
|
77
|
+
raise CampfireExport::Exception.new("#{export_dir}/#{filename}",
|
78
|
+
"can't export file to a directory higher than target directory; " +
|
79
|
+
"expected: #{File.expand_path(export_dir)}, actual: #{true_path}.")
|
80
|
+
end
|
81
|
+
|
82
|
+
if File.exists?("#{export_dir}/#{filename}")
|
83
|
+
log(:error, "#{export_dir}/#{filename} failed: file already exists")
|
84
|
+
else
|
85
|
+
open("#{export_dir}/#{filename}", mode) do |file|
|
86
|
+
file.write content
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def verify_export(filename, expected_size)
|
92
|
+
full_path = "#{export_dir}/#{filename}"
|
93
|
+
unless File.exists?(full_path)
|
94
|
+
raise CampfireExport::Exception.new(full_path,
|
95
|
+
"file should have been exported but did not make it to disk")
|
96
|
+
end
|
97
|
+
unless File.size(full_path) == expected_size
|
98
|
+
raise CampfireExport::Exception.new(full_path,
|
99
|
+
"exported file exists but is not the right size " +
|
100
|
+
"(expected: #{expected_size}, actual: #{File.size(full_path)})")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def log(level, message, exception=nil)
|
105
|
+
case level
|
106
|
+
when :error
|
107
|
+
short_error = ["*** Error: #{message}", exception].compact.join(": ")
|
108
|
+
$stderr.puts short_error
|
109
|
+
open("campfire/export_errors.txt", 'a') do |log|
|
110
|
+
log.write short_error
|
111
|
+
unless exception.nil?
|
112
|
+
log.write %Q{\n\t#{exception.backtrace.join("\n\t")}}
|
113
|
+
end
|
114
|
+
log.write "\n"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
print message
|
118
|
+
$stdout.flush
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
require 'campfire_export/timezone'
|
126
|
+
|
127
|
+
require 'campfire_export/account'
|
128
|
+
require 'campfire_export/exception'
|
129
|
+
require 'campfire_export/message'
|
130
|
+
require 'campfire_export/room'
|
131
|
+
require 'campfire_export/transcript'
|
132
|
+
require 'campfire_export/upload'
|
133
|
+
require 'campfire_export/version'
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CampfireExport
|
4
|
+
describe Account do
|
5
|
+
before(:each) do
|
6
|
+
@subdomain = "test-subdomain"
|
7
|
+
@api_token = "test-apikey"
|
8
|
+
@account = Account.new(@subdomain, @api_token)
|
9
|
+
|
10
|
+
@good_timezone = '<?xml version="1.0" encoding="UTF-8"?>' +
|
11
|
+
'<account>' +
|
12
|
+
' <time-zone>America/Los_Angeles</time-zone>' +
|
13
|
+
' <owner-id type="integer">99999</owner-id>' +
|
14
|
+
' <created-at type="datetime">2010-01-31T18:30:18Z</created-at>' +
|
15
|
+
' <storage type="integer">9999999</storage>' +
|
16
|
+
' <plan>basic</plan>' +
|
17
|
+
' <updated-at type="datetime">2010-01-31T18:31:55Z</updated-at>' +
|
18
|
+
' <subdomain>example</subdomain>' +
|
19
|
+
' <name>Example</name>' +
|
20
|
+
' <id type="integer">999999</id>' +
|
21
|
+
'</account>'
|
22
|
+
|
23
|
+
@bad_timezone = @good_timezone.gsub('America/Los_Angeles',
|
24
|
+
'No Such Timezone')
|
25
|
+
@account_xml = stub("Account XML")
|
26
|
+
@account_xml.stub(:body).and_return(@good_timezone)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when it is created" do
|
30
|
+
it "sets up the account config variables" do
|
31
|
+
Account.subdomain.should equal(@subdomain)
|
32
|
+
Account.api_token.should equal(@api_token)
|
33
|
+
Account.base_url.should == "https://#{@subdomain}.campfirenow.com"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when timezone is loaded" do
|
38
|
+
it "determines the user's timezone" do
|
39
|
+
@account.should_receive(:get).with("/account.xml"
|
40
|
+
).and_return(@account_xml)
|
41
|
+
@account.find_timezone
|
42
|
+
Account.timezone.to_s.should == "America - Los Angeles"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises an error if it gets a bad time zone identifier" do
|
46
|
+
@account_xml.stub(:body).and_return(@bad_timezone)
|
47
|
+
@account.stub(:get).with("/account.xml"
|
48
|
+
).and_return(@account_xml)
|
49
|
+
expect {
|
50
|
+
@account.find_timezone
|
51
|
+
}.to raise_error(TZInfo::InvalidTimezoneIdentifier)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raises an error if it can't get the account settings at all" do
|
55
|
+
@account.stub(:get).with("/account.xml"
|
56
|
+
).and_raise(CampfireExport::Exception.new("/account/settings",
|
57
|
+
"Not Found", 404))
|
58
|
+
expect {
|
59
|
+
@account.find_timezone
|
60
|
+
}.to raise_error(CampfireExport::Exception)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when rooms are requested" do
|
65
|
+
it "returns an array of rooms" do
|
66
|
+
room_xml = "<rooms><room>1</room><room>2</room><room>3</room></rooms>"
|
67
|
+
room_doc = mock("room doc")
|
68
|
+
room_doc.should_receive(:body).and_return(room_xml)
|
69
|
+
@account.should_receive(:get).with('/rooms.xml').and_return(room_doc)
|
70
|
+
room = mock("room")
|
71
|
+
Room.should_receive(:new).exactly(3).times.and_return(room)
|
72
|
+
@account.rooms.should have(3).items
|
73
|
+
end
|
74
|
+
|
75
|
+
it "raises an error if it can't get the room list" do
|
76
|
+
@account.stub(:get).with('/rooms.xml'
|
77
|
+
).and_raise(CampfireExport::Exception.new('/rooms.xml',
|
78
|
+
"Not Found", 404))
|
79
|
+
expect {
|
80
|
+
@account.rooms
|
81
|
+
}.to raise_error(CampfireExport::Exception)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CampfireExport
|
4
|
+
describe Message do
|
5
|
+
include TimeZone
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@messages = Nokogiri::XML <<XML
|
9
|
+
<messages>
|
10
|
+
<message>
|
11
|
+
<created-at type="datetime">2012-05-11T17:45:00Z</created-at>
|
12
|
+
<id type="integer">111</id>
|
13
|
+
<room-id type="integer">222</room-id>
|
14
|
+
<user-id type="integer" nil="true"/>
|
15
|
+
<body nil="true"/>
|
16
|
+
<type>TimestampMessage</type>
|
17
|
+
</message>
|
18
|
+
<message>
|
19
|
+
<created-at type="datetime">2012-05-11T17:47:20Z</created-at>
|
20
|
+
<id type="integer">333</id>
|
21
|
+
<room-id type="integer">222</room-id>
|
22
|
+
<user-id type="integer">555</user-id>
|
23
|
+
<body>This is a tweet</body>
|
24
|
+
<type>TweetMessage</type>
|
25
|
+
<tweet>
|
26
|
+
<id>20100487385931234</id>
|
27
|
+
<message>This is a tweet</message>
|
28
|
+
<author_username>twitter_user</author_username>
|
29
|
+
<author_avatar_url>avatar.jpg</author_avatar_url>
|
30
|
+
</tweet>
|
31
|
+
</message>
|
32
|
+
<message>
|
33
|
+
<created-at type="datetime">2012-05-11T17:47:23Z</created-at>
|
34
|
+
<id type="integer">666</id>
|
35
|
+
<room-id type="integer">222</room-id>
|
36
|
+
<user-id type="integer">555</user-id>
|
37
|
+
<body>Regular message</body>
|
38
|
+
<type>TextMessage</type>
|
39
|
+
</message>
|
40
|
+
</messages>
|
41
|
+
XML
|
42
|
+
Account.timezone = find_tzinfo("America/Los_Angeles")
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when it is created" do
|
46
|
+
it "sets up basic properties" do
|
47
|
+
message = Message.new(@messages.xpath('/messages/message[3]')[0], nil, nil)
|
48
|
+
message.body.should == "Regular message"
|
49
|
+
message.id.should == "666"
|
50
|
+
message.timestamp.should == "10:47 AM"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "handles tweets correctly" do
|
54
|
+
message = Message.new(@messages.xpath('/messages/message[2]'), nil, nil)
|
55
|
+
message.body.should == "This is a tweet"
|
56
|
+
message.id.should == "333"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CampfireExport
|
4
|
+
describe Room do
|
5
|
+
include TimeZone
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
doc = Nokogiri::XML "<room><name>Test Room</name><id>666</id>" +
|
9
|
+
"<created-at>2009-11-17T19:41:38Z</created-at></room>"
|
10
|
+
@room_xml = doc.xpath('/room')
|
11
|
+
Account.timezone = find_tzinfo("America/Los_Angeles")
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when it is created" do
|
15
|
+
it "sets up basic properties" do
|
16
|
+
room = Room.new(@room_xml)
|
17
|
+
room.name.should == "Test Room"
|
18
|
+
room.id.should == "666"
|
19
|
+
room.created_at.should == DateTime.parse("2009-11-17T11:41:38Z")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when it finds the last update" do
|
24
|
+
it "loads the last update from the most recent message"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stackbuilders-campfire_export
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marc Hedlund
|
8
|
+
- Justin Leitgeb
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-03-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '2.6'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '2.6'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: tzinfo
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.2'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.2'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: httparty
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.13'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.13'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: nokogiri
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.6'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.6'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: retryable
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '2.0'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '2.0'
|
112
|
+
description: |-
|
113
|
+
Exports content from all rooms in a
|
114
|
+
37signals Campfire account. Creates a directory containing transcripts
|
115
|
+
and content uploaded to each one of your rooms. Can be configured to
|
116
|
+
recognize start and end date of content export.
|
117
|
+
email:
|
118
|
+
- marc@precipice.org
|
119
|
+
- justin@stackbuilders.com
|
120
|
+
executables:
|
121
|
+
- campfire_export
|
122
|
+
extensions: []
|
123
|
+
extra_rdoc_files: []
|
124
|
+
files:
|
125
|
+
- ".gitignore"
|
126
|
+
- ".travis.yml"
|
127
|
+
- Gemfile
|
128
|
+
- LICENSE.txt
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
- bin/campfire_export
|
132
|
+
- campfire_export.gemspec
|
133
|
+
- lib/campfire_export.rb
|
134
|
+
- lib/campfire_export/account.rb
|
135
|
+
- lib/campfire_export/exception.rb
|
136
|
+
- lib/campfire_export/message.rb
|
137
|
+
- lib/campfire_export/room.rb
|
138
|
+
- lib/campfire_export/timezone.rb
|
139
|
+
- lib/campfire_export/transcript.rb
|
140
|
+
- lib/campfire_export/upload.rb
|
141
|
+
- lib/campfire_export/version.rb
|
142
|
+
- spec/campfire_export/account_spec.rb
|
143
|
+
- spec/campfire_export/message_spec.rb
|
144
|
+
- spec/campfire_export/room_spec.rb
|
145
|
+
- spec/spec_helper.rb
|
146
|
+
homepage: https://github.com/stackbuilders/campfire_export
|
147
|
+
licenses:
|
148
|
+
- Apache 2.0
|
149
|
+
metadata: {}
|
150
|
+
post_install_message:
|
151
|
+
rdoc_options: []
|
152
|
+
require_paths:
|
153
|
+
- lib
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 1.9.3
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
requirements: []
|
165
|
+
rubyforge_project: campfire_export
|
166
|
+
rubygems_version: 2.4.6
|
167
|
+
signing_key:
|
168
|
+
specification_version: 4
|
169
|
+
summary: Export transcripts and uploaded files from your 37signals' Campfire account.
|
170
|
+
test_files:
|
171
|
+
- spec/campfire_export/account_spec.rb
|
172
|
+
- spec/campfire_export/message_spec.rb
|
173
|
+
- spec/campfire_export/room_spec.rb
|
174
|
+
- spec/spec_helper.rb
|