# frozen_string_literal: true require 'ngdrive/version' require 'fileutils' require 'google/apis/drive_v3' require 'googleauth' require 'googleauth/stores/file_token_store' require 'json' require 'net/http' module Ngdrive # google drive util to download files from folder recursively class GdriveUtil # rubocop:disable Metrics/ClassLength SCOPE = Google::Apis::DriveV3::AUTH_DRIVE_READONLY attr_reader :drive_service def initialize @config = YAML.load_file('./settings.yml') @drive_service = Google::Apis::DriveV3::DriveService.new @drive_service.client_options.application_name = @config['app']['name'] @drive_service.authorization = authorize end def get_entries(folder_id) all_files = fetch_files(folder_id) folders = get_folders(all_files['items']) files = get_files(all_files['items']) entries = {} entries[:files] = files.map { |x| { id: x['id'], name: x['title'] } } folders.each do |folder| title = folder['title'] entries[title] = get_entries(folder['id']) end entries end def root_folder_id @config['gdrive']['folder_id'] end def download_folder @config['app']['download_dir'] end def download_files entries = get_entries(root_folder_id) download!(entries) end def download!(root, path = []) return unless root folder = create_folder!(path) root[:files].each do |file| file_path = "#{folder}/#{file[:name]}" drive_service.get_file(file[:id], download_dest: file_path) end folders = root.keys.reject { |x| x == :files } folders.each do |folder_key| download!(root[folder_key], path + [folder_key]) end end private def create_folder!(path) folder = "#{download_folder}/#{path.join('/')}" Dir.mkdir(folder) unless File.exist?(folder) folder end def authorize # rubocop:disable Metrics/AbcSize, Metrics/MethodLength client_id = Google::Auth::ClientId.from_file( @config['app']['credentials'] ) token_store = Google::Auth::Stores::FileTokenStore.new( file: @config['app']['token'] ) authorizer = Google::Auth::UserAuthorizer.new( client_id, SCOPE, token_store ) user_id = 'default' credentials = authorizer.get_credentials user_id if credentials.nil? url = authorizer.get_authorization_url( base_url: @config['app']['oob_uri'] ) puts 'Allow Authorization (Pair User Credentials) on Consent Form ' \ 'Open the following URL in the browser and enter the ' \ "resulting code after authorization:\n" + url code = gets credentials = authorizer.get_and_store_credentials_from_code( user_id: user_id, code: code, base_url: @config['app']['oob_uri'] ) end credentials end def fetch_files(folder_id) # rubocop:disable Metrics/MethodLength prefix = 'https://www.googleapis.com/drive/v2/files?q=' uri = URI("#{prefix}'#{folder_id}'+in+parents") req = Net::HTTP::Get.new(uri) token = drive_service.request_options.authorization.access_token req['Authorization'] = "Bearer #{token}" res = Net::HTTP.start( uri.hostname, uri.port, use_ssl: uri.scheme == 'https' ) do |http| http.request(req) end resp = JSON.parse(res.body) resp end def get_folders(collection) collection.select(&method(:folder?)) end def get_files(collection) collection.reject(&method(:folder?)) end def folder?(param) param['mimeType'] == 'application/vnd.google-apps.folder' end def get_only_pdf_files(collection) collection.select { |x| x['mimeType'] == 'application/pdf' } end end end