My Google Drive app is no longer able to update google documents - google-drive-api

Yesterday afternoon I started having a problem where my google drive app could no longer update google documents. I can still update other file types like docx or rtf. This also happened to a coworker here but two different users are still able to use the google drive app and update google documents without issue, and we're all using the same build.
I logged into one of the working google accounts instead of my own and was not able to update that same google document that a coworker was able to. However the coworker that was having the same problem as me logged into a different google account and he was able to update google documents with the same build as before.
What the hell has happened here all of a sudden? This was working for us all two days ago.
This is where I request permissions:
GoogleWebAuthorizationBroker.Folder = "Tasks.Auth.Store";
StoredCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile },
"user",
CancellationToken.None,
new SavedDataStore()).Result;
I know the fileID going into it so:
request = service.Files.Get(fileID);
myFile = request.Execute();
While working with google documents I download it as a docx file and so:
if (myFile.MimeType == "application/vnd.google-apps.document")
myFile.MimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
And this is where the update happens:
try
{
//fileLoc contains the updated contents
byte[] byteArray = System.IO.File.ReadAllBytes(fileLoc);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
FilesResource.UpdateMediaUpload updateRequest = service.Files.Update(myFile, fileID, stream, myFile.MimeType);
//fileID is used to get myFile in the first place; myFile is = to myFile.Id
updateRequest.Upload();
}
catch (Exception e)
{
MessageBox.Show("An error occurred: " + e.Message);
}
This request happens without throwing any error and even updates the timestamp on these files but the content does not update. I am losing my mind trying to figure this out, I don't know what has gone wrong and I have no idea where to start looking.

There was a temporary glitch, this should be working again now.

Related

Trying to get Google Drive to work with PCL Xamarin Forms application

I’m using Xamarin Forms to do some cross platform applications and I’d like to offer DropBox and GoogleDrive as places where users can do backups, cross platform data sharing and the like. I was able to get DropBox working without doing platform specific shenanagins just fine, but Google Drive is really giving me fits. I have my app setup properly with Google and have tested it with a regular CLI .NET application using their examples that read the JSON file off the drive and create a temporary credentials file – all fine and well but getting that to fly without access to the file system is proving elusive and I can’t find any examples on how to go about it.
I’m currently just using Auth0 as a gateway to allow users to provide creds/access to my app for their account which works dandy, the proper scope items are requested (I’m just using read only file access for testing) – I get an bearer token and refresh token from them – however when trying to actually use that data and just do a simple file listing, I get a 400 bad request error.
I’m sure this must be possible but I can’t find any examples anywhere that deviate from the slightest of using the JSON file downloaded from Google and creating a credentials file – surely you can create an instance of the DriveService object armed with only the bearer token...
Anyway – here’s a chunk of test code I’m trying to get the driveService object configured – if anyone has done this or has suggestions as to what to try here I’d very much appreciate your thoughts.
public bool AuthenticationTest(string pBearerToken)
{
try
{
var oInit = new BaseClientService.Initializer
{
ApplicationName = "MyApp",
ApiKey = pBearerToken,
};
_googleDrive = new DriveService(oInit);
FilesResource.ListRequest listRequest = _googleDrive.Files.List();
listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name)";
//All is well till this call to list the files…
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;
foreach (var file in files)
{
Debug. WriteLine(file.Name);
}
}
catch (Exception ex)
{
RaiseError(ex);
}
}

Edit on Google Docs without converting

I'm integrating my system with Google Drive. Everything is working so far, but one thing. I cannot edit the uploaded Word documents without converting them to Google Docs first.
I've read here it's possible using a Chrome plugin:
https://support.google.com/docs/answer/6055139?hl=en
But that's not my goal. I'm storing the file's information on my database and then I just request the proper URL for editing and previewing. Previewing is working fine, but when I try the edit URL it says the file does not exist. If I convert the file (using Google Drive's interface) and pass the new ID it works. I don't want to convert the user's documents to Google Drive because they still use Word as their main editing software.
Is there a way to accomplish this?
This is how I'm doing right now:
public static File UploadFile(FileInfo fileInfo, Stream stream, string googleAccount)
{
var mimetype = GetValidMimetype(fileInfo.MimeType);
var parentFolder = GetParentFolder(fileInfo);
var file = new File { Title = fileInfo.Title, MimeType = mimetype, Parents = parentFolder };
var uploadRequest = _service.Files.Insert(file, stream, mimetype);
uploadRequest.Upload();
file = uploadRequest.ResponseBody;
ShareFileWith(file.Id, googleAccount);
return file;
}
This is the URL for editing (where {0} is the file ID):
https://docs.google.com/document/d/{0}/edit?usp=drivesdk
I know that in order to convert the file I just need to:
uploadRequest.Convert = true;
But again, that's not what I want. Is it possible?
Thanks!
EDIT
Just an update. Convert = true should've worked but it's not. I've raised an issue for that here https://github.com/google/google-api-dotnet-client/issues/712
Bottomline, it only works if I open the file on Google Docs and then use its Id...

Google Drive Folders/Files Created Using API Not Visible on Google Interface

This is rather strange. I used Google Drive API to create a folder in Google Drive and then uploaded a file there. I can retrieve the folder and file using the same API (the code is working fine in all respect). However, when I go to Google Drive Web interface, I can't seem to find the folder or file. The file also doesn't sync to my local drive. Is there a setting in API or elsewhere to set the "visibility" ON?
Thank you in advance.
I had the same issue. Turned out to be permissions. When the file is uploaded by the service account, the service account is set as the owner, and then you can't see the files from the Drive UI. I found the solution online (but can't seem to find it again...)
This is what I did...
It's C#, your question didn't specify. The code you're interested in is the permission stuff after you get the response body after the upload...
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "text/plain");
request.Upload();
//Start here...
Google.Apis.Drive.v2.Data.File file = request.ResponseBody;
Permission newPermission = new Permission();
newPermission.Value = "yourdriveaccount#domain.com";
newPermission.Type = "user";
newPermission.Role = "reader";
service.Permissions.Insert(newPermission, file.Id).Execute();
The file was visible on the Drive UI after this. I tried specifying "owner" for the role, like the api suggests, but I got and error saying that they're working on it. I haven't played around with the other setting yet, (I literary did this last night). Let me know if you have any luck with any other combinations on permissions.
Hope that helps
I had the same issue, but this got solved my using a list data type for parents parameter, eg: If one wants to create a folder under a folder("1TBymLMZXPGkouw-lTQ0EccN0CMb_yxUB") then the python code would look something like
drive_service = build('drive', 'v3', credentials=creds)
body={
'name':'generated_folder',
'parents':['1TBymLMZXPGkouw-lTQ0EccN0CMb_yxUB'],
'mimeType':'application/vnd.google-apps.folder'
}
doc = drive_service.files().create(body=body).execute()
While permission issue is the main cause of this problem. What I did to make the folders or files appear after I uploaded it with service account was to specify the parent folder. If you upload / create folder / files without parent folder ID, that object's owner will be the service account that you are using.
By specifying parent ID, it will use the inherited permissions.
Here's the code I use in php (google/apiclient)
$driveFile = new Google\Service\Drive\DriveFile();
$driveFile->name = $req->name;
$driveFile->mimeType = 'application/vnd.google-apps.folder';
$driveFile->parents = ['17SqMne7a27sKVviHcwPn87epV7vOwLko'];
$result = $service->files->create($driveFile);
When you create the folder, you should ensure you set a parent, such as 'root'. Without this, it will be not appear in 'My Drive' and only in Search (Have you tried searching in the UI?)
Since you have already created the folder, you can update the file and give it the parent root as well.
You can test it out using the Parents insert 'Try it now' example.
Put your Folders ID in the fileId box, then in the request body, add root in the ID field.
private void SetFilePermission(string fileId)
{
Permission adminPermission = new Permission
{
EmailAddress = "test#gmail.com", // email address of drive where
//you want to see files
Type = "user",
Role = "owner"
};
var permissionRequest = _driveService.Permissions.Create(adminPermission, fileId);
permissionRequest.TransferOwnership = true; // to make owner (important)
permissionRequest.Execute();
Permission globalPermission = new Permission
{
Type = "anyone",
Role = "reader"
};
var globalpermissionRequest = _driveService.Permissions.Create(globalPermission, fileId);
globalpermissionRequest.Execute();
}

