Commit 9e227f4

mo khan <mo@mokhan.ca>
2015-06-14 20:08:48
use google drive js api to download backup file.
1 parent a369294
app/assets/javascripts/models/google.js.coffee → app/assets/javascripts/models/google_drive.js.coffee
@@ -18,7 +18,6 @@ class Stronglifters.GoogleDrive
 
   handleAuthResult: (authResult) =>
     if (authResult)
-      #console.dir(authResult)
       gapi.load('drive-share', @initializeDrive)
     else
       @checkAuth()
@@ -31,19 +30,14 @@ class Stronglifters.GoogleDrive
       'q': "title contains '.stronglifts' and title contains 'backup'"
     })
     request.execute (response) =>
-      console.dir(response)
       if !response.error
         item = response.items[0]
-        console.log('Title: ' + item.title)
-        console.log('Description: ' + item.description)
-        console.log('MIME type: ' + item.mimeType)
-        fileId = item.id
-        downloadUrl = item.downloadUrl
-        $.post( "/training_sessions/drive_upload", item)
-          .done (data) ->
-            console.dir(data)
+        $.post("/training_sessions/drive_upload", {
+          accessToken: gapi.auth.getToken().access_token,
+          data: item
+        }).done (data) ->
+          window.location.reload()
       else if (item.error.code == 401)
-        #// Access token might have expired.
         @checkAuth()
       else
         console.log('An error occured: ' + response.error.message)
app/controllers/training_sessions_controller.rb
@@ -18,7 +18,7 @@ class TrainingSessionsController < ApplicationController
   end
 
   def drive_upload
-    DownloadFromDriveJob.perform_later(params)
+    DownloadFromDriveJob.perform_later(current_user, params)
     redirect_to dashboard_path, notice: t(".success")
   end
 
app/jobs/download_from_drive_job.rb
@@ -1,29 +1,42 @@
 class DownloadFromDriveJob < ActiveJob::Base
   queue_as :default
-  require 'google/api_client'
 
-  CLIENT_ID = "241601222378-kscpfqhpmc6059704mfcq8ckcp799dvn.apps.googleusercontent.com"
-  CLIENT_SECRET = ENV['GOOGLE_CLIENT_SECRET']
-  REDIRECT_URI = ENV['GOOGLE_REDIRECT_URI']
-  SCOPES = [
-    'https://www.googleapis.com/auth/drive',
-    'https://www.googleapis.com/auth/drive.install',
-    'https://www.googleapis.com/auth/drive.file',
-    'https://www.googleapis.com/auth/drive.readonly',
-    'https://www.googleapis.com/auth/drive.apps.readonly',
-  ]
+  def perform(user, params)
+    Dir.mktmpdir do |dir|
+      download_path = File.join(dir, params[:data][:title])
+      execute(create_command(
+        params[:data][:downloadUrl].strip,
+        download_path,
+        params[:accessToken]
+      ))
+      UploadStrongliftsBackupJob.perform_later(
+        user,
+        storage.store(File.new(download_path)),
+        Program.stronglifts
+      )
+    end
+  end
 
-  def perform(params)
-    puts params.inspect
+  private
 
-    drive = GoogleDrive.new
-    drive.build_client(drive.get_credentials())
+  def storage
+    @storage ||= TemporaryStorage.new
+  end
 
-    #Dir.mktmpdir do |dir|
-      #download_path = File.join(dir, params[:title])
-      #`wget -O #{download_path} #{params[:downloadUrl]}`
-    #end
+  def create_command(download_url, download_path, access_token)
+    command = <<-COMMAND
+curl '#{download_url}' \
+-o '#{download_path}' \
+-H 'Authorization: Bearer #{access_token}' \
+-H 'Referer: http://stronglifters.dev/dashboard' \
+-H 'Origin: http://stronglifters.dev' \
+-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36' \
+--compressed
+COMMAND
+    command
   end
-end
 
- 
+  def execute(command)
+    `#{command}`
+  end
+end
app/models/google_drive.rb
@@ -1,183 +0,0 @@
-##
-# Error raised when an error occurred while retrieving credentials.
-class GetCredentialsError < StandardError
-  ##
-  # Initialize a NoRefreshTokenError instance.
-  #
-  # @param [String] authorize_url
-  #   Authorization URL to redirect the user to in order to in order to request
-  #   offline access.
-  def initialize(authorization_url)
-    @authorization_url = authorization_url
-  end
-
-  def authorization_url=(authorization_url)
-    @authorization_url = authorization_url
-  end
-
-  def authorization_url
-    return @authorization_url
-  end
-end
-
-##
-# Error raised when a code exchange has failed.
-class CodeExchangeError < GetCredentialsError
-end
-
-##
-# Error raised when no refresh token has been found.
-class NoRefreshTokenError < GetCredentialsError
-end
-
-##
-# Error raised when no user ID could be retrieved.
-class NoUserIdError < StandardError
-end
-
-class GoogleDrive
-  ##
-  # Retrieved stored credentials for the provided user ID.
-  #
-  # @param [String] user_id
-  #   User's ID.
-  # @return [Signet::OAuth2::Client]
-  #  Stored OAuth 2.0 credentials if found, nil otherwise.
-  def get_stored_credentials(user_id)
-    raise NotImplementedError, 'get_stored_credentials is not implemented.'
-  end
-
-  ##
-  # Store OAuth 2.0 credentials in the application's database.
-  #
-  # @param [String] user_id
-  #   User's ID.
-  # @param [Signet::OAuth2::Client] credentials
-  #   OAuth 2.0 credentials to store.
-  def store_credentials(user_id, credentials)
-    raise NotImplementedError, 'store_credentials is not implemented.'
-  end
-
-  ##
-  # Exchange an authorization code for OAuth 2.0 credentials.
-  #
-  # @param [String] auth_code
-  #   Authorization code to exchange for OAuth 2.0 credentials.
-  # @return [Signet::OAuth2::Client]
-  #  OAuth 2.0 credentials.
-  def exchange_code(authorization_code)
-    client = Google::APIClient.new
-    client.authorization.client_id = CLIENT_ID
-    client.authorization.client_secret = CLIENT_SECRET
-    client.authorization.code = authorization_code
-    client.authorization.redirect_uri = REDIRECT_URI
-
-    begin
-      client.authorization.fetch_access_token!
-      return client.authorization
-    rescue Signet::AuthorizationError
-      raise CodeExchangeError.new(nil)
-    end
-  end
-
-  ##
-  # Send a request to the UserInfo API to retrieve the user's information.
-  #
-  # @param [Signet::OAuth2::Client] credentials
-  #   OAuth 2.0 credentials to authorize the request.
-  # @return [Google::APIClient::Schema::Oauth2::V2::Userinfo]
-  #   User's information.
-  def get_user_info(credentials)
-    client = Google::APIClient.new
-    client.authorization = credentials
-    oauth2 = client.discovered_api('oauth2', 'v2')
-    result = client.execute!(:api_method => oauth2.userinfo.get)
-    user_info = nil
-    if result.status == 200
-      user_info = result.data
-    else
-      puts "An error occurred: #{result.data['error']['message']}"
-    end
-    if user_info != nil && user_info.id != nil
-      return user_info
-    end
-    raise NoUserIdError, 'Unable to retrieve the e-mail address.'
-  end
-
-  ##
-  # Retrieve authorization URL.
-  #
-  # @param [String] email_address
-  #   User's e-mail address.
-  # @param [String] state
-  #   State for the authorization URL.
-  # @return [String]
-  #  Authorization URL to redirect the user to.
-  def get_authorization_url(email_address, state)
-    client = Google::APIClient.new
-    client.authorization.client_id = CLIENT_ID
-    client.authorization.redirect_uri = REDIRECT_URI
-    client.authorization.scope = SCOPES
-
-    return client.authorization.authorization_uri(
-      :approval_prompt => :force,
-      :access_type => :offline,
-      :user_id => email_address,
-      :state => state
-    ).to_s
-  end
-
-  ##
-  # Retrieve credentials using the provided authorization code.
-  #
-  #  This function exchanges the authorization code for an access token and queries
-  #  the UserInfo API to retrieve the user's e-mail address.
-  #  If a refresh token has been retrieved along with an access token, it is stored
-  #  in the application database using the user's e-mail address as key.
-  #  If no refresh token has been retrieved, the function checks in the application
-  #  database for one and returns it if found or raises a NoRefreshTokenError
-  #  with an authorization URL to redirect the user to.
-  #
-  # @param [String] auth_code
-  #   Authorization code to use to retrieve an access token.
-  # @param [String] state
-  #   State to set to the authorization URL in case of error.
-  # @return [Signet::OAuth2::Client]
-  #  OAuth 2.0 credentials containing an access and refresh token.
-  def get_credentials(authorization_code, state)
-    email_address = ''
-    begin
-      credentials = exchange_code(authorization_code)
-      user_info = get_user_info(credentials)
-      email_address = user_info.email
-      user_id = user_info.id
-      if credentials.refresh_token != nil
-        store_credentials(user_id, credentials)
-        return credentials
-      else
-        credentials = get_stored_credentials(user_id)
-        if credentials != nil && credentials.refresh_token != nil
-          return credentials
-        end
-      end
-    rescue CodeExchangeError => error
-      print 'An error occurred during code exchange.'
-      # Drive apps should try to retrieve the user and credentials for the current
-      # session.
-      # If none is available, redirect the user to the authorization URL.
-      error.authorization_url = get_authorization_url(email_address, state)
-      raise error
-    rescue NoUserIdError
-      print 'No user ID could be retrieved.'
-    end
-    authorization_url = get_authorization_url(email_address, state)
-    raise NoRefreshTokenError.new(authorization_url)
-  end
-
-  def build_client(credentials)
-    client = Google::APIClient.new
-    client.authorization = credentials
-    client = client.discovered_api('drive', 'v2')
-    client
-  end
-end
Gemfile
@@ -38,7 +38,6 @@ gem 'chartkick'
 gem 'groupdate'
 gem 'dalli'
 gem 'sequel'
