How can I delete a Google Sheets created by a service account? - google-sheets

I have a python script using gspread to create a Google Sheets using a service user. So the owner of the document is the service user and not me.
How can I easily delete such a document if I am not the onwer but I have the service user details?

The Client object in the gspread library has a del_spreadsheet method. Here's the relevant section of the source code:
class Client:
def del_spreadsheet(self, file_id):
"""Deletes a spreadsheet.
:param str file_id: a spreadsheet ID (a.k.a file ID).
"""
url = "{}/{}".format(DRIVE_FILES_API_V3_URL, file_id)
params = {"supportsAllDrives": True}
self.request("delete", url, params=params)
So you can use your service account credentials to create a Client with ownership of the spreadsheet using gspread.service_account, then call the del_spreadsheet method of the Client. file_id is the unique ID of the spreadsheet, which you can easily pull from the URL bar when the spreadsheet is open, or using the id property of the spreadsheet if you're editing it with gspread.

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

Can you upload a file to the Slack API using files.upload as a different user?

I'm trying to find a way to have an application post a text snippet to our support channel through the Slack API. Using the files.upload method, I can create a text snippet and share it with the channel, but the post appears to come from me (because the token used to authenticate the request is mine).
I'm looking for a way to do this, but make it appear with a custom user name and icon, like you can with the chat.postMessage method's username and icon_url parameters. Is there a way to achieve this?
There are two ways.
Way 1. - If you only want to upload in a channel and don't need to listen to any conversation, then you can use incoming-webhooks. And then override the username and icon. Read "Customizing your username and icon" in Here.
Way 2 - You can create a bot user and let the bot user type post this message for you. I guess right now you are using test tokens generated by Slack so you are getting your name only. But if you use bot-user then you can use custom Name and icon_url for your bot.
I hope this answers your question.
Yes, as #Abhinav Rai suggested, you need have bot. Slack support just answered me the same question.
To upload files as a bot you'll need to create an associated 'bot user' and post the file using the bot's token: https://api.slack.com/bot-users — all files must be owned by a user account and the bot user will fill this requirement.
There is a way 3 which uses the username function from chat.postMessage function. Follow this -
import slack
import json
import os
def pureimg(data1):
data1 = '[{"text": "", "image_url": "'+data1+'"}]'
data1 = [json.loads(data1[1:-1])]
return data1
#This function will make the image url to correct format.
slacker = slack.WebClient(token='your-token-here')
payoff=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'filename.png')
#It gives cross OS compatibility on filepath.
response=slacker.files_upload(channel='#theta',file=payoff)
payoff=response['file']['permalink']
#First We upload the local file to Slack and fetch permalink.
#If you do not have any local file just put the external image URL in the payoff.
response=slacker.chat_postMessage(channel='#channel_name', text="Sample Text", username='Bot name', attachments=pureimg(payoff), icon_emoji=':emoji:')
#Then, We post to Slack Channel as a bot!

post array of numbers to google spreadsheet using android

I need to upload array of numbers from android to a google spreadsheet. I have try this solution https://github.com/FoamyGuy/GoogleFormUploadExample/tree/master/src/com/makemyandroidapp/example/googlespreadsheet/post
its work well but it upload single argument as a spreadsheet form entry. what i need is to upload full array say 1000 element at once.
Make use of the ready made library Google Form Uploader created by one of our developer friend. This would help you in uploading the numbers to the Google Spreadsheet in bulk.
To use this library you need to find your form-id, and your entry id's from the 'Live Form' page source code. Once you have those ids you can upload data to a form like this:
GoogleFormUploader uploader = new GoogleFormUploader("1AYvV0gFgB1hBuoRKnMsXy1LyF8-Ce8VAshAtho6Z08s");
uploader.addEntry("1680144410", "Hello Word");
uploader.addEntry("1558298396", "From android app");
uploader.upload();
but fill in your own form-id and entry ids.

Google Spreadsheets: Is there a HTTP request function?

Does Google Spreadsheets have a cell function that lets me do HTTP requests like
POST the contents of this cell to http://www.mysite.com/input or
GET the XML at http://www.mysite.com/feed.xml
?
Or can I write a custom function that does so? Or is there a more conventional way of doing what I want to do? (using Spreadsheets to talk to REST APIs)
For getting contents of a cell to your website use the Google Spreadsheet API.
Here you can find a simple example of retrieving JSON feeds from Spreadsheets Data API:
https://developers.google.com/gdata/samples/spreadsheet_sample
Since this link may be moved due goole updates here's a copy of the script element:
http://spreadsheets.google.com/feeds/feed/key/worksheet/public/basic?alt=json-in-script&callback=myFunc
... where feed is the type of feed, key is the key of the spreadsheet you want to retrieve, the worksheet is the positional or unique identifier of the worksheet, and myFunc is the name of your callback function that is passed the JSON object.
For getting XML from a web ressource use the function:
IMPORTXML(URL; XPath) e.g.
importXML("http://www.example.com/feed.xml";"/path/inXML")

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.

Resources