Ruby の Google Drive API でファイルを削除すると権限の問題が発生する
概要
スプレッドシートのタブから json ファイルを作成する Google Apps Script があります。
function makeJSON() {
var spreadsheetId = 'someId';
var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
var sheets = spreadsheet.getSheets();
var urls = []; // Array to store the URLs of the created files
for (var i = 1; i < sheets.length; i++) {
var sheet = sheets[i];
var data = sheet.getRange(3, 1, sheet.getLastRow() - 2, sheet.getLastColumn()).getValues();
var headers = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0];
var objects = data.map(function(row) {
var obj = {};
for (var j = 0; j < headers.length; j++) {
//process data
}
return obj;
});
// Convert the array of objects to a JSON string
var json = JSON.stringify(objects, null, 2);
// Create a blob from the JSON string
var blob = Utilities.newBlob(json, 'application/json', sheet.getName() + '.json');
var folder = DriveApp.getFolderById('someId');
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT); //I don't like making these publicly editable but it seems I'm forced to in order to be able to download/delete them via ruby script
// Get the file ID
var fileId = file.getId();
// Construct the direct download URL
var directDownloadUrl = "https://drive.google.com/uc?export=download&id=" + fileId;
// Add the direct download URL to the array
urls.push(directDownloadUrl);
}
return urls;
}
function doGet() {
var urls = makeJSON(); // Call the function to generate JSON files and get their URLs
return ContentService.createTextOutput(JSON.stringify({urls: urls})).setMimeType(ContentService.MimeType.JSON);
}
これらすべてのファイルを Google ドライブからダウンロードする Ruby スクリプトがあります。その部分は機能します。ただし、ダウンロード後に削除したいと考えています。
drive_service = Google::Apis::DriveV3::DriveService.new
scope = 'https://www.googleapis.com/auth/drive'
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open('google_client.json'),
scope: scope
)
authorizer.fetch_access_token!
# Set the authorization for the Drive API client
drive_service.authorization = authorizer
# URL of your deployed web app that returns JSON file URLs
web_app_url = 'https://script.google.com/macros/s/digits/exec'
# Fetch the JSON data from the web app
response = URI.open(web_app_url).read
json_data = JSON.parse(response)
# Directory to save the JSON files
save_directory = 'downloads'
# Ensure the directory exists
FileUtils.mkdir_p(save_directory) unless File.directory?(save_directory)
json_data['urls'].each do |url|
# Extract the file ID from the URL
file_id = url.split('id=')[1]
# Fetch the file's metadata using the Google Drive API
file_metadata = drive_service.get_file(file_id, fields: 'name')
# Extract the file name
file_name = file_metadata.name
# Construct the direct download URL
direct_download_url = "https://drive.google.com/uc?export=download&id=#{file_id}"
# Construct the full path
file_path = File.join(save_directory, file_name)
# Download the file
URI.open(direct_download_url) do |source|
File.open(file_path, 'wb') do |file|
file.write(source.read)
end
end
puts "Saved #{file_name} to #{save_directory}"
# Delete the file from Google Drive
drive_service.delete_file(file_id) #THIS LINE THROWS THE ERROR
end
エラーは次のとおりです。
/Users/me/.rvm/gems/ruby-2.7.2/gems/google-apis-core-0.14.0/lib/google/apis/core/http_command.rb:244:in `check_status': insufficientFilePermissions: The user does not have sufficient permissions for this file. (Google::Apis::ClientError)
問題は、私の Ruby スクリプトの認証情報が私のサービス アカウント ([email protected]) からのものであり、Google ドライブ上のファイルの所有者が「私」([email protected]) であることだと思います。しかし、そもそもそれらを自分のサービス アカウントに所有させる方法も、通常の電子メール アカウントの資格情報を使用してスクリプトを実行する方法もわかりません。 Cloud コンソールでサービス アカウントを作成すると、*.iam.gserviceaccount.com アカウントの使用が強制されます。
Google ドライブ フォルダーはサービス アカウントと共有されています。その中のファイルはすべて「私」が所有しており、私のサービス アカウントにはすべてのファイルに対する編集者権限があります。
とはいえ、これらのファイルをダウンロードした後、Google ドライブからこれらのファイルを削除するにはどうすればよいでしょうか?ファイルはすぐに溜まってしまうので、このディレクトリをクリーンな状態に保つ必要があります。
解決策
あなたの状況では、簡単なアプローチとして、Web Apps でファイルを削除してみてはどうでしょうか?これをスクリプトに反映させる場合、次のように修正してみてはいかがでしょうか。
この変更により、ファイルのダウンロード後、Web Apps でファイルが削除されるようになります。
このスクリプトを使用する前に、高度な Google サービスで Drive API v3 を有効にしてください。
function makeJSON(e) { // Modified
// Added
if (e.parameter.deleteFile) {
Drive.Files.remove(e.parameter.deleteFile); // or Drive.Files.remove(e.parameter.deleteFile, { supportsAllDrives: true });
return [];
}
var spreadsheetId = 'someId';
var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
var sheets = spreadsheet.getSheets();
var urls = []; // Array to store the URLs of the created files
for (var i = 1; i < sheets.length; i++) {
var sheet = sheets[i];
var data = sheet.getRange(3, 1, sheet.getLastRow() - 2, sheet.getLastColumn()).getValues();
var headers = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0];
var objects = data.map(function(row) {
var obj = {};
for (var j = 0; j < headers.length; j++) {
//process data
}
return obj;
});
// Convert the array of objects to a JSON string
var json = JSON.stringify(objects, null, 2);
// Create a blob from the JSON string
var blob = Utilities.newBlob(json, 'application/json', sheet.getName() + '.json');
var folder = DriveApp.getFolderById('someId');
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT); //I don't like making these publicly editable but it seems I'm forced to in order to be able to download/delete them via ruby script
// Get the file ID
var fileId = file.getId();
// Construct the direct download URL
var directDownloadUrl = "https://drive.google.com/uc?export=download&id=" + fileId;
// Add the direct download URL to the array
urls.push(directDownloadUrl);
}
return urls;
}
function doGet(e) { // Modified
var urls = makeJSON(e); // Modified
return ContentService.createTextOutput(JSON.stringify({urls: urls})).setMimeType(ContentService.MimeType.JSON);
}
drive_service = Google::Apis::DriveV3::DriveService.new
scope = 'https://www.googleapis.com/auth/drive'
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open('google_client.json'),
scope: scope
)
authorizer.fetch_access_token!
# Set the authorization for the Drive API client
drive_service.authorization = authorizer
# URL of your deployed web app that returns JSON file URLs
web_app_url = 'https://script.google.com/macros/s/digits/exec'
# Fetch the JSON data from the web app
response = URI.open(web_app_url).read
json_data = JSON.parse(response)
# Directory to save the JSON files
save_directory = 'downloads'
# Ensure the directory exists
FileUtils.mkdir_p(save_directory) unless File.directory?(save_directory)
json_data['urls'].each do |url|
# Extract the file ID from the URL
file_id = url.split('id=')[1]
# Fetch the file's metadata using the Google Drive API
file_metadata = drive_service.get_file(file_id, fields: 'name')
# Extract the file name
file_name = file_metadata.name
# Construct the direct download URL
direct_download_url = "https://drive.google.com/uc?export=download&id=#{file_id}"
# Construct the full path
file_path = File.join(save_directory, file_name)
# Download the file
URI.open(direct_download_url) do |source|
File.open(file_path, 'wb') do |file|
file.write(source.read)
end
end
puts "Saved #{file_name} to #{save_directory}"
# Delete the file from Google Drive
# removed: drive_service.delete_file(file_id) #THIS LINE THROWS THE ERROR
URI.open(web_app_url + "?deleteFile=#{file_id}") # Modified
end