-gem 'google-api-client'
 
 group :development, :test do
   # Call 'byebug' anywhere in the code to stop execution and get a debugger console
Gemfile.lock
@@ -36,12 +36,7 @@ GEM
       minitest (~> 5.1)
       thread_safe (~> 0.3, >= 0.3.4)
       tzinfo (~> 1.1)
-    addressable (2.3.8)
     arel (6.0.0)
-    autoparse (0.3.3)
-      addressable (>= 2.3.1)
-      extlib (>= 0.9.15)
-      multi_json (>= 1.0.0)
     axiom-types (0.1.1)
       descendants_tracker (~> 0.0.4)
       ice_nine (~> 0.11.0)
@@ -118,14 +113,11 @@ GEM
     equalizer (0.0.11)
     erubis (2.7.0)
     execjs (2.5.2)
-    extlib (0.9.16)
     factory_girl (4.5.0)
       activesupport (>= 3.0.0)
     factory_girl_rails (4.5.0)
       factory_girl (~> 4.5.0)
       railties (>= 3.0.0)
-    faraday (0.9.1)
-      multipart-post (>= 1.2, < 3)
     fast_stack (0.1.0)
       rake
       rake-compiler
@@ -139,24 +131,6 @@ GEM
       sass (>= 3.3.0, < 3.5)
     globalid (0.3.5)
       activesupport (>= 4.1.0)
-    google-api-client (0.8.6)
-      activesupport (>= 3.2)
-      addressable (~> 2.3)
-      autoparse (~> 0.3)
-      extlib (~> 0.9)
-      faraday (~> 0.9)
-      googleauth (~> 0.3)
-      launchy (~> 2.4)
-      multi_json (~> 1.10)
-      retriable (~> 1.4)
-      signet (~> 0.6)
-    googleauth (0.4.1)
-      faraday (~> 0.9)
-      jwt (~> 1.4)
-      logging (~> 2.0)
-      memoist (~> 0.12)
-      multi_json (= 1.11)
-      signet (~> 0.6)
     groupdate (2.4.0)
       activesupport (>= 3)
     highline (1.7.2)
@@ -180,19 +154,11 @@ GEM
       railties (>= 4.2.0)
       thor (>= 0.14, < 2.0)
     json (1.8.3)
-    jwt (1.5.0)
-    launchy (2.4.3)
-      addressable (~> 2.3)
     libv8 (3.16.14.7)
-    little-plugger (1.1.3)
-    logging (2.0.0)
-      little-plugger (~> 1.1)
-      multi_json (~> 1.10)
     loofah (2.0.2)
       nokogiri (>= 1.5.9)
     mail (2.6.3)
       mime-types (>= 1.16, < 3)
-    memoist (0.12.0)
     meta_request (0.3.4)
       callsite (~> 0.0, >= 0.0.11)
       rack-contrib (~> 1.1)
@@ -201,7 +167,6 @@ GEM
     mini_portile (0.6.2)
     minitest (5.7.0)
     multi_json (1.11.0)
-    multipart-post (2.0.0)
     net-scp (1.2.1)
       net-ssh (>= 2.6.5)
     net-ssh (2.9.2)
@@ -267,7 +232,6 @@ GEM
       http-cookie (>= 1.0.2, < 2.0)
       mime-types (>= 1.16, < 3.0)
       netrc (~> 0.7)
-    retriable (1.4.1)
     rspec-core (3.2.3)
       rspec-support (~> 3.2.0)
     rspec-expectations (3.2.1)
@@ -300,12 +264,6 @@ GEM
       json (~> 1.7, >= 1.7.7)
       rdoc (~> 4.0)
     sequel (4.23.0)
-    signet (0.6.1)
-      addressable (~> 2.3)
-      extlib (~> 0.9)
-      faraday (~> 0.9)
-      jwt (~> 1.5)
-      multi_json (~> 1.10)
     simplecov (0.10.0)
       docile (~> 1.1.0)
       json (~> 1.8)
@@ -393,7 +351,6 @@ DEPENDENCIES
   flamegraph
   foreman
   foundation-rails
-  google-api-client
   groupdate
   i18n-tasks
   jbuilder (~> 2.0)