Google script to Save open Sheet to file - google-apps-script

I'm in the process of learning about Google Scripts and Javascripts, I love coding solutions but need to know a lot more so apologies for being a little slow.
I know how to use script in google docs but I am not sure yet on how to construct many things, I am learning from examples and trying to understand from what I find.
I have a scenario where I have a google sheet that I would like to use as a template so a user can enter in data in all the fields then click a button to save the whole sheet as a file (the same as going File > Save As) but use an ID number in a field as the name of the document when saving and place these in a folder within the same directory as the master template. After clicking the save button the sheet would need to reset to original ready for another entry.
The user can open up the saved document and make changes if required.
I haven't been able to find examples I can quite understand to make them work so any assistance would be great, even pointers for resources that would make it easier for me to learn
Thanks.

First of all, create a folder in your drive named MyTargetFolder. Put your template spreadsheet in, fill "ID" to first row as a filed, any number as value to second row.
all script you need are below :
// create a custom menu to add Save feature.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Feature')
.addItem('Save Spreadsheet', 'saveSpreadSheet')
.addToUi();
}
Then implement save feature.
function saveSpreadSheet() {
var thisSpreadSheet = SpreadsheetApp.getActive();
/*
What first row and second row look like :
-----
| ID |
-----
| 123 |
-----
*/
var id = thisSpreadSheet.getActiveSheet().getRange(2, 1, 1, 1).getValue();
var folders = DriveApp.getFolders();
var destFolder = '';
while (folders.hasNext()) {
var folder = folders.next();
if ( folder.getName() == 'MyTargetFolder' ) {
destFolder = DriveApp.getFolderById(folder.getId());
}
}
DriveApp.getFileById(thisSpreadSheet.getId()).makeCopy(id, destFolder);
// recover the template
thisSpreadSheet.getActiveSheet().getRange(2, 1, 1, 1).setValue(' ');
SpreadsheetApp
.getUi()
.alert('Check your Drive to make sure file have been saved');
}
All Google app script API that about spreadsheet are well documented here.
And API about Drive.

Related

Copy data from specific cell into different sheet with different formatting in a different folder

From inside one google sheet, I want to run a script (via script-attached button) that copies another,different, sheet into another, destination folder while naming the new file according to a cell value in the first sheet. Can anyone point me in the right direction?
Here's what i have so far:
function onOpen(e) {
var jobTitle = SpreadsheetApp.getActiveSpreadsheet().getName();
SpreadsheetApp.getActiveSpreadsheet().getRange("B3").setValue(jobTitle);
}
function CreateManFile8() {
var copyMan = DriveApp.getFileById("Source ID");
var toFolder = DriveApp.getFolderById("Destination ID");
copyMan.makeCopy(toFolder);
}
The first function is fine as it allows me to copy the first spreadsheet template, name it and then, onOpen, the file name goes into an appropriate cell of the input sheet from which it populates throughout the spreadsheet via standard sheets reference formulas and such.
The second function just copies the "Man." template (from inside the first "Sales" template) and puts it into the appropriate folder without changing the name.
I need a way to name the Man. template according to the value in B3 (or any specified cell) from inside the Sales SpreadSheet template. I have the script attached to a button inside the Sales template but it just copies the second template and names it "Source ID";not the value of B3.
ISSUE BACKGROUND: (FOR THOSE INTERESTED)
Each of the projects I manage at work entail Sales processes contained in a "Sales Spreadsheet" Template composed of several inter-linked sheets and Management processes contained in a "Management Spreadsheet" Template composed of several other inter-linked (with standard formulas) sheets. Eventually, both of these Spreadsheet Templates are copied and used for every new project.
First, each Sales prospect engages sales processes that cause the Sales spreadsheet template to be copied, renamed and iteratively populated with relevant customer and sales data throughout the sales process. Then, at some point, contracts are signed which engage management processes and, consequently, the "Management Spreadsheet" Template is copied, named, and utilized for the project as well.
The idea is to have the "Man. Template" get copied from within the 'Sales Template" after the sales template has been manually named and populated with information collected during the sales process.
Most of the data collected, analyzed, and reported during the management phase of any project is different from the data needed to negotiate the sales processes but, the little bit that is redundant needs to be Programmatically transposed from the Sales Template to the Management Template for each project.
And So, I come to YOU...the stack overflow community for guidance. Any and all serious, service-oriented people offering help will be truly appreciated.
I know most of you are smarter than me. It does not help to be reminded. So, anyone Who actually wants to help a dude out just because they love coding and want to share it, I cant wait to hear from you.
If I understood correctly, you want a function that makes a copy of the spreadsheet in an specified folder and with the value of the B3 cell as name.
You can try this modification of your function:
function CreateManFile8() {
var copyMan = DriveApp.getFileById("spreadsheet Id").getId();
var toFolder = DriveApp.getFolderById("folder Id");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var sheetName = sheet.getRange('B3').getDisplayValue();
DriveApp.getFileById(copyMan).makeCopy(sheetName, toFolder);
}
You can check the documentation of makeCopy and getDisplayValue for more information.
This just a sample, you must modify it for your purpose, this will copy a file from any folder to other folder with new name:
function CreateFile8() {
//This assumes the folders are unique, so I don't use ID
var folders=DriveApp.getFoldersByName('Sistem Folder'); //myfolder = 'my drive' > 'sistem folder'
if (folders.hasNext())
{
var mySrcFolder = folders.next();
var Destfolders = mySrcFolder.getFoldersByName('Test'); //myDestfolder = 'my drive' > 'sistem folder' > 'Test'
var files=mySrcFolder.getFilesByName('Jojo'); //file jojo will be copied (only if not exist), and Jojo is as template
if (files.hasNext() && Destfolders.hasNext())
{
var DestFolder = Destfolders.next();
var myFile = files.next();
var Destfiles=DestFolder.getFilesByName('Jobe'); //file jojo will be copied (only if not exist in dest), and Jojo is as template
if (Destfiles.hasNext()==false)
myFile.makeCopy('Jobe', DestFolder); //And jobe is extracted from your sheet, I don't adopt here to extract from your sheet
}
}
}

