Недавно нам нужно было сделать простое приложение для Google Drive. Приложение должно было формировать список пользователей, на которых расшарены документы в указанной папке с возможностью редактирования. Задача, в принципе, простая, поэтому недолго думая развернул болванку проекта на angularJS и начал кодить. Гугл, подумал я, это же большая компания, у него должен быть понятный и стабильный API и я сделаю это за пару дней.
Я был слишком наивен.
Авторизация
Приложение подразумевало отсутствие серверной части (только клиентский js), поэтому для авторизации и идентификации было решено использовать авторизацию гугла. Авторизация — это же просто! Но не тут-то было. Для идентификации пользователя между экранами приложения решил хранить объект авторизации, который возвращается методом gapi.auth.getToken(). Метод штатный, все как бы для этого и создано. Но при сериализации этого объекта постоянно возникала забавная ошибка «Permission denied to access property 'toJSON'». Ошибка «интуитивно» понятная, поэтому потратил на нее пол дня. Оказалось, что в объекте, который возвращает эта функция, есть циклическая ссылка на самого себя. Циклическая ссылка содержалась в переменной g-oauth-window. Поэтому простой код решил эту проблему:
var oAuthObj = gapi.auth.getToken();
oAuthObj['g-oauth-window'] = null;
$window.localStorage.setItem('googlerSession', JSON.stringify(oAuthObj));
Следующая проблема при клиентской авторизации — это возобновление клиентской сессии. Сессия аутентификации при использовании только клиентской аутентификации сохраняется на 1 час. Но как возобновить ее или продлить — не понятно. Мои танцы с бубном с повторной авторизацией и прочим шаманством не смогли мне помочь, поэтому до сих пор клиентская часть у меня авторизует пользователя на 1 час. Для удобства вывел в верхнее меню время, оставшееся до инвалидации сессии. В принципе, для этого инструмента 1 часа вполне хватает.
Работа с документами
И тут не обошлось без проблем. Первая незадача, с которой столкнулся — как получить внешнюю ссылку на документ? Если с обычными документами все хорошо — она берется из свойства alternateLink объекта файла, то с папкой какая-то магия. Любая папка возвращается в виде ссылки на странный интерфейс folderview, который я до этого никогда не видел. Гугление ни к чему не привело, поэтому пришлось исправлять это некрасивым кодом:
var fileLink = fileObject.alternateLink;
if (fileLink.indexOf("folderview") != 0) {
fileLink = fileLink.replace("folderview?id=", "#folders/");
fileLink = fileLink.replace("&usp=drivesdk", "");
fileLink = fileLink.replace("docs.google.com", "drive.google.com");
}
Права на документы
Весь массив владельцев документа я строил относительно userId, который отдает гугл. Я думал, он уникальный и дает полное понимание, что это один и тот же пользователь. Но это оказалось не так. Согласно документации drive.permissions.list, в качестве id возвращается идентификатор пользователя (пруфлинк). Но в реальности оказалось, что это не тот идентификатор, который я ищу. Почему так — для меня до сих пор остается загадкой. Поэтому для идентификации и «узнавания» пользователя в списке владельцев я использовал email. Но это еще пол беды.
Такая путаница с идентификаторами приводит к другому забавному багу. Если текущий авторизованный пользователь является читателем документа, то permission.list не возвратит список прав доступа. Следовательно, что бы показать, что я читатель — я использую информацию из userInfo текущего пользователя. А если этот же человек потом будет в permission.list другого файла, например, владелец документа, то у него будет совсем другой идентификатор. Это приводит к тому, что в списке пользователей текущий авторизованный пользователь может быть продублирован.
Вывод: идентификатору пользователя доверять нельзя, тк он может меняться. Для идентификации пользователя лучше использовать email, хотя, теоретически он может отсутствовать. Например, если документ расшарен на корпоративный домен, то в этом случае email не будет, так как он расшарен на всех пользователей, которые принадлежат этому домену.
Была еще пара мелочей, которые уже вылетели из головы. Например, в объекте с информацией о файле не было нескольких переменных описанных в документации. Честно говоря уже не помню каких, но это уже мелочи.
P.S. Что из этого всего получилось, можно наблюдать здесь (http://googler.chililab.pro). Если есть идеи, как дополнить сервис, пишите в комментариях — реализую.
P.P.S. Если вы знаете красивое решение описанных в статье проблем, напишите в личку или в комментариях. Думаю, я не первый, кто столкнулся с этими проблемами.
Автор: kmolochkov