Revert Revision of an Excel File - Drive API - google-apps-script

I have an Excel file on my Drive (web version). That Excel has many versions. I require the file every so often to revert to a specific version without deleting the most recent version.
I have the following code:
function revertRevisionExcel() {
var revisionId = "######"; // Revision ID to revert.
var fileId = "#####"; // Set the file ID.
var endpoint = "";
var token = ScriptApp.getOAuthToken();
Logger.log(token);
var res = Drive.Revisions.get(fileId, revisionId);
endpoint =
"https://www.googleapis.com/drive/v3/files/" +
fileId +
"/revisions/" +
revisionId +
"?pageToken=" +
token;
var mediaData = UrlFetchApp.fetch(endpoint).getBlob();
Drive.Files.update({}, fileId, mediaData);
}
When I run it shows me the error 401 "Login Required". Could any one please guide me?

Modification points:
About your question of When I run it shows me the error 401 "Login Required". Could any one please guide me?, when I saw your script, I think that the following modification is required.
token and res are not used.
I think that var token = ScriptApp.getOAuthToken() cannot be used for the query parameter of ?pageToken=" + token.
I think that the reason of your issue of Login Required is due to this. In this case, please use the access token retrieved by var token = ScriptApp.getOAuthToken() to the request header.
In order to retrieve the blob from the specific revision, please use alt=media in the query parameter.
When above modification points are reflected to your script, it becomes as follows.
Modified script:
function revertRevisionExcel() {
var revisionId = "######"; // Revision ID to revert.
var fileId = "#####"; // Set the file ID.
var endpoint = "https://www.googleapis.com/drive/v3/files/" + fileId + "/revisions/" + revisionId + "?alt=media";
var token = ScriptApp.getOAuthToken();
var mediaData = UrlFetchApp.fetch(endpoint, {headers: {authorization: "Bearer " + token}}).getBlob();
Drive.Files.update({}, fileId, mediaData);
}
Note:
In this modified script, it supposes that you have already enabled Drive API at Advanced Google services and the values of revisionId and fileId are the valid values. Please be careful this.
References:
Revisions: get
fetch(url, params)

Related

Export Google Sheet as .xlsx and send file to server

My company manages non-confidential information in a Google Sheet. Every day, I export that sheet to .xlsx format and then upload it to various services for data syndication.
Normally, such a process could be automated using the "Publish to Web" feature. But for security reasons, that option is locked for all users.
I do have full permissions for Google Apps Script, though. So, I'd like to write a script for this. The particulars don't matter. Somehow, I need to export the sheet on a schedule and send it to an AWS server, where it can be automatically retrieved.
At the AWS side, I can easily set up an email server, FTP server, rclone, whatever. I just need to figure out what to do on the Google side first.
Can this be done?
What I have tried so far:
Export a Google Sheet to Google Drive in Excel format with Apps Script
function makeCopy() {
var formattedDate = Utilities.formatDate(new Date(), "CET", "yyyy-MM-dd' 'HH:mm");
var name = "Backup Copy " + formattedDate;
var destination = DriveApp.getFolderById("1vFL98cgKdMHLNLSc542pUt4FMRTthUvL");
// Added
var sheetId = "2SqIXLiic6-gjI2KwQ6OIgb-erbl3xqzohRgE06bfj2c";
var url = "https://docs.google.com/spreadsheets/d/" + sheetId + "/export?format=xlsx&access_token=" + ScriptApp.getOAuthToken();
var blob = UrlFetchApp.fetch(url).getBlob().setName(name + ".xlsx"); // Modified
destination.createFile(blob);
}
--- OR ---
function convertSheetToXLSX() {
var sheetId = "2SqIXLiic6-gjI2KwQ6OIgb-erbl3xqzohRgE06bfj2c";
var spreadsheetName = "My Spreadsheet";
var destination = DriveApp.getFolderById("1vFL98cgKdMHLNLSc542pUt4FMRTthUvL");
var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + sheetId + "&exportFormat=xlsx";
var params = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
};
var blob = UrlFetchApp.fetch(url, params).getBlob();
blob.setName(spreadsheetName + ".xlsx");
destination.createFile(blob);
}
I have tried these scripts from the URL posted above but it results in "An unknown error has occurred, please try again later."
Take a look at this thread. It is about sending a spreadsheet in PDF format, but if you just change the ExportOptions to xlsx, you should be able to make it.

error "Invalid argument:" when using UrlFetchApp.fetch(url) with where date 'yyy-MM-dd'

