module Paperclip::Storage::GoogleDrive

return id of Public folder, must be in options

Public Class Methods

check_gem_is_installed() click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 40
def check_gem_is_installed
  begin
    require 'google-api-client'
  rescue LoadError => e
    e.message << '(You may need to install the google-api-client gem)'
    raise e
  end unless defined?(Google)
end
extended(base) click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 29
def extended(base)
  check_gem_is_installed
  base.instance_eval do
    @google_drive_client_secret_path = @options[:google_drive_client_secret_path]
    @google_drive_options = @options[:google_drive_options] || { application_name: 'test-app' }
    raise(ArgumentError, 'You must provide a valid google_drive_client_secret_path option') unless @google_drive_client_secret_path
    raise(ArgumentError, 'You must set the public_folder_id option') unless @google_drive_options[:public_folder_id]
    google_api_client # Force validations of credentials
  end
end

Public Instance Methods

custom_thumbnail_image_for(drive_thumbnail_link, custom_width) click to toggle source

Retrieves the specific image with a custom size. It is resized by GDrive API if you pass the :custom_thumb as style option. In other cases, it removes the last parameter `=s220` which is inchaged to do the scaling process. @param drive_thumbnail_link [ String ] with the form: value>=s220 @param custom_width [ Integer ] ex. 512 @return [ String ]

# File lib/paperclip/storage/google_drive.rb, line 174
def custom_thumbnail_image_for(drive_thumbnail_link, custom_width)
  file_url, current_width = drive_thumbnail_link.split(/=s/)
  "#{ file_url }=s#{ custom_width }"
end
default_image() click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 268
def default_image
  if @google_drive_options[:default_url] #if default image is set
    title = @google_drive_options[:default_url]
    searched_id = search_for_title(title) # id
    if searched_id.nil?
      raise 'Default image not found, please double check its name'
    else
      metadata = metadata_by_id(searched_id)
      effective_url_from(metadata.web_content_link)
    end
  else
    'No picture' # ---- ?
  end
end
effective_url_from(drive_web_content_link) click to toggle source

TOO SLOW and PERMISSIONS ISSUES Seems that the retrieved file url is only visible for the user which is owner and is currently log in GDrive.

Gets the effective url from the web content link These are a series of steps to hack the way that GDrive API handle its urls. It consists in catch a Google::Apis::RedirectError error and take the correct url where is located the file. @param driver_web_content_link [ String ] @return [ String ]

# File lib/paperclip/storage/google_drive.rb, line 189
def effective_url_from(drive_web_content_link)
  redirect_url = drive_web_content_link.split(/&export=/)[0]
  google_drive.http(:get, redirect_url) do |result, err|
    err.header[:location].split('&continue=')[1]
  end
end
exists?(style = default_style) click to toggle source

Checks if the image already exits @param style [ String ] @return [ Boolean ]

# File lib/paperclip/storage/google_drive.rb, line 243
def exists?(style = default_style)
  return false if not present?
  result_id = search_for_title(path(style))
  if result_id.nil?
    false
  else
    data = metadata_by_id(result_id)
    !data.trashed # if trashed -> not exists
  end
end
find_public_folder() click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 283
def find_public_folder
  if @google_drive_options[:public_folder_id].is_a? Proc
    instance.instance_exec(&@google_drive_options[:public_folder_id])
  else
    @google_drive_options[:public_folder_id]
  end
end
flush_deletes() click to toggle source

Process to destroy a file

# File lib/paperclip/storage/google_drive.rb, line 76
def flush_deletes
  @queued_for_delete.each do |path|
    Paperclip.log("Delete: #{ path }")
    file_id = search_for_title(path)
    google_api_client.delete_file(file_id) unless file_id.nil?
  end
  @queued_for_delete = []
end
flush_writes() click to toggle source

Main process to upload a file

# File lib/paperclip/storage/google_drive.rb, line 51
def flush_writes
  @queued_for_write.each do |style, file|
    raise FileExists, "file \"#{path(style)}\" already exists in your Google Drive" if exists?(path(style))

    name, mime_type = filename_from(style), "#{ file.content_type }"

    file_metadata = {
      name: name,
      description: 'paperclip file on google drive',
      mimeType: mime_type,
      parents: [find_public_folder]
    }

    google_api_client.create_file(
      file_metadata,
      fields: 'id',
      upload_source: file.binmode,
      content_type: file.content_type,
      )
  end
  after_flush_writes
  @queued_for_write = {}
end
google_api_client() click to toggle source

@return [ Google::Apis::DriveV3::DriveService ]

# File lib/paperclip/storage/google_drive.rb, line 86
def google_api_client
  @google_api_client ||= begin
    # Initialize the client & Google+ API
    ::Paperclip::GoogleDrive::Session.from_config(
      @google_drive_client_secret_path,
      application_name: @google_drive_options[:application_name]
    )
  end
