403 quotaExceeded error when executing com.google.api.services.drive.Drive.Files.Insert on Android, using a service account

断了今生、忘了曾经 提交于 2019-12-04 15:02:53
Oca

I found the problem and a candidate solution.

This is the scenario:

  • An account with acces to Google Drive, let's call it: manager@gmail.com.
  • Several accounts which are used to upload photos to the manager Google Drive, using an Android app, let's call it: worker@gmail.com.
  • I don't want to give access to the workers@gmail.com to the Google Drive of the manager@gmail.com, so I created a service account, which is the responsible to upload the photos from the Android App to the manager Google Drive, let's call it service@gmail.com.

When worker@gmail.com takes a photo, the service@gmail.com uploads a photo to the manager@gmail.com Google Drive. But the owner of the photo is the service@gmail.com. So in the manager@gmail.com Google Drive, you can see all the photos, but the quota always remains to zero.

After uploading 15 GB o photos I actually exceeded the quota, but it was the quota of the service@gmail.com (which is not visible in Google Drive).

SOLUTIONS

  1. Log into the manager@gmail.com Google Drive and delete the photos.

    ERROR: manager@gmail.com is not the owner. So if you remove the file, it will not be visible to the manager but it will keep on consuming quota of the service@gmail.com.

  2. Log into the service@gmail.com Google Drive and delete the photos.

    ERROR: There is no way (AKAIK) to log into a service@gmail.com Google Drive.

  3. Transfer the ownership of the files from service@gmail.com to manager@gmail.com.

    COOL That's a valid solution. Let's do it!!

    ERROR It seems that Google does not allow to change the ownership of some types of files. More info here

DIRTY SOLUTION

Yep, this may not be the most elegant solution. But it worked for me.

I created a Google Script using the manager@gmail.com account and I published as a Public Web Application.

function doGet(data) {
  var fileId = data.parameter.fileId;
  var file = DriveApp.getFileById(fileId);
  var result = { fileId: file.makeCopy(file.getName()).getId() };
  //I need to remove the file. Otherwise it semains linked to the one created by the *service@gmail.com*
  DriveApp.removeFile(file);
  return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
}

This methods receives the fileId created by the service@gmail.com, makes a copy (which owns manager@gmail.com). I need to remove the the file created by the service@gmail.com. The file is actually not removed, but it is not linked any more to the one created by the manager@gmail.com. Finally it returns the new fileId.

Now, my Android App looks like this:

private void uploadPhoto(String photoFolderId, File body, FileContent mediaContent) {
    //First, I upload the photo
    if(driveService.files().insert(body, mediaContent) != null) {
        transferOwnerShip(photoFolderId);
    }

    private void transferOwnerShip(String photoFolderId) {
        String photoId = getInsertedPhotoId();
        //Now I create a copy of the photo. The copied photo is owned by *manager@gmail.com*
        String ownedPhotoId = makeCopyOfPhoto(photoId);
        if(ownedPhotoId != null)
            //Once I have copied the photo, I remove the photo owned by *service@gmail.com*
            driveService.files().delete(photoId).execute();
    }

    private String makeCopyOfFile(String fileId) {
        URL url;
        try {
            url = new URL(URL_TO_MY_PUBLIC_SERVICE + "?fileId=" + fileId);

            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(url.toURI());
            HttpResponse resp = client.execute(get);
            BufferedReader rd = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
            StringBuffer result = new StringBuffer();
            String line = "";
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
            JSONObject jsonResponse = new JSONObject(result.toString());
            return jsonResponse.getString("fileId");
        } catch (Exception e) {
            warnAboutError();
        }
        return null;
    }

}

The dirty solution works, but it is very dirty. I could not figure out other way to work around this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!