403 quotaExceeded ошибка при выполнении com.google.api.services.drive.Drive.Files.Insert на Android, используя учетную запись службы

У меня есть приложение для Android, которое копирует электронную таблицу, редактирует электронную таблицу и загружает некоторые фотографии в учетную запись Google Drive от третьего лица, используя служебную учетную запись.

Приложение работало хорошо. Но последний 22 января приложение начало выходить из строя.

Теперь он копирует электронную таблицу и редактирует, но фотографии больше не загружаются. И я получаю эту ошибку.

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden

{re 
  "code" : 403,
  "errors" : [ {
    "domain" : "usageLimits",
    "message" : "The user has exceeded their Drive storage quota",
    "reason" : "quotaExceeded"
  } ],
  "message" : "The user has exceeded their Drive storage quota"
}

Я проверил как квоту API, так и квоту хранилища на накопителе, и они значительно ниже предела.

Я не внес изменения в код и не изменил настройки безопасности ни в одной из задействованных учетных записей.

Я не смог найти ни одной известной проблемы по этому поводу.

Кто-нибудь еще испытывает нечто подобное??

1 ответ

Я нашел проблему и возможное решение.

Это сценарий:

  • Аккаунт с доступом к Google Drive, назовем его: manager@gmail.com.
  • Несколько аккаунтов, которые используются для загрузки фотографий в менеджер Google Drive, с помощью приложения для Android, назовем его: worker@gmail.com.
  • Я не хочу предоставлять доступ к worker@gmail.com на диск Google на адрес manager@gmail.com, поэтому я создал служебную учетную запись, которая отвечает за загрузку фотографий из приложения Android в менеджер Google. Диск, назовем это service@gmail.com.

Когда работник@gmail.com делает фотографию, service@gmail.com загружает фотографию на страницу управления@gmail.com Google Drive. Но владельцем фотографии является service@gmail.com. Так что в manager@gmail.com Google Диске вы можете увидеть все фотографии, но квота всегда остается нулевой.

После загрузки 15 ГБ фотографий я фактически превысил квоту, но это была квота на service@gmail.com (который не отображается в Google Диске).

РЕШЕНИЯ

  1. Зайдите на manager@gmail.com Google Диск и удалите фотографии.

    ОШИБКА: manager@gmail.com не является владельцем. Поэтому, если вы удалите файл, он не будет виден менеджеру, но он будет продолжать использовать квоту на service@gmail.com.

  2. Войдите на сервис@gmail.com Google Drive и удалите фотографии.

    ОШИБКА: Невозможно (AKAIK) войти на сервисную диск Google@gmail.com.

  3. Перенесите владение файлами сservice@gmail.com на manager@gmail.com.

    COOL Это правильное решение. Давай сделаем это!!

    ОШИБКА Похоже, что Google не позволяет изменить владельца некоторых типов файлов. Больше информации здесь

Грязное решение

Да, это может быть не самым элегантным решением. Но это сработало для меня.

Я создал скрипт Google Script, используяучетную запись manager@gmail.com, и опубликовал его как общедоступное веб-приложение.

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);
}

Этот метод получает fileId, созданный service@gmail.com, создает копию (которой владеет manager@gmail.com). Мне нужно удалить файл, созданный service@gmail.com. Файл на самом деле не удален, но он больше не связан с тем, который создан manager@gmail.com. Наконец, он возвращает новый идентификатор файла.

Теперь мое Android-приложение выглядит так:

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;
    }

}

Грязный раствор работает, но он очень грязный. Я не мог придумать другой способ обойти это.

Другие вопросы по тегам