How to sync conflicting changes with Google Drive API

I have a google drive app which will auto-save changes. If you have two active sessions then they will overwrite each other. The app supports merging changes but I can't see how to safely integrate this with the drive API. Some options I have considered:
Version safe commits
Use google drive to "only update if current revision in drive == X otherwise fail"
If failed then fetch latest version, merge and retry
problem: I don't think drive supports this. Previous API versions used etags but I see no mention of this in the current documenation.
Pre-commit check
check current saved version, if still current, save
otherwise download, merge and update
problem: obvious race condition between clients
Post-commit check
save new version
if new version is as expected: done
if new version higher than expected: download previous version, merge and update
problem: I don't have much faith this is safe. I can see multiple clients getting in edit loops.
Google real-time api - field binding
replace file format with a google rt datamodel
problem: It would require redesigning just for google-rt
Google real-time api - document support
use google rt api external document support
problem: I don't think this solves the problem
I would really like a way to achieve #1 but any suggestions would be helpful. I would be happy enough with a basic locking / handover scheme between clients but I don't think Drive supports that either.
According to here, "If-Match" using etags still works. Not sure if it applies to data, but at least it applies to metadata.
To follow up on user1828559's answer, the following Java code seems to work well:
private File updateDriveFile(Drive drive, File file, byte[] data) throws IOException {
try {
ByteArrayContent mediaContent = new ByteArrayContent(MIME_TYPE, data);
Drive.Files.Update update = drive.files().update(file.getId(), file, mediaContent);
update.getRequestHeaders().setIfMatch(file.getEtag());
return update.execute();
}
catch (GoogleJsonResponseException e) {
if (isConflictError(e.getDetails())) {
logger.warn("ETag precondition failed, concurrent modification detected!");
return null;
}
throw e;
}
}
private boolean isConflictError(GoogleJsonError error) {
if (error.getCode() == 412) {
final List<GoogleJsonError.ErrorInfo> errors = error.getErrors();
if (errors != null && errors.size() == 1) {
final GoogleJsonError.ErrorInfo errorInfo = errors.get(0);
if ("header".equals(errorInfo.getLocationType()) &&
"If-Match".equals(errorInfo.getLocation()) &&
"conditionNotMet".equals(errorInfo.getReason()))
return true;
}
}
return false;
}

When i open a generated PDF it results in a error using the new spreadsheets

I brought the code down in the function below to the bare minimum and the file creation of the PDF is ok.
But if I use a file id created with the “new spreadsheet” setting on. The PDF opens with a error. If I switch back to the old version of the spreadsheets the file is actually ok.
Must be something wrong with the blob creation? Is this a know issue?
Thanks,
function alone() {
try {
var spreadSheetFile = DriveApp.getFileById("1lljK6wItraoMhI4NM3kueN69LZ3MSs-2mCWiM-W7tEU");
var pdf = spreadSheetFile.getAs('application/pdf');
} catch (e) {
Logger.log ("Catched something: "+e+"\n"+e.stack);
}
DriveApp.createFile(pdf);
}
While there are multiple issues in the tracker regarding getAs(), none seem specific to the new Sheets. I suggest that you enter a new issue.
There are also many known problems with Apps Script support for the new Sheets offering. Again, no mention of File.getAs() there.