end
Also aliased as: google_drive
google_drive()
Alias for: google_api_client
is_valid_for_custom_thumb?() click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 125
def is_valid_for_custom_thumb?
  content_type =~ /image/ || content_type =~ /pdf/
end
metadata_by_id(file_id) click to toggle source

Gets a file from GDrive @parent file_id [ String ] @return [ Google::Apis::DriveV3::File ]

# File lib/paperclip/storage/google_drive.rb, line 217
def metadata_by_id(file_id)
  if file_id.is_a? String
    client = google_api_client
    metadata = client.get_file(
              file_id,
              fields: 'id, name, thumbnailLink, webContentLink, webViewLink, trashed'
              )
    validate_metadata(metadata)
    metadata
  end
end
metadata_or_default_img_from(title) { |metadata| ... } click to toggle source

Gets the file metadata if it exists in other case returns the defaul image @param title [ String ] @param block [ Proc ]

# File lib/paperclip/storage/google_drive.rb, line 258
def metadata_or_default_img_from(title, &block)
  searched_id = search_for_title(title) #return id if any or style
  if searched_id.nil? # it finds some file
    default_image
  else
    metadata = metadata_by_id(searched_id)
    yield metadata
  end
end
path(style)
Alias for: filename_from
public_url_custom_thumbnail_from(title, custom_width) click to toggle source

Gets the public url for a passed filename @param title [ String ] @param custom_width [ Integer ] @return [ String ] with url

# File lib/paperclip/storage/google_drive.rb, line 162
def public_url_custom_thumbnail_from(title, custom_width)
  metadata_or_default_img_from(title) do |metadata|
    custom_thumbnail_image_for(metadata.thumbnail_link, custom_width)
  end
end
public_url_for(title) click to toggle source

Gets the public url for a passed filename @param title [ String ] @return [ String ] with url

# File lib/paperclip/storage/google_drive.rb, line 147
def public_url_for(title)
  metadata_or_default_img_from(title) do |metadata|
    # effective_url_from(metadata.web_content_link)
    if content_type =~ /image/
      custom_thumbnail_image_for(metadata.thumbnail_link, 1000)
    else
      metadata.web_view_link
    end
  end
end
search_for_title(name) click to toggle source

Takes the file title/name and search it in a given folder If it finds a file, return id of a file or nil @param name [ String ] @return [ String ] or NilClass

# File lib/paperclip/storage/google_drive.rb, line 200
def search_for_title(name)
  raise 'You are trying to search a file with NO name' if name.nil? || name.empty?
  client = google_api_client
  result = client.list_files(page_size: 1,
          q: "name contains '#{ name }' and '#{ find_public_folder }' in parents",
          fields: 'files(id, name)'
          )
  if result.files.length > 0
    result.files[0].id
  else
    nil
  end
end
url(*args) click to toggle source

Retrives the origina file or this also could be used to scale images as Google does. e.i. `<url>=s220`, where 220 is the width in pixeles OR as Paperclip does. @params args [ Array ] @return [ String ]

ex.
   1. If you want the medium version of your image (Paperclip way)
     some_model.avatar.url(:medium)
   2. If you want a custom thumbanil of your image/pdf (Google way)
     some_model.avatar.url(:custom_thumb, width: 500)
# File lib/paperclip/storage/google_drive.rb, line 108
def url(*args)
  if present?
    style = args.first.is_a?(Symbol) ? args.first : default_style
    options = args.last.is_a?(Hash) ? args.last : {}
    if style == :custom_thumb && is_valid_for_custom_thumb?
      custom_width = options[:width] || 220
      file_name = filename_from(default_style)
      public_url_custom_thumbnail_from(file_name, custom_width)
    else
      file_name = filename_from(style)
      public_url_for(file_name)
    end
  else
    default_image
  end
end
validate_metadata(metadata) click to toggle source

Raises an error in case that the Google Drive API does not response with the minimum required information. @params [ Google::Apis::DriveV3::File ]

# File lib/paperclip/storage/google_drive.rb, line 232
def validate_metadata(metadata)
  raise 'the file id was not retrieved' if metadata.id.nil?
  raise 'the file name was not retrieved' if metadata.name.nil?
  raise 'the file web_content_link was not retrieved' if metadata.web_content_link.nil?
  raise 'the file web_view_link was not retrieved' if metadata.web_view_link.nil?
  raise 'the file trashed was not retrieved' if metadata.trashed.nil?
end

Private Instance Methods

file_title() click to toggle source
# File lib/paperclip/storage/google_drive.rb, line 300
def file_title
  return @google_drive_options[:path] if @google_drive_options[:path] #path: proc
  eval %(proc { |style| "\#{id}_\#{#{name}.original_filename}"})
end
original_extension() click to toggle source

@return [String] with the extension of file

# File lib/paperclip/storage/google_drive.rb, line 306
def original_extension
  File.extname(original_filename)
end