Posting this here because I have found no note or solution elsewhere on the web.
I am currently experiencing a discrepancy between search results when using the drive search toolbar and the DriveApp.searchFiles() functionality of apps scripts as follows.
The drive search bar always returns complete results for a given query [looking at all text within a document and in the title], but DriveApp.searchFiles() does not. Certain files are missing/not returned.
Upon finding a given file that is returned from the drive search bar ONLY (one that was not being returned by the DriveApp search) and opening it, it then starts appearing/being returned by DriveApp.searchFiles().
This issue further seems to be a user-specific one. The script we are developing is used by multiple users and new users (ones that are added to an extant file system and then given our tool) experience this issue for a majority of files. After which, when they open a given 'missing' file, it begins appearing in the search results once more.
For reference, my code is as follows:
var targetParam = 'title contains "'+target+'" or fullText contains "'+target+'"';
var searchResults = DriveApp.searchFiles(targetParam);
In all instances of this issue, the drive search bar returns a complete list and opening a given file 'fixes' its issue. Given the scale of what we are trying to do it is not a possibility to have every user open every file.
For clarification, these files are within a large file system in either team drives or traditional G suite. Users are given access by being added to the highest level file, to the team drive, or by being added to a user group that has access to the file system already. All users are within our domain.
Is this a known discrepancy? Is there something that I may be doing wrong in my search query to cause this? I am interested in any potential solutions or ideas.
Just to mention one of the things that are causing this, from Use Groups to share content (emphasis mine)
If you later add new members to the group, they'll be able to access the document only via the document's URL. To make the document appear in the Shared with Me view of a new member's Google Drive, you must reshare the document with the group or share the document with the new member individually.
A possible solution to this (I don't have a domain to test on) is to enable and then use the Drive "advanced service" and not the DriveApp implementation. If one reviews the Drive REST API for Files#list, one will note that the default corpus used when querying for files is files that the user has accessed. This corpus includes any file the user has created themselves (by UI or by script).
Thus, modifying the search corpora could be the answer. There's a lot of extra stuff that has to be added if you want to search Team Drive items, so I'll leave that to the reader.
function searchDomain(query) {
const listOptions = {
q: query,
corpora: 'domain',
};
const results = [];
do {
var search = Drive.Files.list(listOptions);
listOptions.pageToken = search.nextPageToken;
if (search.items)
Array.prototype.push.apply(results, search.items);
else
console.log({message: "No results for search", search: query, options: listOptions});
} while (listOptions.pageToken);
return results;
}
Given that you mention DriveApp.searchFiles you already know the general structure for the query string, but for anyone who is finding this, you will want to review the documentation on its format here
Related
I would like to allow users to use my spreadsheet but not copy it as it contains intellectual property. I tried going to sharing settings and disabling:
Editors can change permissions and share
Viewers and commenters can see the option to download, print, and copy
But the sheet can still be copied. Ideas?
Unfortunately, it is not possible to disable copy / download for editors.
You can only do that for commenters and viewers.
As a workaround, I would advice you to keep your sensitive information into one master file and then importrange or copy via a script the shareable information into another file. So even if they copy or download the latter your sensitive information won't be copied / downloaded.
Related questions:
How to disable copy/ download access for editors in google sheets
Prevent editors from downloading the file
Disable download & Copy to Option in Google Spreadsheet
I think the simplest solution would be to copy and paste from the master file the range of values you want to share with the other document. In this scenario the editors of the other document won't have access to neither the code nor the full data of the master file since the latter won't be shared with them.
The copy and paste part can be done automatically via a script and a trigger mechanism to update the data automatically so you won't have to do anything manually and the master file won't be exposed to any user.
There isn't any sure way to hide your data. Once something is published on the internet, you should consider it saved on many devices all over the world. Consider some ways to get hidden spreadsheet data
Attack scenarios:
By far the easiest way is CTRLC and CTRLV(Copy and Paste)
Editor menu options: File->Copy and File->Export
Once your file id is visible, any editor or even viewer with access to the file can easily copy the file itself through
Url manipulation: Adding /copy at the end instead of /edit
google-drive-api: File:get and File:copy
google-sheets-api: Useful to directly get data as json
google-vizualization-api: Can get data as html,csv or json(google query). See endpoints
Screenshot and use OCR(Optical character recognition)
View source code in the browser and directly copy the table
web-scraping Simulate browser using selenium
Hiding data:
Data may be hidden from naive users. Data cannot be hidden from users, who know the basics of how the web works.
Add ?rm=minimal to url, when sharing the sheets file. This hides all menu options.See here
Frame the edior in a iframe in your own website and use css to hide the top portion of the web page.
Hiding Logic:
You may still be able to hide logic of your code.
IMPORTRANGE: This is a very basic and easy way to hide your logic. But there are limitations and any editor can access any part of your master spreadsheet.
You can implement a IMPORTRANGE like logic using custom functions and webapps. This gives more control over the connector and secures your master spreadsheet much better than IMPORTRANGE. Here,
Two web apps are created, each associated with a spreadsheet(Master and client).
You use two KEYs to communicate between them. One for access and other for encryption.
Once access is verified, the data from master spreadsheet is encrypted and sent back to the custom function. Simultaneously the encryption key is posted to the client webapp.
The key here is the Master/Server webapp posts the encryption key only to the published client web app link. So, no other sheet or anything else can intercept the key or decrypt the data. Furthermore, a random key is generated for each access.
Another option is to let go off the spreadsheet completely and use a single webapp to show the data. This hides the logic in server scripts and linked spreadsheets.
Comment thoughts:
Create a script onOpen to kill sheets if the file is wrong?
onOpen cannot post data anywhere without the new copy owner permission. It's not possible to kill sheets. But data can be erased.
/**
* Deletes all sheets on the copy, if a copy is made
*/
const onOpen = () => {
const ss = SpreadsheetApp.getActive();
const id = ss.getId();
const sheets = ss.getSheets();
ss.insertSheet(sheets.length);//insert a blank sheet at the end
if (id !== '###Original ID###') sheets.forEach(s => ss.deleteSheet(s));//will fail at the last sheet(doesn't matter)
};
But editor can modify the original script before making a copy. And a revision of the original spreadsheet will still be available. The new owner can revert to the original version, use api endpoints mentioned above to get the data. Also mobile apps don't support onOpen. New owners can simply use mobile versions to access data.
Use formula web-app to notify file owner, ?
Possible, but data is already copied and there's no specific information that can be used to accurately identify the new owner. You maybe able to get locale information though.
I am building an application that will have many users, each of whom will have many Google documents. Each doc will have a custom menu and that custom menu will invoke a library script. I may need or want to change the coding in that library script from time to time.
As changes to a library script must be "saved" as a new version in order for the changed version to be passed on to client scripts (in my case, the scripts bound to Google Docs), I need a way that users can "batch" update the version number in their docs' bound script appsscript.json
file.
I have researched this issue and there seems to be two general alternatives: set the client scripts' library mode to "Developmental" or use an add-on.
The problem with the former is that it won't work unless the users are all granted edit mode access to the library script (which seems particularly a bad idea as the users may well not even be known to me).
The problem with the later is essentially complication and cost. If I make the add-on private, it only works for users in the same domain which means I have to create a G-Suite domain (and pay at least (as of this writing) $72 per year per user—a non-starter for this project).
If I make the add-on public, in addition to the complication, I have to sign up to the Google Cloud Platform and the costs for that require one to navigate a veritable maze of choices and alternatives such that at this point, I really have no idea what the cost per service or user would be.
Below I present some "mock-up" code that should at least indicate the direction I am trying to go.
function upDate() {
var version = 23
var scripts = "https://script.google.com/u/0/home"
//while (scripts.hasNext()) {
//var script = files.next();
//Note: All of the script's have the same name as they commence life bound to a template, which template is duplicated to create the rest of the user's docs
if( scriptName = ScriptName){
//set.dependencies.enabledAdvancedServices[].version
}
}
I don't even know if it's possible to step through bound scripts the way one step's through files in a Google Drive, so that is the first question. Then, the second question is whether, assuming you can step through the scripts one by one, you can change a manifest value—in this case, the version number.
One cannot step through container-bound scripts as they are (no longer) located in one's Google Drive. Moreover, despite Google's documentation about using a "stable" value in the version section of the manifest, that documentation appears erroneous. Finally, one cannot programmatically edit standalone scripts.
However, there is a workaround. What I ended up doing was writing a script that steps through all of the involved Google Docs and copies them to a blank template (i.e., in effect, duplicates them all). That blank template has the bound script installed in it with the new version number of the library. Then, delete original docs (via the same script) and voilà, batch update to all of the target docs is accomplished. (One drawback of this is: if Google Doc revision history is important to you, be advised this gambit jettisons that (unless you keep the original versions).
I'm trying to figure out a way to search in a google csv (list of names) if a name is present.
Is it possible in uipath?
According to my research, it may fall into the web recorder and the use the module to read csv?
Here is what I tried again:
In the main screen, I created a sequence.
Open a browser to a url like this
"https://docs.google.com/spreadsheets/d/xyzz/edit#gid=0"
Added a "Navigate to" the above URL again.
Then selected "Data Scraping".
Click on the first row of google sheet.
Then to create a pattern I clicked on next row. It couldn't find a pattern.
So I'm stuck on the final 6th position. I tried downloading and working on the csv as an alternative. But I would rather want it on the google sheet in the browser.
Am I going in the right direction?
Another way is:
to download Google GSuite set of activities from Google GSuite.
Place it under Packages folder in your UiPath installation folder and load it via Manage Packages option in Design Mode.
Use GSuite Application Scope (you need to fill your ClientID and ClientSecret for your account)
Use activity Find Files and Folders to search for the file that you want by name. You will get the file ID (in your case the SpreadSheetID) as output
Use a Read Range activity placing the output from step 3 to get the contents of spreadsheet as DataTable
Use your pattern to search through DataTable for the desired result.
Activities are shown as per below (Highlighted are the ones to use)-(Notification on the second Image is due to the fact that ClientID and ClientSecret are mandatory and i left them empty):
Hope you will find these information useful
So I hope the question makes sense. I am relatively new to GoogleAppScripts. I have a client that has some Scripts that I am trying to interoperate and modify. In order to do so I need to find each document that is associated by 'id'. But when I search for the id in the search bar of drive,I just get the script file that I am working on because the id number is in the text. I need to find the particular sheets doc that is associated with a particular ID, plain n simple. There has to be an easy way to do this aside from writing a function and outputting the result...
The search bar in Drive doesn't do search by ID, however if you know the ID you can hand-craft the file URL & access it that way — if you have permission to access the file in question. e.g. you could open a Drive file with a URL like https://docs.google.com/{file-type}/d/{file-ID}, where {file-type} is document, spreadsheet, etc, & {file-ID} is the ID you have in the code.
An alternative is to get the names of the files for which you have IDs, write the results to the log (i.e. Logger.log(DriveApp.getFileById("your_file_id").getName());) & then search for them by name in the Drive UI.
In Google Drive one can search files 'Not owned by me'.
I need access to this from Google Apps Script.
I already tried DocsList.find("Not 'me' in owner"); which appears to be the way to do it in the drive API, but without success (in fact that gets me files with me as owner.) I also replaced me with my email address, with and without quotes, but again without success.
Does anyone know if this is possible (other than by iterating all files and checking getOwner().getEmail() manually, which would take far too long given the enormous amount of files owned by this specific user.)
I think the updated answer as of now is to use DriveApp.searchFiles(params) (https://developers.google.com/apps-script/reference/drive/drive-app#searchFiles(String) ).
Code is something like:
// Log the name of every file in the user's Drive that shared with me
var files = DriveApp.searchFiles('sharedWithMe');
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
}
This function will return an array of all files shared with you. It uses the Advanced Drive Service, which must be enabled before use.
/**
* Get array of files on user's Google Drive that have been shared with them.
* From https://stackoverflow.com/a/15947340/1677912
*
* #returns {Array} Array of file resources
* (see https://developers.google.com/drive/v2/reference/files#resource)
*/
function getSharedWithMe() {
var optionalArgs = {q:"sharedWithMe=true"};
var sharedFiles = Drive.Files.list(optionalArgs);
debugger; // pause in debugger
return sharedFiles.items;
}
You can do the same thing without code, by using the Google Drive SDK "Explorer".
See this previous answer that used this technique to get a list of trashed files.
You'll find the Files List API Explorer at the bottom of the Google Drive SDK documentation page for Files:list. For information about search terms, see Search for files. For our purposes, we'll just use sharedWithMe.
If you leave "fields" blank, you'll get everything that's known about the shared files. You can expand and collapse the results using hard-to-see minus sign tags. But it's helpful to limit the output. I used items(id,selfLink,owners/displayName). Here's how that looks: