forked from mdarby/scribd_fu
/
scribd_fu.rb
278 lines (224 loc) · 8.52 KB
/
scribd_fu.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
module ScribdFu
ConfigPath = "#{RAILS_ROOT}/config/scribd_fu.yml".freeze
# A list of content types supported by iPaper.
ContentTypes = [
'application/pdf',
'application/msword',
'application/mspowerpoint',
'application/vnd.ms-powerpoint',
'application/excel',
'application/vnd.ms-excel',
'application/postscript',
'text/plain',
'text/rtf',
'application/rtf',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.sun.xml.writer',
'application/vnd.sun.xml.impress',
'application/vnd.sun.xml.calc',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'application/vnd.openxmlformats-officedocument.presentationml.template',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template'
]
# RegExp that matches AWS S3 URLs
S3 = /^https?:\/\/s3.amazonaws.com/
CLOUD_FRONT = /^http:\/\/[A-Za-z0-9]*.cloudfront.net/
# Available parameters for the JS API
# http://www.scribd.com/publisher/api/api?method_name=Javascript+API
Available_JS_Params = [ :height, :width, :page, :my_user_id, :search_query,
:jsapi_version, :disable_related_docs, :mode, :auto_size ]
class ScribdFuError < StandardError #:nodoc:
end
class ScribdFuUploadError < ScribdFuError #:nodoc:
end
class << self
def included(base) #:nodoc:
base.extend ClassMethods
end
# Login, store, and return a handle to the Scribd user account
def scribd_user
begin
# Ensure we can login to Scribd, and get a handle on the account
Scribd::API.instance.key = config[:key]
Scribd::API.instance.secret = config[:secret]
@scribd_user = Scribd::User.login(config[:user], config[:password])
rescue
raise ScribdFuError, "Your Scribd credentials are incorrect"
end
end
# Upload a file to Scribd
def upload(obj, file_path)
begin
res = scribd_user.upload(:file => escape(file_path), :access => access_level)
obj.update_attributes({:ipaper_id => res.doc_id, :ipaper_access_key => res.access_key})
rescue
raise ScribdFuUploadError, "Sorry, but #{obj.class} ##{obj.id} could not be uploaded to Scribd: #{res.inspect}"
end
end
# Delete an iPaper document
def destroy(document)
document.destroy
end
# Read, store, and return the ScribdFu config file's contents
def config
raise ScribdFuError, "#{ConfigPath} does not exist" unless File.file?(ConfigPath)
# Load the config file and strip any whitespace from the values
@config ||= YAML.load_file(ConfigPath).each_pair{|k,v| {k=>v.to_s.strip}}.symbolize_keys!
end
# Get the preferred access level for iPaper documents
def access_level
config[:access] || 'private'
end
# Load, store, and return the associated iPaper document
def load_ipaper_document(id)
# Yes, catch-all rescues are bad, but the end rescue
# should return nil, so laziness FTW.
scribd_user.find_document(id) rescue nil
end
# Replace spaces with '%20' (needed by Paperclip models).
def escape(str)
str.gsub(' ', '%20')
end
# See if a URL is S3 or CloudFront based
def amazon_based?(url)
url =~ S3 || url =~ CLOUD_FRONT
end
# Strip off any trailing "?1234567890" cache strings
# They cause headaches on Scribd's end.
def strip_cache_string(url)
pos = url.rindex('?')
(pos) ? url[0, pos] : url
end
end
module ClassMethods
# Load and inject ScribdFu goodies
def has_ipaper_and_uses(str)
check_environment
load_base_plugin(str)
include InstanceMethods
after_save :upload_to_scribd # This *MUST* be an after_save
before_destroy :destroy_ipaper_document
end
def has_ipaper(*args)
options = args.extract_options!
check_environment
load_base_plugin(options[:uses])
include InstanceMethods
after_save :upload_to_scribd unless options[:disable_callbacks] == true
before_destroy :destroy_ipaper_document unless options[:disable_callbacks] == true
end
private
# Configure ScribdFu for this particular environment
def check_environment
load_rscribd
check_config
check_fields
end
def check_config
ScribdFu::config
end
# Load the rscribd gem
def load_rscribd
begin
require 'rscribd'
rescue LoadError
raise ScribdFuError, 'Please install the rscribd gem'
end
end
# Load Attachment_Fu specific methods and files
def load_attachment_fu
require 'scribd_fu/attachment_fu'
include ScribdFu::AttachmentFu::InstanceMethods
end
# Load Paperclip specific methods and files
def load_paperclip
require 'scribd_fu/paperclip'
include ScribdFu::Paperclip::InstanceMethods
end
# Ensure ScribdFu-centric attributes exist
def check_fields
fields = %w{ipaper_id ipaper_access_key}.inject([]){|stack, f| stack << "#{name}##{f}" unless column_names.include?(f); stack}
raise ScribdFuError, "These fields are missing: #{fields.to_sentence}" if fields.size > 0
end
# Load either AttachmentFu or Paperclip-specific methods
def load_base_plugin(str)
if str == 'AttachmentFu'
load_attachment_fu
elsif str == 'Paperclip'
load_paperclip
else
raise ScribdFuError, "Sorry, only Attachment_fu and Paperclip are supported."
end
end
end
module InstanceMethods
def self.included(base)
base.extend ClassMethods
end
# Upload the associated file to Scribd for iPaper conversion
# This is called +after_save+ and cannot be called earlier,
# so don't get any ideas.
def upload_to_scribd
ScribdFu::upload(self, file_path) if scribdable?
end
# Checks whether the associated file is convertable to iPaper
def scribdable?
ContentTypes.include?(get_content_type) && ipaper_id.blank?
end
# Responds true if the conversion is converting
def conversion_processing?
!(conversion_complete? || conversion_successful? || conversion_error?)
end
# Responds true if the conversion is complete -- note that this gives no
# indication as to whether the conversion had an error or was succesful,
# just that the conversion completed.
def conversion_complete?
ipaper_document && ipaper_document.conversion_status != 'PROCESSING'
end
# Responds true if the document has been converted.
def conversion_successful?
ipaper_document && %w[DISPLAYABLE DONE].include?(ipaper_document.conversion_status)
end
# Responds true if there was a conversion error while converting to iPaper.
def conversion_error?
ipaper_document && ipaper_document.conversion_status == 'ERROR'
end
# Responds the Scribd::Document associated with this model, or nil if it does not exist.
def ipaper_document
@document ||= ScribdFu::load_ipaper_document(ipaper_id)
end
# Destroys the scribd document for this record. This is called +before_destroy+
def destroy_ipaper_document
ScribdFu::destroy(ipaper_document) if ipaper_document
end
# Display the iPaper document in a view
def display_ipaper(options = {})
<<-END
<script type="text/javascript" src="http://www.scribd.com/javascripts/view.js"></script>
<div id="embedded_flash">#{options.delete(:alt)}</div>
<script type="text/javascript">
var scribd_doc = scribd.Document.getDoc(#{ipaper_id}, '#{ipaper_access_key}');
#{js_params(options)}
scribd_doc.write("embedded_flash");
</script>
END
end
private
# Check and collect any Javascript params that might have been passed in
def js_params(options)
opt = []
options.each_pair do |k, v|
opt << "scribd_doc.addParam('#{k}', '#{v}');" if Available_JS_Params.include?(k)
end
opt.compact.join("\n")
end
end
end
# Let's do this.
ActiveRecord::Base.send(:include, ScribdFu) if Object.const_defined?("ActiveRecord")