Google Forms Rename "File upload" File to "Question - Submitter"

I am using Google Forms to collect images from team members and I want to ensure that each file that is uploaded to Google Forms and saved in Google Drive has the same naming convention.
There are five File upload questions that team members are asked to upload their images to. The files are placed into Google Drive folders with random file names followed by - firstName lastName. On an onFormSubmit trigger I would like to change the names of the user-provided files to fileUploadQuestionName - firstName lastName.
I am pretty new to Google Apps Script and I have no idea how to go about doing this. Any help would be greatly appreciated!
You can change the name of the uploaded file on each form submit by the following process
retrieve the last form response onFormSubmit with form.getResponses()[LAST FORM SUBMISSION]
retrieve the ID of the uploaded file with getItemResponses()[QUESTION NUMBER].getResponse()
open the file ID with DriveApp and change its name as desired
function myFunction() {
var form=FormApp.getActiveForm();
// returns the total number of form submissions
var length=form.getResponses().length;
//replace QUESTION NUMBER through the index of the question prompting the file upload - keep in mind that the first question has the index 0
var id=form.getResponses()[length-1].getItemResponses()[QUESTION NUMBER].getResponse();
//getResponses()[length-1] retrieves the last form response, accounting for the fact that the first index is zero and hte last length-1
//gets the name of the question
var fileUploadQuestionName=form.getResponses()[length-1].getItemResponses()[QUESTION NUMBER].getItem().getTitle();
//accesses the uploaded file
var file=DriveApp.getFileById(id);
name = file.getName();
//changes the file name
var name = fileUploadQuestionName+' - '+name.split(' - ')[1]
file.setName(name);
}
PS: If you want to change a posteriori the names of all the files submitted and not just the last files - you need to loop through all form responses:
for(var i=0;i<length;i++){
var id=form.getResponses()[i].getItemResponses()[QUESTION NUMBER].getResponse();
...
...
}
The easiest way to do this would likely be by either iterating through the specified folder in google drive on a time-based trigger and either checking if they meet your specified condition or moving them to a different folder after they're renamed.
function checkFile()
{
var files = DriveApp.getFolderById('ID of Folder').getFiles();
// you can find this by going to form responses and clicking the link to an attached file and copying the id from the URL
// https://drive.google.com/drive/folders/xxxxxxxxxxxxxxxxxxxxxxxxxxx
var fileUploadQuestionName = 'Test';
while(files.hasNext())
{
var file = files.next();
var name = file.getName();
if(name.indexOf(fileUploadQuestionName) == -1)
{
name = fileUploadQuestionName+' - '+name.split('-')[1]
file.setName(name);
}
}
}
From there you'll need to add a time-based trigger to run every hour or day or minute depending on how critical it is to always find files of the correct name.
I can't find any documentation on accessing the file from within the response item on google's formApp documentation.

Programmatically delete a script

