stackbuilders-campfire_export 0.4.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.
- 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,32 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Account
|
3
|
+
include CampfireExport::IO
|
4
|
+
include CampfireExport::TimeZone
|
5
|
+
|
6
|
+
@subdomain = ""
|
7
|
+
@api_token = ""
|
8
|
+
@base_url = ""
|
9
|
+
@timezone = nil
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :subdomain, :api_token, :base_url, :timezone
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(subdomain, api_token)
|
16
|
+
Account.subdomain = subdomain
|
17
|
+
Account.api_token = api_token
|
18
|
+
Account.base_url = "https://#{subdomain}.campfirenow.com"
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_timezone
|
22
|
+
settings = Nokogiri::XML get('/account.xml').body
|
23
|
+
selected_zone = settings.xpath('/account/time-zone')
|
24
|
+
Account.timezone = find_tzinfo(selected_zone.text)
|
25
|
+
end
|
26
|
+
|
27
|
+
def rooms
|
28
|
+
doc = Nokogiri::XML get('/rooms.xml').body
|
29
|
+
doc.xpath('/rooms/room').map {|room_xml| Room.new(room_xml) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Exception < StandardError
|
3
|
+
|
4
|
+
attr_reader :resource, :message, :code
|
5
|
+
|
6
|
+
def initialize(resource, message, code=nil)
|
7
|
+
@resource = resource
|
8
|
+
@message = message
|
9
|
+
@code = code
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"<#{resource}>: #{message}" + (code ? " (#{code})" : "")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Message
|
3
|
+
include CampfireExport::IO
|
4
|
+
attr_accessor :id, :room, :body, :type, :user, :date, :timestamp, :upload
|
5
|
+
|
6
|
+
def initialize(message, room, date)
|
7
|
+
@id = message.xpath('id').text
|
8
|
+
@room = room
|
9
|
+
@date = date
|
10
|
+
@body = message.xpath('body').text
|
11
|
+
@type = message.xpath('type').text
|
12
|
+
|
13
|
+
time = Time.parse message.xpath('created-at').text
|
14
|
+
localtime = CampfireExport::Account.timezone.utc_to_local(time)
|
15
|
+
@timestamp = localtime.strftime '%I:%M %p'
|
16
|
+
|
17
|
+
no_user = ['TimestampMessage', 'SystemMessage', 'AdvertisementMessage']
|
18
|
+
unless no_user.include?(@type)
|
19
|
+
@user = username(message.xpath('user-id').text)
|
20
|
+
end
|
21
|
+
|
22
|
+
@upload = CampfireExport::Upload.new(self) if is_upload?
|
23
|
+
end
|
24
|
+
|
25
|
+
def username(user_id)
|
26
|
+
@@usernames ||= {}
|
27
|
+
@@usernames[user_id] ||= begin
|
28
|
+
doc = Nokogiri::XML get("/users/#{user_id}.xml").body
|
29
|
+
rescue => e
|
30
|
+
"[unknown user]"
|
31
|
+
else
|
32
|
+
# Take the first name and last initial, if there is more than one name.
|
33
|
+
name_parts = doc.xpath('/user/name').text.split
|
34
|
+
if name_parts.length > 1
|
35
|
+
name_parts[-1] = "#{name_parts.last[0,1]}."
|
36
|
+
name_parts.join(" ")
|
37
|
+
else
|
38
|
+
name_parts[0]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_upload?
|
44
|
+
@type == 'UploadMessage'
|
45
|
+
end
|
46
|
+
|
47
|
+
def indent(string, count)
|
48
|
+
(' ' * count) + string.gsub(/(\n+)/) { $1 + (' ' * count) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
case type
|
53
|
+
when 'EnterMessage'
|
54
|
+
"[#{user} has entered the room]\n"
|
55
|
+
when 'KickMessage', 'LeaveMessage'
|
56
|
+
"[#{user} has left the room]\n"
|
57
|
+
when 'TextMessage'
|
58
|
+
"[#{user.rjust(12)}:] #{body}\n"
|
59
|
+
when 'UploadMessage'
|
60
|
+
"[#{user} uploaded: #{body}]\n"
|
61
|
+
when 'PasteMessage'
|
62
|
+
"[" + "#{user} pasted:]".rjust(14) + "\n#{indent(body, 16)}\n"
|
63
|
+
when 'TopicChangeMessage'
|
64
|
+
"[#{user} changed the topic to: #{body}]\n"
|
65
|
+
when 'ConferenceCreatedMessage'
|
66
|
+
"[#{user} created conference: #{body}]\n"
|
67
|
+
when 'AllowGuestsMessage'
|
68
|
+
"[#{user} opened the room to guests]\n"
|
69
|
+
when 'DisallowGuestsMessage'
|
70
|
+
"[#{user} closed the room to guests]\n"
|
71
|
+
when 'LockMessage'
|
72
|
+
"[#{user} locked the room]\n"
|
73
|
+
when 'UnlockMessage'
|
74
|
+
"[#{user} unlocked the room]\n"
|
75
|
+
when 'IdleMessage'
|
76
|
+
"[#{user} became idle]\n"
|
77
|
+
when 'UnidleMessage'
|
78
|
+
"[#{user} became active]\n"
|
79
|
+
when 'TweetMessage'
|
80
|
+
"[#{user} tweeted:] #{body}\n"
|
81
|
+
when 'SoundMessage'
|
82
|
+
"[#{user} played a sound:] #{body}\n"
|
83
|
+
when 'TimestampMessage'
|
84
|
+
"--- #{timestamp} ---\n"
|
85
|
+
when 'SystemMessage'
|
86
|
+
""
|
87
|
+
when 'AdvertisementMessage'
|
88
|
+
""
|
89
|
+
else
|
90
|
+
log(:error, "unknown message type: #{type} - '#{body}'")
|
91
|
+
""
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Room
|
3
|
+
include CampfireExport::IO
|
4
|
+
attr_accessor :id, :name, :created_at, :last_update
|
5
|
+
|
6
|
+
def initialize(room_xml)
|
7
|
+
@id = room_xml.xpath('id').text
|
8
|
+
@name = room_xml.xpath('name').text
|
9
|
+
created_utc = DateTime.parse(room_xml.xpath('created-at').text)
|
10
|
+
@created_at = Account.timezone.utc_to_local(created_utc)
|
11
|
+
end
|
12
|
+
|
13
|
+
def export(start_date=nil, end_date=nil)
|
14
|
+
# Figure out how to do the least amount of work while still conforming
|
15
|
+
# to the requester's boundary dates.
|
16
|
+
find_last_update
|
17
|
+
start_date.nil? ? date = created_at : date = [start_date, created_at].max
|
18
|
+
end_date.nil? ? end_date = last_update : end_date = [end_date, last_update].min
|
19
|
+
|
20
|
+
while date <= end_date
|
21
|
+
transcript = Transcript.new(self, date)
|
22
|
+
transcript.export
|
23
|
+
|
24
|
+
# Ensure that we stay well below the 37signals API limits.
|
25
|
+
sleep(1.0/10.0)
|
26
|
+
date = date.next
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def find_last_update
|
32
|
+
begin
|
33
|
+
last_message = Nokogiri::XML get("/room/#{id}/recent.xml?limit=1").body
|
34
|
+
update_utc = DateTime.parse(last_message.xpath('/messages/message[1]/created-at').text)
|
35
|
+
@last_update = Account.timezone.utc_to_local(update_utc)
|
36
|
+
rescue => e
|
37
|
+
log(:error,
|
38
|
+
"couldn't get last update in #{room} (defaulting to today)",
|
39
|
+
e)
|
40
|
+
@last_update = Time.now
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# Ruby on Rails is released under the MIT license.
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'tzinfo'
|
6
|
+
|
7
|
+
module CampfireExport
|
8
|
+
# This is a total cut & paste from:
|
9
|
+
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
|
10
|
+
# I'm copying it here to avoid bugs in the current active_support gem, to
|
11
|
+
# avoid having a dependency on active_support that might freak out Rails
|
12
|
+
# users, and to avoid fighting with RubyGems about threads and deprecation.
|
13
|
+
# See for background:
|
14
|
+
# https://github.com/rails/rails/pull/1215
|
15
|
+
# http://stackoverflow.com/questions/5176782/uninitialized-constant-activesupportdependenciesmutex-nameerror
|
16
|
+
module TimeZone
|
17
|
+
# Keys are Rails TimeZone names, values are TZInfo identifiers
|
18
|
+
MAPPING = {
|
19
|
+
"International Date Line West" => "Pacific/Midway",
|
20
|
+
"Midway Island" => "Pacific/Midway",
|
21
|
+
"Samoa" => "Pacific/Pago_Pago",
|
22
|
+
"Hawaii" => "Pacific/Honolulu",
|
23
|
+
"Alaska" => "America/Juneau",
|
24
|
+
"Pacific Time (US & Canada)" => "America/Los_Angeles",
|
25
|
+
"Tijuana" => "America/Tijuana",
|
26
|
+
"Mountain Time (US & Canada)" => "America/Denver",
|
27
|
+
"Arizona" => "America/Phoenix",
|
28
|
+
"Chihuahua" => "America/Chihuahua",
|
29
|
+
"Mazatlan" => "America/Mazatlan",
|
30
|
+
"Central Time (US & Canada)" => "America/Chicago",
|
31
|
+
"Saskatchewan" => "America/Regina",
|
32
|
+
"Guadalajara" => "America/Mexico_City",
|
33
|
+
"Mexico City" => "America/Mexico_City",
|
34
|
+
"Monterrey" => "America/Monterrey",
|
35
|
+
"Central America" => "America/Guatemala",
|
36
|
+
"Eastern Time (US & Canada)" => "America/New_York",
|
37
|
+
"Indiana (East)" => "America/Indiana/Indianapolis",
|
38
|
+
"Bogota" => "America/Bogota",
|
39
|
+
"Lima" => "America/Lima",
|
40
|
+
"Quito" => "America/Lima",
|
41
|
+
"Atlantic Time (Canada)" => "America/Halifax",
|
42
|
+
"Caracas" => "America/Caracas",
|
43
|
+
"La Paz" => "America/La_Paz",
|
44
|
+
"Santiago" => "America/Santiago",
|
45
|
+
"Newfoundland" => "America/St_Johns",
|
46
|
+
"Brasilia" => "America/Sao_Paulo",
|
47
|
+
"Buenos Aires" => "America/Argentina/Buenos_Aires",
|
48
|
+
"Georgetown" => "America/Guyana",
|
49
|
+
"Greenland" => "America/Godthab",
|
50
|
+
"Mid-Atlantic" => "Atlantic/South_Georgia",
|
51
|
+
"Azores" => "Atlantic/Azores",
|
52
|
+
"Cape Verde Is." => "Atlantic/Cape_Verde",
|
53
|
+
"Dublin" => "Europe/Dublin",
|
54
|
+
"Edinburgh" => "Europe/London",
|
55
|
+
"Lisbon" => "Europe/Lisbon",
|
56
|
+
"London" => "Europe/London",
|
57
|
+
"Casablanca" => "Africa/Casablanca",
|
58
|
+
"Monrovia" => "Africa/Monrovia",
|
59
|
+
"UTC" => "Etc/UTC",
|
60
|
+
"Belgrade" => "Europe/Belgrade",
|
61
|
+
"Bratislava" => "Europe/Bratislava",
|
62
|
+
"Budapest" => "Europe/Budapest",
|
63
|
+
"Ljubljana" => "Europe/Ljubljana",
|
64
|
+
"Prague" => "Europe/Prague",
|
65
|
+
"Sarajevo" => "Europe/Sarajevo",
|
66
|
+
"Skopje" => "Europe/Skopje",
|
67
|
+
"Warsaw" => "Europe/Warsaw",
|
68
|
+
"Zagreb" => "Europe/Zagreb",
|
69
|
+
"Brussels" => "Europe/Brussels",
|
70
|
+
"Copenhagen" => "Europe/Copenhagen",
|
71
|
+
"Madrid" => "Europe/Madrid",
|
72
|
+
"Paris" => "Europe/Paris",
|
73
|
+
"Amsterdam" => "Europe/Amsterdam",
|
74
|
+
"Berlin" => "Europe/Berlin",
|
75
|
+
"Bern" => "Europe/Berlin",
|
76
|
+
"Rome" => "Europe/Rome",
|
77
|
+
"Stockholm" => "Europe/Stockholm",
|
78
|
+
"Vienna" => "Europe/Vienna",
|
79
|
+
"West Central Africa" => "Africa/Algiers",
|
80
|
+
"Bucharest" => "Europe/Bucharest",
|
81
|
+
"Cairo" => "Africa/Cairo",
|
82
|
+
"Helsinki" => "Europe/Helsinki",
|
83
|
+
"Kyiv" => "Europe/Kiev",
|
84
|
+
"Riga" => "Europe/Riga",
|
85
|
+
"Sofia" => "Europe/Sofia",
|
86
|
+
"Tallinn" => "Europe/Tallinn",
|
87
|
+
"Vilnius" => "Europe/Vilnius",
|
88
|
+
"Athens" => "Europe/Athens",
|
89
|
+
"Istanbul" => "Europe/Istanbul",
|
90
|
+
"Minsk" => "Europe/Minsk",
|
91
|
+
"Jerusalem" => "Asia/Jerusalem",
|
92
|
+
"Harare" => "Africa/Harare",
|
93
|
+
"Pretoria" => "Africa/Johannesburg",
|
94
|
+
"Moscow" => "Europe/Moscow",
|
95
|
+
"St. Petersburg" => "Europe/Moscow",
|
96
|
+
"Volgograd" => "Europe/Moscow",
|
97
|
+
"Kuwait" => "Asia/Kuwait",
|
98
|
+
"Riyadh" => "Asia/Riyadh",
|
99
|
+
"Nairobi" => "Africa/Nairobi",
|
100
|
+
"Baghdad" => "Asia/Baghdad",
|
101
|
+
"Tehran" => "Asia/Tehran",
|
102
|
+
"Abu Dhabi" => "Asia/Muscat",
|
103
|
+
"Muscat" => "Asia/Muscat",
|
104
|
+
"Baku" => "Asia/Baku",
|
105
|
+
"Tbilisi" => "Asia/Tbilisi",
|
106
|
+
"Yerevan" => "Asia/Yerevan",
|
107
|
+
"Kabul" => "Asia/Kabul",
|
108
|
+
"Ekaterinburg" => "Asia/Yekaterinburg",
|
109
|
+
"Islamabad" => "Asia/Karachi",
|
110
|
+
"Karachi" => "Asia/Karachi",
|
111
|
+
"Tashkent" => "Asia/Tashkent",
|
112
|
+
"Chennai" => "Asia/Kolkata",
|
113
|
+
"Kolkata" => "Asia/Kolkata",
|
114
|
+
"Mumbai" => "Asia/Kolkata",
|
115
|
+
"New Delhi" => "Asia/Kolkata",
|
116
|
+
"Kathmandu" => "Asia/Kathmandu",
|
117
|
+
"Astana" => "Asia/Dhaka",
|
118
|
+
"Dhaka" => "Asia/Dhaka",
|
119
|
+
"Sri Jayawardenepura" => "Asia/Colombo",
|
120
|
+
"Almaty" => "Asia/Almaty",
|
121
|
+
"Novosibirsk" => "Asia/Novosibirsk",
|
122
|
+
"Rangoon" => "Asia/Rangoon",
|
123
|
+
"Bangkok" => "Asia/Bangkok",
|
124
|
+
"Hanoi" => "Asia/Bangkok",
|
125
|
+
"Jakarta" => "Asia/Jakarta",
|
126
|
+
"Krasnoyarsk" => "Asia/Krasnoyarsk",
|
127
|
+
"Beijing" => "Asia/Shanghai",
|
128
|
+
"Chongqing" => "Asia/Chongqing",
|
129
|
+
"Hong Kong" => "Asia/Hong_Kong",
|
130
|
+
"Urumqi" => "Asia/Urumqi",
|
131
|
+
"Kuala Lumpur" => "Asia/Kuala_Lumpur",
|
132
|
+
"Singapore" => "Asia/Singapore",
|
133
|
+
"Taipei" => "Asia/Taipei",
|
134
|
+
"Perth" => "Australia/Perth",
|
135
|
+
"Irkutsk" => "Asia/Irkutsk",
|
136
|
+
"Ulaan Bataar" => "Asia/Ulaanbaatar",
|
137
|
+
"Seoul" => "Asia/Seoul",
|
138
|
+
"Osaka" => "Asia/Tokyo",
|
139
|
+
"Sapporo" => "Asia/Tokyo",
|
140
|
+
"Tokyo" => "Asia/Tokyo",
|
141
|
+
"Yakutsk" => "Asia/Yakutsk",
|
142
|
+
"Darwin" => "Australia/Darwin",
|
143
|
+
"Adelaide" => "Australia/Adelaide",
|
144
|
+
"Canberra" => "Australia/Melbourne",
|
145
|
+
"Melbourne" => "Australia/Melbourne",
|
146
|
+
"Sydney" => "Australia/Sydney",
|
147
|
+
"Brisbane" => "Australia/Brisbane",
|
148
|
+
"Hobart" => "Australia/Hobart",
|
149
|
+
"Vladivostok" => "Asia/Vladivostok",
|
150
|
+
"Guam" => "Pacific/Guam",
|
151
|
+
"Port Moresby" => "Pacific/Port_Moresby",
|
152
|
+
"Magadan" => "Asia/Magadan",
|
153
|
+
"Solomon Is." => "Asia/Magadan",
|
154
|
+
"New Caledonia" => "Pacific/Noumea",
|
155
|
+
"Fiji" => "Pacific/Fiji",
|
156
|
+
"Kamchatka" => "Asia/Kamchatka",
|
157
|
+
"Marshall Is." => "Pacific/Majuro",
|
158
|
+
"Auckland" => "Pacific/Auckland",
|
159
|
+
"Wellington" => "Pacific/Auckland",
|
160
|
+
"Nuku'alofa" => "Pacific/Tongatapu"
|
161
|
+
}.each { |name, zone| name.freeze; zone.freeze }
|
162
|
+
MAPPING.freeze
|
163
|
+
|
164
|
+
def find_tzinfo(name)
|
165
|
+
TZInfo::Timezone.get(MAPPING[name] || name)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module CampfireExport
|
2
|
+
class Transcript
|
3
|
+
include CampfireExport::IO
|
4
|
+
attr_accessor :room, :date, :xml, :messages
|
5
|
+
|
6
|
+
def initialize(room, date)
|
7
|
+
@room = room
|
8
|
+
@date = date
|
9
|
+
end
|
10
|
+
|
11
|
+
def transcript_path
|
12
|
+
"/room/#{room.id}/transcript/#{date.year}/#{date.mon}/#{date.mday}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def export
|
16
|
+
begin
|
17
|
+
log(:info, "#{export_dir} ... ")
|
18
|
+
@xml = Nokogiri::XML get("#{transcript_path}.xml").body
|
19
|
+
rescue => e
|
20
|
+
log(:error, "transcript export for #{export_dir} failed", e)
|
21
|
+
else
|
22
|
+
@messages = xml.xpath('/messages/message').map do |message|
|
23
|
+
CampfireExport::Message.new(message, room, date)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Only export transcripts that contain at least one message.
|
27
|
+
if messages.length > 0
|
28
|
+
log(:info, "exporting transcripts\n")
|
29
|
+
begin
|
30
|
+
FileUtils.mkdir_p export_dir
|
31
|
+
rescue => e
|
32
|
+
log(:error, "Unable to create #{export_dir}", e)
|
33
|
+
else
|
34
|
+
export_xml
|
35
|
+
export_plaintext
|
36
|
+
export_html
|
37
|
+
export_uploads
|
38
|
+
end
|
39
|
+
else
|
40
|
+
log(:info, "no messages\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def export_xml
|
46
|
+
begin
|
47
|
+
export_file(xml, 'transcript.xml')
|
48
|
+
verify_export('transcript.xml', xml.to_s.bytesize)
|
49
|
+
rescue => e
|
50
|
+
log(:error, "XML transcript export for #{export_dir} failed", e)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def export_plaintext
|
55
|
+
begin
|
56
|
+
date_header = date.strftime('%A, %B %e, %Y').squeeze(" ")
|
57
|
+
plaintext = "#{CampfireExport::Account.subdomain.upcase} CAMPFIRE\n"
|
58
|
+
plaintext << "#{room.name}: #{date_header}\n\n"
|
59
|
+
messages.each {|message| plaintext << message.to_s }
|
60
|
+
export_file(plaintext, 'transcript.txt')
|
61
|
+
verify_export('transcript.txt', plaintext.bytesize)
|
62
|
+
rescue => e
|
63
|
+
log(:error, "Plaintext transcript export for #{export_dir} failed", e)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def export_html
|
68
|
+
begin
|
69
|
+
transcript_html = get(transcript_path).to_s
|
70
|
+
|
71
|
+
# Make the upload links in the transcript clickable from the exported
|
72
|
+
# directory layout.
|
73
|
+
transcript_html.gsub!(%Q{href="/room/#{room.id}/uploads/},
|
74
|
+
%Q{href="uploads/})
|
75
|
+
# Likewise, make the image thumbnails embeddable from the exported
|
76
|
+
# directory layout.
|
77
|
+
transcript_html.gsub!(%Q{src="/room/#{room.id}/thumb/},
|
78
|
+
%Q{src="thumbs/})
|
79
|
+
|
80
|
+
export_file(transcript_html, 'transcript.html')
|
81
|
+
verify_export('transcript.html', transcript_html.bytesize)
|
82
|
+
rescue => e
|
83
|
+
log(:error, "HTML transcript export for #{export_dir} failed", e)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def export_uploads
|
88
|
+
messages.each do |message|
|
89
|
+
if message.is_upload?
|
90
|
+
begin
|
91
|
+
message.upload.export
|
92
|
+
rescue => e
|
93
|
+
path = "#{message.upload.export_dir}/#{message.upload.filename}"
|
94
|
+
log(:error, "Upload export for #{path} failed", e)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|