class BackupGoogleDocsController < ApplicationController
verify :method => :post, :only => :backup, :redirect_to => '/404.html'
caches_action :source
helper_method :authsub_url
before_filter :setup_client
def index
upgrade_session if params[:token]
end
def backup
backup_docs
end
def source
render :inline => "<html><head><title>Google Docs Backup : Source</title><%= stylesheet_link_tag :harsh %></head>" +
"<body><% harsh File.read('#{__FILE__}') %></body></html>"
end
private
DocsPaths = {
'document' => 'https://docs.google.com/feeds/download/documents/Export?exportFormat=%s&docID=%s',
'presentation' => 'https://docs.google.com/feeds/download/presentations/Export?exportFormat=%s&docID=%s',
'spreadsheet' => 'https://spreadsheets.google.com/feeds/download/spreadsheets/Export?exportFormat=%s&key=%s&gid=0',
'pdf' => 'content tag src attribtue',
}
ValidExtensions = {
'document' => ["odt", "doc", "pdf", "html", "rtf", "txt", "png", "zip"],
'presentation' => ["ppt", "pdf", "swf", "png"],
'spreadsheet' => ["ods", "xls", "pdf", "html"],
'pdf' => ["pdf"],
}
class TokenMissing < RuntimeError; end
def setup_client
@scope = ['https://docs.google.com/feeds', 'https://spreadsheets.google.com/feeds', 'https://docs.googleusercontent.com'].join(' ')
@client = GData::Client::DocList.new(:authsub_scope => @scope, :source => 'gdocs-backup-v2', :version => '3.0')
end
def authsub_url(secure=false)
@client.authsub_url(root_url, secure, true)
end
def upgrade_session
@client.authsub_token = params[:token]
session[:token] = @client.auth_handler.upgrade
redirect_to root_path
rescue GData::Client::AuthorizationError
auth_error
end
def backup_docs
raise TokenMissing unless session[:token]
params[:ext] = {} unless params[:ext].is_a?(Hash)
@client.authsub_token = session[:token]
file = Tempfile.new("gdocs-backup")
zip = Zip::ZipOutputStream.new(file.path)
list = @client.get('https://docs.google.com/feeds/default/private/full').to_xml
names = []
ext = {}
ValidExtensions.each do |label, ext_list|
ext[label] = ext_list.include?(params[:ext][label]) ? params[:ext][label] : ext_list.first
end
REXML::XPath.each(list, '//feed/entry') do |entry|
resource_id = entry.elements['gd:resourceId'].text
doc_title = entry.elements['title'].text
label, doc_id = resource_id.split(/:/,2)
next unless DocsPaths[label]
doc_path = DocsPaths[label] % [ext[label], doc_id]
doc_path = entry.elements['content'].attributes['src'] if label == 'pdf'
clean_name = [doc_title.clean, ext[label]].join('.')
doc_name = clean_name
doc_idx = 0
doc_name = clean_name + "(#{doc_idx+=1})" while names.include?(doc_name)
names << doc_name
zip.put_next_entry(doc_name)
zip << @client.get(doc_path).body
end
zip.close
log_size file.size
send_file file.path, :type => 'application/zip', :disposition => 'attachment', :filename => "gdocs-backup.zip"
file.close
rescue GData::Client::AuthorizationError, TokenMissing
auth_error
end
def auth_error
session[:token] = nil
flash[:error] = "Google Authorization Error - Please Try Again"
redirect_to root_path
end
def log_size(file_size)
logger.info("==== %s ==== package size: %d (%.2fM) ====" % [Time.now.to_s, file_size, file_size.to_f / 1024 / 1024])
end
end