I use this sheet and I want to get the values where the date is > to '2020-07-21',
the data source URL I used with html output is: https://docs.google.com/spreadsheets/d/1u78Qx5YIB2mektPyErz6xYtTXMLLtCapXlEpp63NTYI/gviz/tq?tqx=out:html&tq=select B where date '2020-07-21' > A &gid=0
the problem that when I se the data source URL in chrome browser, I could see the response data but when running that with the function UrlFetchApp.fetch(url) I receice an error.
the code in script editor:
function myFunction() {
var url ="https://docs.google.com/spreadsheets/d/1u78Qx5YIB2mektPyErz6xYtTXMLLtCapXlEpp63NTYI/gviz/tq?tqx=out:csv&tq=select B where date '2020-07-21' > A &gid=0"
var response = UrlFetchApp.fetch(url).getContentText();
Logger.log(response);
}
In your case, there are the following modification points.
Modification points:
Please do the URL encode for select B where date '2020-07-21' > A.
Please request to the endpoint using the access token.
In this case, because the data is retrieved, I think that the scope of https://www.googleapis.com/auth/drive.readonly can be used.
When these points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
var query = "select B where date '2020-07-21' > A";
var url ="https://docs.google.com/spreadsheets/d/1u78Qx5YIB2mektPyErz6xYtTXMLLtCapXlEpp63NTYI/gviz/tq?tqx=out:html&tq=" + encodeURIComponent(query) + "&gid=0";
var params = {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}};
var response = UrlFetchApp.fetch(url, params).getContentText();
Logger.log(response);
// DriveApp.getFiles() // This line is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive.readonly". So please don't remove this line.
}
When you run the script, the authorization dialog is opened. So please authorize the scopes. By this, the script is run.
Note:
If your Spreadsheet is publicly shared, I think that params is not required. At that time, you can remove // DriveApp.getFiles().
If you want to use the scope of https://www.googleapis.com/auth/drive instead of https://www.googleapis.com/auth/drive.readonly, please use // DriveApp.createFile() instead of // DriveApp.getFiles()
References:
encodeURIComponent()
Class UrlFetchApp

Google Cloud Logging API with Apps Script - delete logs - The requested URL was not found on this server

Using Apps Script, I need to delete the Stackdriver logs of a particular Google Cloud Project. This should be possible to do with Apps Script and the Cloud Logging REST API, using a DELETE request. Apps Script UrlFetchApp.fetch(url,options) can use the DELETE method. The code below is returning response code: 404. I was previously getting response code: 400, but now it's accepting the URL structure, but it just can't find the URL. If the URL needs a log ID, then I'm not sure where to get the log ID. I want to delete all logs in the project, not just a particular one.
Error Message:
The requested URL was not found on this server.
Code:
function deleteStackDriverLogs(po) {
var httpRz,options,url;
/*
po.id = GCP project ID - https://console.cloud.google.com/home/dashboard
*/
options = {};
options.method = "delete";
options.muteHttpExceptions = true;
options.headers = {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()};
options.contentType = "application/json";
url = 'https://logging.googleapis.com/v2/';
options.payload = JSON.stringify({
logName: 'projects/' + po.id + "/logs/*"
});
httpRz = UrlFetchApp.fetch(url,options);
Logger.log('response code: ' + httpRz.getResponseCode());
//Logger.log('httpRz.getAllHeaders(): ' + JSON.stringify(httpRz.getAllHeaders()))
//Logger.log(httpRz.getContentText())
}
function testDlet() {
deleteStackDriverLogs({"id":"project-id-your-GCP-id-here"});
}
Documentation:
https://cloud.google.com/logging/docs/reference/v2/rest/v2/logs/delete
If just a URL without the payload is used, then I get response code 404 with no explanation.
I've tried many variations of the url.
url = 'https://logging.googleapis.com/v2/logName={projects/' + po.id + '}';//404
url = 'https://logging.googleapis.com/v2/logName=projects/' + po.id + '/';//404
url = 'https://logging.googleapis.com/v2/logName=projects/' + po.id;//404
url = 'https://logging.googleapis.com/v2/logName=projects/' + po.id + '/logs/*/';//400
url = 'https://logging.googleapis.com/v2/logName=projects/' + po.id + '/logs/';//404
The documentation states that the Log ID must be URL-encoded. But, I'm not sure what to use for the Log ID.
I believe your goal as follows.
You want to delete the logs of the stackdriver using Google Apps Script.
For this, how about this answer?
Modification points:
In this case, please retrieve the log name for deleting the logs.
You can retrieve logName using the method "logs.list" in Could Logging API v2.
Please use logName as the path of the endpoint.
When above points are reflected to your script, it becomes as follows.
Modified script:
function deleteStackDriverLogs(po) {
// --- I added below script.
const endpoint = `https://logging.googleapis.com/v2/projects/${po.id}/logs`;
const res = UrlFetchApp.fetch(endpoint, {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}});
const obj = JSON.parse(res.getContentText());
const logName = obj.logNames.filter(e => e.includes("console_logs"))[0];
/// ---
var httpRz,options,url;
/*
po.id = GCP project ID - https://console.cloud.google.com/home/dashboard
*/
options = {};
options.method = "delete";
options.muteHttpExceptions = true;
options.headers = {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()};
url = 'https://logging.googleapis.com/v2/' + logName; // Modified
httpRz = UrlFetchApp.fetch(url,options);
Logger.log('response code: ' + httpRz.getResponseCode());
//Logger.log('httpRz.getAllHeaders(): ' + JSON.stringify(httpRz.getAllHeaders()))
//Logger.log(httpRz.getContentText())
}
Note:
This is a simple modification for your script. So please modify this for your actual situation.
This modified script supposes that you have already been able to use Could Logging API v2.
In this case, please use this script with V8.
References:
Method: logs.list
Method: logs.delete

How to get file (video) duration of google drive file programmatically?

Either using rest API, Google Scripts, Node SDK, whatever works.
I'm seeing this in the docs but that doesn't seem to tell me the duration:
function watchFile(fileId, channelId, channelType, channelAddress) {
var resource = {
'id': channelId,
'type': channelType,
'address': channelAddress
};
var request = gapi.client.drive.files.watch({
'fileId': fileId,
'resource': resource
});
request.execute(function(channel){console.log(channel);});
}
I found this link but it doesn't seem to help https://apis-nodejs.firebaseapp.com/drive/classes/Resource$Files.html#watch
You want to retrieve the duration of the video on your Google Drive.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this sample script? In this modification, I used files.get and files.list methods of Drive API. From your question, I thought that the script that the endpoint is directly requests might be useful for your situation. So I proposed the following script.
1. Using files.get method
In this sample script, the duration is retrieved from a video file.
Sample script:
function sample1() {
var fileId = "###"; // Please set the file ID of the video file.
var fields = "mimeType,name,videoMediaMetadata"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files/" + fileId + "?fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res);
Logger.log("filename: %s, duration: %s seconds", obj.name, obj.videoMediaMetadata.durationMillis / 1000);
// DriveApp.getFiles() // This line is put for automatically detecting the scope (https://www.googleapis.com/auth/drive.readonly) for this script.
}
2. Using files.list method
In this sample script, the durations are retrieved from a folder including the video files.
Sample script:
function sample2() {
var folderId = "###"; // Please set the folder ID including the video files.
var q = "'" + folderId + "' in parents and trashed=false";
var fields = "files(mimeType,name,videoMediaMetadata)"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files?q=" + encodeURIComponent(q) + "&fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res);
for (var i = 0; i < obj.files.length; i++) {
Logger.log("filename: %s, duration: %s seconds", obj.files[i].name, obj.files[i].videoMediaMetadata.durationMillis / 1000);
}
// DriveApp.getFiles() // This line is put for automatically detecting the scope (https://www.googleapis.com/auth/drive.readonly) for this script.
}
Note:
These are simple sample scripts. So please modify them for your situation.
I'm not sure about the format of your video files. So if above script cannot be used for your situation, I apologize.
References:
Files of Drive API
Class UrlFetchApp
If I misunderstood your question and this was not the result you want, I apologize.
Updated: March 19, 2020
From January, 2020, the access token cannot be used with the query parameter like access_token=###. Ref So please use the access token to the request header instead of the query parameter. It's as follows.
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});

Google apps script to email google spreadsheet excel version [duplicate]

This question already has answers here:
Google app scripts: email a spreadsheet as excel
(2 answers)
Closed 2 years ago.
I would like to write an apps script to email an excel version of my Google Spreadsheet. I know I can save the spreadsheet as an Excel file. I am not sure if I can use the script to email the excel version out as an attachment. How can this be done?
After an answer on another recent post (Thomas van Latum), I tried the suggested doc api and get an interesting result... here is the test code I used and that is working nicely except the file is in xlsx format, not in xls but this is not necessarily an issue these days :
function googleOAuth_(name,scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:name, oAuthUseToken:"always"};
}
function test(){
var id = 'spreadsheet_ID'
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
googleOAuth_('docs',url)).getBlob()
DocsList.createFile(doc).rename('newfile.xls')
}
note : if you don't rename it, its default name is Export.xlsx , it might be more usefull to get its ID to use it later...
so the last line could be like this instead :
var xlsfileID = DocsList.createFile(doc).getId()
EDIT : to trigger the authorization process, try a small function like this, run it from the script editor
function autorise(){
// function to call to authorize googleOauth
var id=SpreadsheetApp.getActiveSpreadsheet().getId();
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/documents/Export?exportFormat=html&format=html&id='+id,
googleOAuth_('docs',url)).getContentText();
}
As I spent about four hours of playing Rumpelstiltskin because none of the typically very old code snippets for the old Spreadsheet versions and the old OAUTH you can find when googling "google docs script send excel attachment" or similar (i.e. you want to take an existing Spreadsheet, convert it to Excel format and send it as email attachment) actually worked, I finally found the solution.
To create the actual attachment content, neither the supposed res.getContent() nor res.getBlob() nor res.getBytes alone worked. These hints are misleading!
The only thing that works for me is response.getBlob().getContent()!
Whole code :
function sendCurrentDocAsEmail() {
var driveService = getDriveService();
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getName();
var email = "recipient#demo.com"
var subject = "Here be Subjects";
var body = "Don't even think about learning how to code. It's wasted time.";
var file = Drive.Files.get(ssID );
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + driveService.getAccessToken()
}
});
var attachments = [{
fileName:sheetName+".xlsx",
content: response.getBlob().getBytes(), // this single line has cost me hours!
mimeType:"application//xls",
headers: {
Authorization: 'Bearer ' + driveService.getAccessToken()
}
}];
MailApp.sendEmail(email,subject ,body, {attachments:attachments});
}
Where getDriveService() is a function from Google's "OAuth2 for Apps Script" readme on https://github.com/googlesamples/apps-script-oauth2
The latest working version is below. Based on this example, i.e. similar as in previous answer but uses Google Service Account which does not require a human going by link to receive a token. You have to install Oath library from Google, the instructions are pretty clear.
var PRIVATE_KEY = 'xxx'
var CLIENT_EMAIL = 'xxx';
var USER_EMAIL=Session.getActiveUser().getEmail()
function getOathService() {
return OAuth2.createService('GoogleDrive:' + USER_EMAIL)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(USER_EMAIL)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope('https://www.googleapis.com/auth/drive');
}
function sendEmail() {
var oathService = getOathService();
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var file = Drive.Files.get(ssID );
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
var file = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + oathService.getAccessToken()
}
});
var attachments = [{
fileName:'xxx.xls',//TODO DATE
content: file.getBlob().getBytes(),
mimeType:"application//xls",
headers: {
Authorization: 'Bearer ' + oathService.getAccessToken()
}
}];
MailApp.sendEmail('email#domain.com', 'xxx', 'Hi,\n\nPlease see the last data in attachment',{attachments:attachments});
}
The one that worked for me:
var AUTH_TOKEN = "Enter your OAuth_Token";
ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var url = "http://spreadsheets.google.com/feeds/download/spreadsheets/Export?key="+ ssID + "&exportFormat=xls";
//Add &gid=x at the end of above url if you only want a particular sheet
var auth = "AuthSub token=\"" + AUTH_TOKEN + "\"";
var res = UrlFetchApp.fetch(url, {headers: {Authorization: auth}});
var attachments = [{fileName:"<Filename>.xls", content: res.getContent(),mimeType:"application/vnd.ms-excel"}];
MailApp.sendEmail("<recipient's email id>", "<email subject>", "<email body>", {attachments: attachments});
Get OAuth documentation & you token from here https://developers.google.com/accounts/docs/OAuth2
Use the following snippet of code after modifying it to suit your needs
var file = DocsList.getFileById(FILE_ID);
var attachment = file.getAs('application/vnd.ms-excel');
MailApp.sendEmail("abcd#example.com", "Subject", " Body" , {"fileName": "Your_file_name" , "mimeType" : "application/vnd.ms-excel" , "content":attachment.getBytes() } );
Note that this code is not tested, so please feel free to fix an error or two that might pop up