Google sheets API read in Visual Basic - visual-studio-2019

I am using Visual Basic to receive data from a Google sheet column using a key created in Credentials. Initially it works fine with the first sheet ID I used but I keep on getting "permission denied" if I use other ID's. Does anybody have a hint of what could cause the error?
The code creating the string used for calling the sheet looks like this
Dim sheetURL As String = "https://sheets.googleapis.com/v4/spreadsheets/" & GoogleID & "/values/" & SheetID & "!" & ColumnID & ":" & ColumnID & "?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

Based on your issue, you can try to refer to this link for some possible fixes on your case: "PERMISSION_DENIED" on Google Spreadsheet REST API v4

Case solved as it was related to Sharing properties of the individual sheets. A public link will not work with VB even though it is readable in a browser unless sharing properties are set to "Anyone on the Internet with this link can edit"

Related

Pygsheet keeps sharing new worksheet IDs with same name

I'm trying to use Python to maintain a single report tied to a "title" and share then with specific people. In my code, I try to open my existing sheet report. If it fails in opening I create a new one.
My problem is, this code keeps getting a new ID everytime I do a 'x = client.open(title)', I get a new 'x.id' every time. I debugged and made sure that it was opening and not creating, but still keeps getting a new ID.
This makes it so that multiple versions of this sheet exist since I do a 'x.share' and they all have the same name and appear to have the same history. But looks different with every share. Every share appears to have their own versino because of this unique ID. Edits on previous shares does not apply to the latest share. What can I do here?
#########################
## Open/Create GSheet ###
#########################
client = pygsheets.authorize(service_account_file=credsfile)
try:
gsheet = client.open(title)
except:
gsheet = client.create(title)
gsheet = client.open(title)
gsheet.share('john.doe#gmail.com', role='writer')
To test this, run code above and share it to yourself. Edit the first sheet and run the code again. Open that share. It won't have the previous edits you did, but history will show them.
I believe your goal and your current situation as follows.
You want to check the existing Spreadsheet using the Spreadsheet title.
When the Spreadsheet is existing, you want to open the existing Spreadsheet.
When the Spreadsheet is not existing, you want to create new Spreadsheet and open it.
You want to achieve this using pygsheets for python.
You have already been able to use pygsheets.
Modification points:
From client = pygsheets.authorize(service_account_file=credsfile), I confirmed that you are using pygsheets with the service account. In this case, when I consider this and My problem is, this code keeps getting a new ID everytime I do a 'x = client.open(title)', I get a new 'x.id' every time. I debugged and made sure that it was opening and not creating, but still keeps getting a new ID.. Spreadsheet of the value of title of gsheet = client.open(title) might be not existing in the Drive of the service account. If my understanding is correct, this might be the reason of your issue.
The Google Drive of the service account is different from the Google Drive of your Google account. When the Spreadsheet of title of gsheet = client.open(title) is existing in your Google Drive and it tries to search the Spreadsheet using the service account, the service account cannot find the Spreadsheet. In your script, by this, new Spreadsheet is created. In this case, when the Spreadsheet is shared with the email of service account, the service account can find it. I'm worry that this situation might be the reason of your issue.
And, I thought that in order to check whether the Spreadsheet is existing, Drive API Wrapper of pygsheets can be used. In this case, try - except is not required to be used.
It seems that open medhod also uses the files.list method of Drive API. Ref
When above points are reflected to your script, it becomes as follows.
Modified script:
title = '###' # Spreadsheet title.
yourEmail = '###' # Your email address.
userEmail = '###' # User's email address.
client = pygsheets.authorize(service_account_file=credsfile)
try:
gsheet = client.open(title)
except:
gsheet = client.create(title)
gsheet.share(yourEmail, role='writer')
gsheet.share(userEmail, role='writer')
or
title = '###' # Spreadsheet title.
yourEmail = '###' # Your email address.
userEmail = '###' # User's email address.
client = pygsheets.authorize(service_account_file=credsfile)
res = client.drive.list(q="name='" + title + "'")
if res == []:
gsheet = client.create(title)
gsheet.share(yourEmail, role='writer')
gsheet.share(userEmail, role='writer')
else:
gsheet = client.open(title)
By sharing the created Spreadsheet by the service account with your Google account, you can see the created Spreadsheet at "Shared with me".
Note:
When you want to open the Spreadsheet existing in your Google Drive, at first, please share the Spreadsheet with the email of the service account. By this, in your script and above modified script, the Spreadsheet is opened and new Spreadsheet is not created.
Reference:
list(**kwargs) of Drive API Wrapper