I was wondering if someone could offer me some advice.
I have a master spreadsheet, acting as a template. I have written a script which can be run from the menu (using addToUi command), which makes a copy of template spreadsheet.
The problem is that the script gets copied into the new spreadsheet also which I don't want.
Could anyone suggest a possible way around this please?
I did think a possible way was to get the script to open the copied template and delete the script but not sure if this is possible.
Here is the function which does the copying....
function createCopy() {
var myValue = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("B8").getValue();
var destinationFolder = DriveApp.getFolderById("xxxxxxxxxxxxxxxx");
DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).makeCopy(myValue,destinationFolder);
}
(Cell reference B8 holds the value of what I called the copied spreadsheet).
Rayden, I use a function like that to just copy one sheet to a new spreadsheet and it doesn't drag the script with it. gDrive is the id for the Spreadsheet, tabName the individual sheet you want copied, Filename the name of the copy and destination the destination directory.
//******************************************************************************
//- This function takes a tab and makes it its own file
function tabToSheet(gDrive,tabName,fileName,destination){
var sh = SpreadsheetApp.openById(gDrive);
var ss = sh.getSheetByName(tabName);
//create a new document in the location given
var newSheet = SpreadsheetApp.create("TEMPDELETEME");
//copy the tab from current document to new document
ss.copyTo(newSheet);
var id = newSheet.getId();
newSheet.deleteSheet(newSheet.getSheetByName("Sheet1"));
os = newSheet.getSheets()[0];
os.setName(tabName);
var file = DriveApp.getFileById(id);
var folder = DriveApp.getFolderById(destination);
var finalId = file.makeCopy(fileName, folder).getId();
file.setTrashed(true);
return finalId;
}//*****************************************************************************
The difference is that i'm making a new sheet, then copying the tab rather than copying the entire file. You could add another tab and remove the variables if you want to copy multiple tabs.
I was having trouble implementing J.G.'s approach of moving individual sheets, so the approach I took was to add a conditional in front of the script to only run if the spreadsheet id was equal to the id of the original spreadsheet. My use case was trying to suppress a custom menu on the original workbook from reappearing on the copy, so it worked for that.
var bookId = spreadsheet.getId();
if (bookId === 'original spreadsheet id') {
*Function*
}

Share Google Doc using a Google Script to set an array of emails (in Google Sheets) as editors

I basically am imagining commands that would change the sharing status of sheets it was allowed to edit. For example, I have a master document for a company (a "Roster" for keeping track of where employees are working and which other employees they are working with in that area) and other "Area Sheets" the employees use to keep track of progress. People move around quarterly, so I want to be able to update my Roster and then let the programming update the sharing status of their sheets instead of clicking on every sheet and copy-pasting emails.
As far as I know there is no current possible way to use google products to achieve this. Are there any other ways, barring a New Feature developed by Google?
I don't think I fully understand your requirements, so I'll start be rephrasing what I do understand.
For every employee, generate a list of who they're working with that quarter.
For a certain set of files owned by the employee, make those files editable to the employee's current co-workers.
For point 1, you already have the list built out in Google Sheets, so you can read the contents into arrays for processing. You can use Google Apps Script Spreadsheet Service for this. Example:
var roster = SpreadsheetApp.getActive(); //assuming the script is running within the Roster spreadsheet
var employeesSheet = roster.getSheetByName("Employees"); //assuming sheet name is "Employees"
var employeeEmails = employeesSheet.getRange("B2:B").getValues(); //assuming the emails are in column B with the first row as header
//In this next line I'm going to make a very big simplification.
//I will assume that the coworkers emails are listed as "coworker1#company.com;coworker2#company.com" in the cell.
//This is likely not the case, but you may already have this formatted in a way that works.
//If not, you can merge these values in Google Apps Script, but I'll consider that outside the scope of this question.
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
For point 2, I assume you already have a way of determining which files need to have their access permissions modified and that you have permission to make those modifications. You'll need to use the Drive Service for this part. In my example, I will assume that all relevant files are saved in a folder specific to each employee and that the folder ID is saved in column D.
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
//At this point, you could give direct access to the entire folder,
//or just to the files within the folder, as I will do.
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
Please note that in the above:
This is untested code and meant only to demonstrate how to achieve what I think you're looking for.
No access permissions are being revoked. This would be quite trivial to add, though.
The folder.getFiles() command only gets files that are children of the folder. So, if the folder has child folders, you'll need to traverse through those as well.
You may want to create a custom menu in your Roster spreadsheet to run this script
In the end, including the custom menu, your code could like:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Reset Permissions", functionName: "resetPermissions"});
ss.addMenu("Roster Actions", menuEntries);
}
function resetPermissions() {
var roster = SpreadsheetApp.getActive();
var employeesSheet = roster.getSheetByName("Employees");
var employeeEmails = employeesSheet.getRange("B2:B").getValues();
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
}
For reference, this is how I assumed the example "Employees" sheet in the "Roster" spreadsheet to look:

PDF Template Archiving

I have Created a form that generates a response sheet. I also have created a Doc which is a Template that my responses fill into. From here it was being turned into a PDF and e-mailed to specific recipients. I now need to archive these into specific folders based on a columns answer. I simply first would like to just be able to move or copy them into a specific folder. How is this possible. I have used multiple scripts but just cant see where the disconnect is. Any help would be greatly appreciated. Thank you enter link description here
You could try using some code like this:
function moveFileToFolder() {
var theFolder = DriveApp.getFolderById('your Folder ID');
var theFile = DriveApp.getFileById('Your File ID').makeCopy(theFolder);
var oldFileName = theFile.getName();
var archivedName = oldFileName.slice(5);
Logger.log('archivedName: ' + archivedName);
archivedName = "archive" + archivedName;
theFile.setName(archivedName);
}
To delete the old file without having to send it to the trash:
//This requires the Drive API To be turned on in the Advanced Google Services.
//RESOURCES menu, ADVANCED GOOGLE SERVICES
function deleteFile(idToDLET) {
//idToDLET = 'the File ID';
//This deletes a file without needing to move it to the trash
var rtrnFromDLET = Drive.Files.remove(idToDLET);
}