Trigger spreadsheet script after change by IFTTT - javascript

Is there a way to make a google spreadsheet script run if the sheet is edited by IFTTT instead of by a person via the sheets browser?
Background: IFTTT put a value in a specific cell. My google spreadsheet script says if the cell is not empty; insert a new row. So my script is running if my sheet is edited by me manually and I put a value in that cell. However, if IFTTT adds a new entry to the spreadsheet nothing happens. I have tried both the onEdit and onChange triggers to no avail. Any suggestions?
The actual script I am using is below:
(function InsertRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Diagramm');
var values = sheet.getRange('B2').getValues();
if (values[0][0] != "")
sheet.insertRowBefore(2);
})();
So I followed the tutorial on Google Driver API Push Notifications and added following code to my script:
function listFiles() {
var optionalArgs = {
maxResults: 10
};
var response = Drive.Files.list(optionalArgs);
var files = response.items;
if (files && files.length > 0) {
Logger.log('Files:');
for (i = 0; i < files.length; i++) {
var file = files[i];
Logger.log('%s (%s)', file.title, file.id);
}
} else {
Logger.log('No files found.');
}
};
But what do I need to do now? Sorry I am not a good programmer...

You have to use Drive API push notifications to pick up these changes.
This example on using Apps Script with the Drive API is helpful to get started.
Spencer Easton has also provided a tutorial on get GMail push notifications that'll give you some hints on setting this up as you have to make some changes in the dev console.

Related

Delete curent item in a Javascript while hasNext-loop?

I have read 10+ questions about deleting items in Javascripts loops but they don't seem to apply to my situation.
I have this code
var childFolders = parent.getFolders();
// List folders inside the folder
while (childFolders.hasNext()) {
var childFolder = childFolders.next();
//processing childFolder
After this I want to delete the current item (childFolder) from the array childFolders. The reason is that I am doing some work in a Google Apps script but it often takes too long and times out so I need to be able to restart the loop and only have unprocessed items left in the array. To achieve this, in every loop, I copy the content of childFolders into a permanent storage that I can restore on the next run.
I believe your goal is as follows.
You want to stop the loop of the folder iterator, and when you run the script again, you want to start the folder iterator from the stopped iterator.
In this case, how about using "ContinuationToken"? When "ContinuationToken" is used, I thought that your goal might be able to be achieved by the native methods of Google Apps Script. When this is reflected in your script, how about the following script?
Sample script:
Please set var parent = DriveApp.getFolderById("###");.
// When you want to clear the token, please run this function.
function clearToken() {
PropertiesService.getScriptProperties().deleteProperty("token");
}
// This is the main function.
function main() {
var parent = DriveApp.getFolderById("###"); // Please set your parent folder.
var numberOfLoop = 2; // The folder iterator is run every this number.
var p = PropertiesService.getScriptProperties();
var token = p.getProperty("token");
var childFolders = token ? DriveApp.continueFolderIterator(token) : parent.getFolders();
var count = 0;
while (childFolders.hasNext()) {
count++;
var childFolder = childFolders.next();
//processing childFolder
console.log(childFolder.getName()); // This is a sample.
if (count == numberOfLoop) {
var token = childFolders.getContinuationToken();
p.setProperty("token", token);
break;
}
}
}
When you run main function, in this sample script, 2 folders are processed and the script is finished. When you run main again, the folder iterator is started from the continuation.
When you want to start from the 1st folder iterator, please run clearToken.
References:
getContinuationToken() of Class FolderIterator
continueFolderIterator(continuationToken) of Class DriveApp
Added:
From your following reply,
It is the script in step 3 here ourtechroom.com/fix/… I have problem with. I changed it to add all files to an array first and insert them into a sheet in a separate step at the end but that wasn't enough. Hence my question.
My issue is that your solution is a little too complicated for me. That is, I have a hard time applying your solution to the script in the link.
Do you want to retrieve the file metadata of all files in your Google Drive? If my understanding is correct, I think that the script in your link is a high process cost because appendRow is used in the loop. Ref I thought that this might be the reason for your actual situation. If my understanding is correct, how about the following sample script?
Usage:
1. Install Google Apps Script library.
You can see how to install Google Apps Script library of [FilesApp] at here.
2. Enable Drive API.
This modified script uses Drive API. So, please enable Drive API at Advanced Google services.
3. Sample script.
Please copy and paste the following script to the script editor of Spreadsheet. And, please set the top folder ID to folderId. If you use var folderId = "root";, all files in your Google Drive are retrieved.
function myFunction() {
var folderId = "###"; // Please set the top folder ID.
var header = ["parent", "folder", "name", "update", "Size", "URL", "ID", "description", "type"]; // This is from your script.
var obj = FilesApp.createTree(folderId, null, "files(name,modifiedTime,size,webViewLink,id,description,mimeType)");
var values = [header, ...obj.files.flatMap(({ folderTreeByName, filesInFolder }) => {
const f = [folderTreeByName.join("|"), folderTreeByName.pop()];
return filesInFolder.length == 0 ? [[...f, ...Array(7).fill(null)]] : filesInFolder.filter(({ mimeType }) => mimeType != MimeType.FOLDER).map(({ name, modifiedTime, size, webViewLink, id, description, mimeType }) => [...f, name || null, new Date(modifiedTime), size || 0, webViewLink, id, description || null, mimeType]);
})];
SpreadsheetApp.getActiveSheet().clear().getRange(1, 1, values.length, values[0].length).setValues(values);
}
References:
FilesApp of Google Apps Script library (Author me)
Files: list of Drive API v3

Upload PDF file in Google sheet using Google apps script

I am trying to upload pdf file to a single cell in google sheet just like we insert image in a google sheet cell. I've searched for quite some time now, but haven't been able to find any solutions to this. I have tried the following code:
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var menuEntries = [];
menuEntries.push({name: "File...", functionName: "doGet"});
ss.addMenu("Attach ...", menuEntries);
}
function doGet(e) {
var app = UiApp.createApplication().setTitle("upload attachment into Google Drive");
SpreadsheetApp.getActiveSpreadsheet().show(app);
var form = app.createFormPanel().setId('frm').setEncoding('multipart/form-data');
var formContent = app.createVerticalPanel();
form.add(formContent);
formContent.add(app.createFileUpload().setName('thefile'));
formContent.add(app.createHidden("activeCell", SpreadsheetApp.getActiveRange().getA1Notation()));
formContent.add(app.createHidden("activeSheet", SpreadsheetApp.getActiveSheet().getName()));
formContent.add(app.createHidden("activeSpreadsheet", SpreadsheetApp.getActiveSpreadsheet().getId()));
formContent.add(app.createSubmitButton('Submit'));
app.add(form);
SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
function doPost(e) {
var app = UiApp.getActiveApplication();
app.createLabel('saving...');
var fileBlob = e.parameter.thefile;
var doc = DriveApp.getFolderById('0B0uw1JCogWHuc29FWFJMWmc3Z1k').createFile(fileBlob);
var label = app.createLabel('file uploaded successfully');
var value = 'hyperlink("' + doc.getUrl() + '";"' + doc.getName() + '")'
var activeSpreadsheet = e.parameter.activeSpreadsheet;
var activeSheet = e.parameter.activeSheet;
var activeCell = e.parameter.activeCell;
var label = app.createLabel('file uploaded successfully');
app.add(label);
SpreadsheetApp.openById(activeSpreadsheet).getSheetByName(activeSheet).getRange(activeCell).setFormula(value);
app.close();
return app;
}
Since UiApp has been deprecated so it shows the error "UiApp has been deprecated. Please use HtmlService instead". I have tried the following line to avoid UiApp error but of no use:
var app = HtmlService.createHtmlOutput();
Is there any workaround that we can get to avoid this error? Thank you.
I believe your goal is as follows.
From your following comments,
I have pdf file in local pc, I would have a google sheet add-on with an option "file upload". I would click on that, it will upload file in the Drive folder which we have specified in script and the active google sheet cell will show the confirmation message.
I want to put the message in currently active cell of the sheet
You wanted to upload a PDF file on the local PC to Google Drive. And you want to put the confirmation message to a current active cell. You want to achieve this by a sidebar using HTML and Google Apps Script.
In this case, how about the following sample script?
Sample script:
Google Apps Script side: Code.gs
Please copy and paste the following script to the script editor of Google Spreadsheet as the script file and save the script.
const openSidebar = _ => SpreadsheetApp.getUi().showSidebar(HtmlService.createHtmlOutputFromFile("index"));
function upload(e){
const message = "sample confirmation message"; // Please set your confirmation message.
DriveApp.createFile(Utilities.newBlob(...e));
SpreadsheetApp.getActiveRange().setValue(message);
}
HTML&Javascript side: index.html
Please copy and paste the following script to the script editor of Google Spreadsheet as the HTML file and save the script.
<form>
<input type="file" name="file" onchange="upload(this.parentNode)" accept=".pdf,application/pdf" />
</form>
<script>
function upload(e){
const file = e.file.files[0];
const fr = new FileReader();
fr.onload = e => google.script.run.upload([[...new Int8Array(e.target.result)], file.type, file.name]);
fr.readAsArrayBuffer(file);
}
</script>
Testing:
When you run the function openSidebar, the sidebar is opened. And when you select the file from the input tag, the file is uploaded to the root folder of Google Drive, and the confirmation message is put to the active cell.
Note:
In this method, the maximum file size is 50 MB because of the specification of the Google Apps Script side. Please be careful about this.
This is a simple sample script for achieving the goal of your question. So please modify this for your actual situation.
Reference:
Dialogs and Sidebars in Google Workspace Documents

Writing to Excel spreadsheet with ASP.Net site using the Excel Javascript API

I have created an ASP.Net webapp using the Empty Template in Visual Studio 2017. The website has many familiar Web Controls such as Button (s), ImageButton, and Label (s). Users open a picture inside the ImageButton control and are able to click inside the control. The webapp calculates a value depending on where the user clicks in the ImageButton, and the values are displayed in the corresponding Label controls. The user is meant to write the values into an open Excel Spreadsheet (this is where the issue lies). For additional context, every action taken by the user is handled by a client-side javascript function-- with the exception of opening the picture. The opening action is handled by C# code belonging to the aspx page.
In the process of writing a similar Excel Web Add In, I found some very helpful code for writing to an Excel Spreadsheet using the Excel JavaScript API.
Here is that very code:
function HighlightCell() {
Excel.run(function (ctx) {
// Create a proxy object for the selected range and load its properties
var sourceRange = ctx.workbook.getSelectedRange().load("values, rowCount, columnCount");
var sheet = ctx.workbook.worksheets.getActiveWorksheet()
// Run the queued-up command, and return a promise to indicate task completion
return ctx.sync()
.then(function () {
var highestRow = 0;
var highestCol = 0;
var highestValue = sourceRange.values[0][0];
// Find the cell to highlight
for (var i = 0; i < sourceRange.rowCount; i++) {
for (var j = 0; j < sourceRange.columnCount; j++) {
if (!isNaN(sourceRange.values[i][j]) && sourceRange.values[i][j] > highestValue) {
highestRow = i;
highestCol = j;
highestValue = sourceRange.values[i][j];
}
}
}
cellToHighlight = sourceRange.getCell(highestRow, highestCol);
cellToHighlight.format.fill.color = "IndianRed";
cellToHighlight.values = 5;
})
.then(ctx.sync);
})
.catch(errorHandler);
}
The code works like a charm within the Excel Web Add In, but it hasn't worked so far within the ASP.Net webapp. From my understanding, it is because the code hasn't been able to retrieve the active workbook / worksheet. This could be because of the disconnect between the server and the client-side from what I know.
Is there any way to open an excel spreadsheet on the client-side with javascript or C#. Can I even use the above code in an ASP.Net webapp?
EDIT: more code
I opened the spreadsheet on the client side with this code:
function excload() {
var selectedFile = document.getElementById('imgupload').files[0];
document.getElementById("frame").src = window.URL.createObjectURL(selectedFile);
}
In this code, imgupload is an HTML file input and "frame" is an iframe element. I'm not sure why when I run it, instead of just opening the spreadsheet in the iframe, it opens the spreadsheet in a new instance of the Excel program on the computer.
Noticed something weird in writing code:
Calling the function HighlightCell--which writes to the cell refreshes the page, while none of the other javascript functions do. This happens even if I add a return false; line to the function and call it from button with _onclick ="HighlightCell(); return false;"
REDUX of "Noticed something weird in writing code":
Managed to call Highlight cell without refresh by using:
$(document).ready(function () {
$('#chosen').click(HighlightCell);
});
But still no writing takes place

Google picker make a copy when uploading

I have replicated the google file picker in a web app.
My question is how would I tell the google picker to make a copy of the file when uploading it to google drive ?
Any help would be much appreciated.
I realised that google picker could not do what I needed so Google App Script to the rescue.
Firstly you need to create a new google spreadsheet
Under "Tools->Script Editor" add the following code
Thought trial an error I came up with the following.
function copyFiles() {
var dApp = DriveApp; // Get the drive app
var folderIter = dApp.getFoldersByName('parentFolder'); //Get folder my id
var folder = folderIter.next(); // Get the first folder
var fileIter = folder.getFiles(); // File iterator
var storageFolder = folder.getFoldersByName('childFolder').next(); // Get target folder
var subFolderIter = storageFolder.getFiles(); // sub folder File iterator
while(fileIter.hasNext()) {
var file = fileIter.next(); // Get the current File
var fileName = file.getName();
// Check if the current file exists in a coped folder
// If false make a copy else do noting
// This check prevents duplicate, Becasue makeCopy generates uniques ID everytime
if(!storageFolder.getFilesByName(fileName).hasNext()) {
//Logger.log('Files does NOT exists');
file.makeCopy(storageFolder);
} else {
//Logger.log('Files does exists');
}
}
}
Hope this helps anyone who might need.
Note: You will need to set up triggers for the script to run when required

Google Apps Scripts - Extract data from gmail into a spreadsheet

this is the first script i try to write from scratch. It's been no good up to now so i'm going to ask for some help.
Case: I recieve e-commerce confirmation emails from e-commerce sites no reply email address. In the email's body they send email address from buyers. I want to send an automated mail to the body's email address.
How i plan to do this (any suggetions to eliminate steps will be thanked).
Use a rule to tag incoming emails with a unique tag.
Use that tag to identify emails in gmail with a script, go one by one and extract the info i need. Use regex with the emails body content to extract the email address i need to send the automated emails. Plan is to get: subject, date, email from body.
Write all that info to a spreadsheet.
Get rid of unique tag info to prevent duplicate runs.
Then use form mule addon to send emails from the spreadsheet.
So far, i've dealt with steps 1 (easy), and been stuggling with steps 2 and 3 (im not a coder, i can read, undestrand and hack. writing from scratch is a completely different thing). Ive dealt with 4 before i think this is the best way to deal with it.
With the script i extract info to the spreadsheet, with the addon i use the info from the spreadsheet to send emails.
This is the code ive written so far. I've left the regex part for later cause i cant even write anything into the spreadsheet yet. once i get that working, ill start working in the regex and "remove the label" aspects of the script.
function myFunction() {
function getemails() {
var label = GmailApp.getUserLabelByName("Main tag/subtag");
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
var messages=threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var message=messages[j];
var subject=message.getSubject();
tosp(message);
}
}
}
function tosp(message){
var body=message.getBody()
var date=message.getDate();
var subject=message.getSubject();
var id= "my spreasheet id";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getActiveSheet();
sheet.appendRow(subject,date,body);
}
}
Any help would be appreciated.
Thanks
Sebastian
Following is the code I wrote and tested that performs the steps 2, 3 and 4 mentioned by you perfectly well.
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
var label = GmailApp.getUserLabelByName("MyLabel");
var threads = label.getThreads();
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var msg = messages[j].getBody();
var sub = messages[j].getSubject();
var dat = messages[j].getDate();
ss.appendRow([msg, sub, dat])
}
threads[i].removeLabel(label);
}
}
One of the faults in your code was that the appendRow function accepts an array of elements specified within [ ] brackets.
Depending on where you're attaching this script, your line of code:
var ss = SpreadsheetApp.openById(id);
is not necessary if the script is being written in the script editor of the Spreadsheet where you want these emails to be logged. However, if there are multiple sheets in that spreadsheet, you can replace my line
var ss = SpreadsheetApp.getActiveSheet();
by
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
Another suggestion is that the current code will give you messages in HTML format. Hence, if you want to get the message in plain text as you see it, use:
var msg = messages[i].getPlainBody();
Now you can write another function for regex and pass the message msg to that. Hope this helps!
I made a ready-to-use script, explaining how to use it (from the start) as well, for those who need more assistance.
It's on gmail-to-google-sheets-script repository. Just read the content and follow the instructions.
How to use
Create a new Google Sheet
Access menu Tools > Script Editor
Copy the content from gmailt-to-sheets.gs to editor, replacing the sample code there
Replace the value on SEARCH_QUERY to your real query (Do your search on gmail first, copy and paste the search terms there)
Select saveEmails on menu (near "run" and "debug" buttons)
Click on "Run" button
It will ask for authorization at first run, proceed accepting it (it's your Gmail account authorizing your Google Script account)
After run, the results will be applied to you sheet
Changing fields
If you want to save different message attributes, take a look at gmail-message class and change your script file the code below comments with a ✏️ (pencil).

Categories

Resources