How to get a note or comment

I have an Excel containing cell comments/notes, I've uploaded it to Google Drive, and converted it into a Google Spreadsheet. How may I retrieve the comments for cell A1?
The API doesn't describe how to get a note or comment from a cell.
The Google Apps Spreadsheet API only provides programmatic access to spreadsheet data. You cannot access comments using the API.
You can get the Notes for a cell or range of cells using Google Apps Script. See the Class Range documentation for these methods:
getNote() - Returns the note associated with the given cell.
getNotes() - Returns the notes associated with the cells in the range.
There are open issues related to this functionality, mainly concerning comments (the "other" type of note). See Issue 1818 and Issue 2566
In a comment on your question, SGC asks if you've looked at developers.google.com/drive/v2/reference/comments/get and developers.google.com/drive/v2/reference/comments/list; these are FILE level comments, not the comments attached to a spreadsheet cell.
1 - Add the following custom function to your spreadsheet (through the Tools -> Script Editor menu)
function getNote(cell) {
return SpreadsheetApp.getActiveSheet().getRange(cell).getComment()
}
2 - on your spreadsheet use the following formula to get contents
=getNote(cell("address",a1))
or
=getNote(cell("address",E9),GoogleClock())
if your comments are not static.
Bit of a muck around but it's possible to download the googlesheet as a .xlsx file, which, with varying degrees of success, converts the comments into Excel comments.
Uploading this xslx file converts the comments to notes!
There is a difference between Note and Comment.
getNote is working fine. You create a Note by using the cell menu "insert Note" , and not "insert Comment"
Very sad, but there is no getComment. The example of Oren did not work for me either.

Query Google Spreadsheet with URL Parameters

I have recently opened a new spreadsheet:
https://docs.google.com/spreadsheets/d/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo/pubhtml
I want to find 'title' which url=http://www.ettoday.net/news/20140327/339912.htm
I read google api doc and tried this:
spreadsheets.google.com/feeds/list/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo/0/private/full?sq=url%3D%27http%3A%2F%2Fwww.peoplenews.tw%2Fnews%2F29813808-befa-45b6-9123-8dcef851af45%27
but it didn't work.
I also tried:
docs.google.com/spreadsheets/d/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo/gviz/tq?tq=SELECT%20topic20WHERE%20url%3D'http%3A%2F%2Fwww.peoplenews.tw%2Fnews%2F29813808-befa-45b6-9123-8dcef851af45'
but it didn't work either.
are there any way to do this kind of query?
I know this is old, but I just worked through a similar issue.
Querying a google spreadsheet via URL params requires the use of their data visualization query language (nearly identical to SQL).
Your query must be encoded then added as a parameter to the end of your URL (google provides an encoder with its document on this here).
Using your example url (notice no "/pubhtml"):
https://docs.google.com/spreadsheets/d/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo
To query this sheet, you must append this URL with /gviz/tq?tq=YOUR_ENCODED_QUERY_STRING
YOUR_ENCODED_QUERY_STRINGfor your case would be:
SELECT * where B contains "ettoday"
Note #1 - I used "B" and not "url". This is because you must query based on the spreadsheet cell identifier (A-Z), not the label/contents.
Note #2 - I could not get it to work when I queried with a fully quallified URL, so I used contains instead.
After encoding that string we get:
SELECT%20*%20where%20B%20contains%20%22ettoday%22
Slap that onto your URL (with /gviz/tq?tq=) and you have:
https://docs.google.com/spreadsheets/d/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo/gviz/tq?tq=SELECT%20*%20where%20B%20contains%20%22ettoday%22
Which works for me :)
The spreadsheets.google.com query is the old method of accessing the google spreadsheets.
The new method involves the docs.google.com query.
Here is a working one:
https://docs.google.com/spreadsheets/d/1chFDkz5Fqus1ODgtdEGNt4Mq2nxnkKnuqbEB4LaZF6o/gviz/tq
That was retrieved from:
query to new google spreadsheets
Some of the old query parameters still work, such as "?range=A1:B", however not all of them do. Unfortunately, I have not yet found a good reference for the new API. Google claims that all the features of V1 and v2 of the api are available in this new one, but it sure doesn't feel like it to me.
Note: the old query method still works with the old version of google spreadsheets and you should use it if you haven't converted the sheet you are using. The new method is just for sheets that have been converted.
Note2: Google forms no longer seems to work consistently with the old spreadsheets, so you will probably be forced to delete the old sheet and have the form generate a new one which will be the new version and require the new url to query it.
try this
https://docs.google.com/spreadsheets/u/0/d/1yapaaaFn0mtJF0CMiIil4Y1uYCqS97jIWL4iBZMPAKo/gviz/tq?tqx=out:html&tq=SELECT+*+where+B+contains+"http://www.ettoday.net/news/20140327/339912.htm"
tq=SELECT+*+where+B+contains+"http://www.ettoday.net/news/20140327/339912.htm"
SELECT * where B contains "http://www.ettoday.net/news/20140327/339912.htm"
More info here -> 在這裡閱讀更多

How can I format a Google Sheets spreadsheet cell with the API?

My application generates a table of data and creates a new spreadsheet document in a user's Google Drive. How can I add formatting (color, font-weight, width, etc.) to individual cells? I can't seem to find any documentation, much less how I could implement this through the google-api-ruby-client.
Most of my findings date back to Google API mailing lists that state it isn't supported.
However, I found that another application accomplishes my desired result. An example of "Smartsheet" exporting a document to Google Drive:
From Smartsheet.com:
And the resulting sheet in my Google Drive:
(Feb 2017) As of Google I/O 2016, developers no longer need to export to Excel nor create a new Sheet w/the desired formatting, so the other answers are now dated. You can now format cells using the Google Sheets API. Here's a short Python example that bolds the 1st row (assuming the file ID is SHEET_ID and SHEETS is the API service endpoint):
DATA = {'requests': [
{'repeatCell': {
'range': {'endRowIndex': 1},
'cell': {'userEnteredFormat': {'textFormat': {'bold': True}}},
'fields': 'userEnteredFormat.textFormat.bold',
}}
]}
SHEETS.spreadsheets().batchUpdate(
spreadsheetId=SHEET_ID, body=DATA).execute()
I also made a developer video on this subject if that helps (see below). BTW, you can do the same in Ruby (see its API quickstart sample) or any other language supported by the Google APIs Client Libraries.
The Sheets API provides features not available in older releases, namely giving developers programmatic access to a Sheet as if you were using the user interface (frozen rows, cell formatting[!], resizing rows/columns, adding pivot tables, creating charts, etc.). If you're new to the API, I've created a few videos with somewhat more "real-world" examples:
Migrating SQL data to a Sheet plus code deep dive post
Formatting text using the Sheets API plus code deep dive post
Generating slides from spreadsheet data plus code deep dive post
To see what else you can do with Google Sheets via its REST API or Google Apps Script, check out my other videos. As you can tell, the Sheets API is primarily for document-oriented functionality as described above, but to perform file-level access such as import/export, copy, move, rename, etc., use the Google Drive API instead.
Smartsheet utilizes the ability of the Google API to import an Excel file. The code is roughly along these lines:
DocsService client = new DocsService(<YOUR APP NAME>);
client.setOAuthCredentials(<OAUTH PARAMETERS>);
DocumentListEntry newEntry = new SpreadsheetEntry();
newEntry.setMediaSource(new MediaByteArraySource(<EXCEL FILE BYTE ARRAY OUTPUT STREAM>, DocumentListEntry.MediaType.XLS.getMimeType()));
newEntry.setTitle(new PlainTextConstruct(<FILE NAME>));
DocumentListEntry insertedEntry = client.insert(new URL("https://docs.google.com/feeds/default/private/full/"), newEntry);
// This is your URL to the new doc
String docUrl = insertedEntry.getDocumentLink().getHref();
We already had the ability to export a Smartsheet to an Excel file with formatting via Apache POI. Adding export to a Google Spreadsheet was quite simple for us to implement and it provided some additional functionality beyond what you could do via the API.
Sorry for the delayed response - just happened across this question.
The APIs only provide access to the data and do not expose any methods to add formatting.
Another option (and the one that ended up using) is to manually create a Google Sheet file, with all of the formatting pre-configured, as a template. Then, instead of creating a new spreadsheet document in the user's Google Drive, copy the template, like so:
var config = require('./config');
var google = require('googleapis');
function createSheetFromTemplate(user, templateFileId, done) {
var oauth2Client = new google.auth.OAuth2(config.google.clientId, config.google.clientSecret);
oauth2Client.setCredentials({
access_token: user.google.token,
refresh_token: user.google.refreshToken,
});
var drive = google.drive({
version: 'v2',
auth: oauth2Client
});
drive.files.copy({
fileId: templateFileId,
resource: {
title: 'New Google Sheet',
parents: [{
id: 'root'
}]
}
}, function(err, response) {
if (err) done(err)
initializeSpreadsheet(response.id, user, done);
});
}
In that code, templateFileId is the file id of your shared template. You can get this fileId from your shared template file in any number of ways, but the quick-and-dirty way is just to copy-and-paste it out of the URL when you share it.
For instance, if the sharing URL is:
https://docs.google.com/spreadsheets/d/1234567890abcdefghijklmnop/edit?usp=sharing
Then the file id is 1234567890abcdefghijklmnop
In my case there is nothing private in the template itself, so I just shared it with 'anyone with the link' configured for 'can view', as described here:
https://support.google.com/drive/answer/2494886
If you need to keep the contents of the template file private, then you'll need to find some way to ensure that the account specified by config.google.clientId has access to it.
Hope that helps!
If, like me, uploading a pre-formatted Excel sheet isn't sufficient, then Google Apps Script looks like it might be the way to go. The Range class specifically lets you manipulate at least some of the formatting you were asking about.
https://developers.google.com/apps-script/reference/spreadsheet/range
setFontColor() and setFontWeight() are there, but I don't know of anything for cell width yet.
Importantly, I have also not yet figured out how to bind a Google Apps Script to the sheet that I'm creating using the Google Drive API SDK (Node/Javascript in my case, Ruby in yours).
https://developers.google.com/apps-script/guides/bound
It's been a while since your question, so I'm betting you've already solved it some other way. I'm also not necessarily suggesting porting everything in your app over to Google Apps Script (although I'm seriously considering it myself...), but if you or some other reader figures out how to bind a Google App Script to a spreadsheet with the google-api-ruby-client, you might be good-to-go.

Can't parse new google urls - HTTP_REFERER doesn't contain parameters anymore

It seems a little odd to my, but although everybody knows about the new google search urls (see Google using # instead of search? in URL. Why?) no one has a problem with the HTTP_REFERER.
I'm using the referrer to parse the google string for the searchquery (&q= ) but as this is all in a hash-tag it wont be sent to the server and all i get is "http://www.google.de/".
So do you know a way of getting the query the user searched for, befor landing on my site?
Due to late-2011 Google security changes, this is no longer possible when the search was performed by a signed-in Google user. See:
http://googleblog.blogspot.com/2011/10/making-search-more-secure.html
http://analytics.blogspot.com/2011/10/making-search-more-secure-accessing.html
Since there are multiple q's in the query string you have to match the "q" parameter globally and take the last one:
/[?|&|#]q=([^&|^#]+)/ig
Get rid of "site:" searches (there are others, but I haven't done them)
/[\+|?|&]?site:([^&|^#])+/g, '');
Then parse the results.
/[\w^'\(\)\{\}]+|"[^"]+"/g
This has been working well for me.

Resources