Google Apps Script: Как получить имя текущего пользователя?

Краткое описание Google Apps Script и его возможностей

Google Apps Script (GAS) — это облачная платформа для разработки скриптов, основанная на JavaScript, которая позволяет автоматизировать задачи, интегрировать и расширять функциональность приложений Google Workspace (Docs, Sheets, Forms, Drive, Gmail и др.). Она предоставляет удобный способ создания пользовательских меню, диалоговых окон, автоматических обработчиков событий и взаимодействия с внешними API.

Почему важно знать имя текущего пользователя в скриптах

Определение текущего пользователя, взаимодействующего со скриптом, является ключевым аспектом для многих сценариев. Это позволяет персонализировать интерфейс, разграничивать права доступа к данным или функциям, вести журналы аудита действий пользователей, а также настраивать логику скрипта в зависимости от того, кто его запускает. Например, в системе утверждения документов важно знать, кто инициировал или утвердил запрос.

Обзор методов получения имени пользователя, которые будут рассмотрены

В этой статье мы рассмотрим основные подходы к идентификации текущего пользователя в Google Apps Script:

  • Использование встроенного сервиса Session для получения email и имени пользователя.
  • Применение Properties Service для кэширования идентификатора пользователя.
  • Краткий обзор альтернативных методов, таких как Admin SDK и Google Picker API.

Использование сервиса Session для получения имени пользователя

Сервис Session предоставляет информацию о текущем сеансе пользователя, включая его идентификационные данные. Это наиболее прямой и часто используемый способ.

Метод Session.getActiveUser().getEmail(): получение адреса электронной почты пользователя

Метод Session.getActiveUser().getEmail() возвращает основной адрес электронной почты пользователя, запустившего скрипт. Это наиболее надежный способ идентификации пользователя в домене Google Workspace или обычного пользователя Gmail, так как email уникален.

/**
 * Получает и логирует адрес электронной почты текущего активного пользователя.
 *
 * @returns {string | null} Адрес электронной почты пользователя или null, если пользователь не может быть определен.
 */
function logCurrentUserEmail(): string | null {
  try {
    const userEmail: string = Session.getActiveUser().getEmail();
    if (userEmail) {
      console.log(`Электронная почта текущего пользователя: ${userEmail}`);
      return userEmail;
    } else {
      // Это может произойти в редких случаях или при определенных режимах авторизации
      console.log('Не удалось получить email активного пользователя.');
      return null;
    }
  } catch (e: any) {
    // Ошибка может возникнуть, если скрипт выполняется в контексте,
    // где нет активного пользователя (например, анонимный доступ к веб-приложению)
    console.error(`Ошибка при получении email пользователя: ${e.message}`);
    return null;
  }
}

Важно отметить, что для вызова getEmail() скрипту требуется разрешение script.scriptapp.getuserinfo.email.

Метод Session.getActiveUser().getUsername(): получение имени пользователя (может потребовать авторизации)

Метод Session.getActiveUser().getUsername() возвращает имя пользователя, как оно определено в аккаунте Google. Для пользователей Google Workspace это обычно часть email до символа @. Для обычных аккаунтов Gmail результат может совпадать с email.

/**
 * Получает и логирует имя пользователя (username) текущего активного пользователя.
 *
 * @returns {string | null} Имя пользователя или null, если пользователь не может быть определен.
 */
function logCurrentUsername(): string | null {
  try {
    // Важно: getUsername() может не всегда возвращать уникальное значение
    // и его поведение может отличаться для Workspace и Gmail аккаунтов.
    const username: string = Session.getActiveUser().getUsername();
    if (username) {
      console.log(`Имя пользователя (username): ${username}`);
      return username;
    } else {
      console.log('Не удалось получить имя пользователя (username).');
      return null;
    }
  } catch (e: any) {
    console.error(`Ошибка при получении username пользователя: ${e.message}`);
    return null;
  }
}

Использование getEmail() обычно предпочтительнее для надежной идентификации.

Ограничения использования getActiveUser() в различных контекстах (например, триггеры)

Методы getActiveUser() имеют ограничения:

  • Простые триггеры (onOpen, onEdit и т.д.): В режиме AuthMode.LIMITED, эти триггеры не могут вызывать сервисы, требующие авторизации, включая Session.getActiveUser().getEmail(). Вызов вернет пустую строку или вызовет ошибку.
  • Устанавливаемые триггеры (Installable Triggers): Если триггер установлен пользователем, скрипт будет выполняться от имени этого пользователя, и getActiveUser() вернет его данные. Если триггер настроен на запуск от имени разработчика, то getActiveUser() вернет данные разработчика, а не пользователя, вызвавшего событие (например, редактирование ячейки).
  • Веб-приложения: В веб-приложениях, развернутых с настройкой «Execute as: Me» и «Who has access: Anyone», getActiveUser() вернет данные владельца скрипта. Если выбрано «Execute as: User accessing the app», то getActiveUser() вернет данные пользователя, открывшего приложение, но только если доступ разрешен не анонимным пользователям («Anyone, even anonymous» не позволит получить email).
  • Дополнения (Add-ons): Поведение зависит от модели авторизации дополнения.

Всегда учитывайте контекст выполнения скрипта при использовании getActiveUser().

Использование сервиса Properties для хранения и получения имени пользователя

В сценариях, где прямой вызов Session.getActiveUser().getEmail() невозможен или нежелателен при каждом запуске (например, в простых триггерах или для оптимизации), можно использовать Properties Service для кэширования email пользователя.

Сохранение имени пользователя в Properties Service при первом запуске скрипта

При первом запуске скрипта пользователем (например, через пользовательское меню, требующее авторизации), можно получить его email и сохранить его в UserProperties.

/**
 * Получает email текущего пользователя и сохраняет его в UserProperties,
 * если он еще не сохранен.
 */
function storeUserEmailOnce(): void {
  const userProperties: GoogleAppsScript.Properties.Properties = PropertiesService.getUserProperties();
  const storedEmail: string | null = userProperties.getProperty('userEmail');

  if (!storedEmail) {
    try {
      const currentUserEmail: string = Session.getActiveUser().getEmail();
      if (currentUserEmail) {
        userProperties.setProperty('userEmail', currentUserEmail);
        console.log(`Email пользователя ${currentUserEmail} сохранен в UserProperties.`);
      } else {
        console.log('Не удалось получить email пользователя для сохранения.');
      }
    } catch (e: any) {
      console.error(`Ошибка при получении или сохранении email: ${e.message}`);
    }
  }
}

Эту функцию можно вызвать из функции, которая гарантированно требует авторизации.

Получение имени пользователя из Properties Service при последующих запусках

В функциях, где прямой доступ к Session.getActiveUser().getEmail() ограничен (например, onEdit), можно попытаться извлечь сохраненный email из UserProperties.

/**
 * Получает email пользователя из UserProperties.
 *
 * @returns {string | null} Сохраненный email или null, если он не найден.
 */
function getStoredUserEmail(): string | null {
  const userProperties: GoogleAppsScript.Properties.Properties = PropertiesService.getUserProperties();
  const storedEmail: string | null = userProperties.getProperty('userEmail');

  if (storedEmail) {
    console.log(`Получен сохраненный email: ${storedEmail}`);
    return storedEmail;
  } else {
    console.log('Email пользователя не найден в UserProperties.');
    // Здесь можно инициировать процесс запроса авторизации и сохранения,
    // если это уместно в данном контексте.
    return null;
  }
}

// Пример использования в onEdit (требует осторожности)
function onEdit(e: GoogleAppsScript.Events.SheetsOnEdit): void {
  const userEmail: string | null = getStoredUserEmail();
  if (userEmail) {
    // Логика, использующая email пользователя
    console.log(`Ячейка ${e.range.getA1Notation()} отредактирована пользователем (из Properties): ${userEmail}`);
  } else {
    // Обработка случая, когда email не сохранен (например, первый запуск)
    console.log(`Ячейка ${e.range.getA1Notation()} отредактирована неизвестным пользователем (нет в Properties).`);
  }
}

Преимущества и недостатки использования Properties Service для этой цели

Преимущества:

  • Позволяет получить идентификатор пользователя в контекстах с ограниченной авторизацией (после первоначального сохранения).
  • Уменьшает количество запросов авторизации, если email требуется часто.

Недостатки:

  • Требуется первоначальный запуск с полной авторизацией для сохранения email.
  • UserProperties хранятся для каждого пользователя отдельно. Данные не будут доступны, если скрипт выполняется от имени другого пользователя (например, через триггер, установленный администратором).
  • Не отражает реального текущего пользователя, если скрипт выполняется не от его имени (например, триггер, запускающийся от имени создателя триггера).
  • Данные могут устареть, если пользователь изменит свой основной email (хотя это редкий случай).

Альтернативные способы получения имени пользователя

Существуют и другие, более специфичные методы.

Использование Admin SDK (если есть права администратора Google Workspace)

Администраторы домена Google Workspace могут использовать сервис AdminDirectory (часть Advanced Google Services) для получения подробной информации о пользователях домена по их email, включая полное имя, должность и т.д. Это выходит за рамки получения текущего пользователя скрипта, но позволяет обогатить данные, полученные через Session.getActiveUser().getEmail().

/**
 * Пример получения полного имени пользователя (требует прав администратора и включения Admin SDK).
 *
 * @param {string} email Адрес электронной почты пользователя.
 * @returns {string | null} Полное имя пользователя или null при ошибке/отсутствии данных.
 */
function getUserFullNameByEmail(email: string): string | null {
  // Необходимо включить Admin Directory API в Расширенных сервисах Google
  try {
    const user: GoogleAppsScript.AdminDirectory.Schema.User = AdminDirectory.Users.get(email);
    if (user && user.name && user.name.fullName) {
      return user.name.fullName;
    }
    return null;
  } catch (e: any) {
    console.error(`Не удалось получить данные пользователя ${email} через Admin SDK: ${e.message}`);
    return null;
  }
}

Получение имени пользователя через Google Picker API (требуется дополнительная настройка)

Google Picker API позволяет пользователю выбирать файлы из Google Drive, но также может быть использован для получения информации о пользователе, который взаимодействует с Picker. Это требует создания клиентского интерфейса (HTML Service) и сложной настройки, поэтому редко используется только для получения имени пользователя.

Заключение и рекомендации

Сравнение различных методов получения имени пользователя

  • Session.getActiveUser().getEmail(): Самый надежный и прямой способ идентификации текущего пользователя. Требует соответствующей авторизации и имеет ограничения в определенных контекстах (простые триггеры).
  • Session.getActiveUser().getUsername(): Менее надежен для уникальной идентификации, но может быть полезен для отображения имени пользователя.
  • Properties Service: Хороший способ кэширования email для использования в ограниченных контекстах, но требует первоначального сохранения и не всегда отражает реального пользователя в текущем сеансе выполнения (особенно с триггерами).
  • Admin SDK: Мощный инструмент для администраторов Workspace для получения детальной информации о пользователях домена, но не для определения текущего пользователя скрипта без его email.
  • Picker API: Слишком сложен для простой задачи получения имени пользователя.

Рекомендации по выбору оптимального метода в зависимости от сценария использования

  • Стандартные скрипты, пользовательские меню, диалоги: Используйте Session.getActiveUser().getEmail(). Это самый надежный идентификатор.
  • Простые триггеры (onOpen, onEdit): Прямое получение email невозможно. Либо используйте Properties Service (с пониманием ограничений), либо переходите на устанавливаемые триггеры.
  • Устанавливаемые триггеры: Session.getActiveUser().getEmail() вернет email пользователя, установившего триггер. Если вам нужен email пользователя, вызвавшего событие (например, редактирование), этот метод не подойдет. В таких случаях можно записать email в ячейку или использовать Properties Service при редактировании, если email был сохранен ранее.
  • Веб-приложения: Используйте Session.getActiveUser().getEmail() при настройке «Execute as: User accessing the app» и доступе не для анонимных пользователей.
  • Административные задачи в Workspace: Используйте Session.getActiveUser().getEmail() для идентификации администратора, запускающего скрипт, и Admin SDK для получения данных о других пользователях.

Наиболее универсальным и рекомендуемым методом для идентификации пользователя, взаимодействующего со скриптом в рамках сессии с достаточными правами, остается Session.getActiveUser().getEmail().

Дополнительные ресурсы и полезные ссылки

Для более глубокого изучения рекомендуется обратиться к официальной документации Google Apps Script по сервисам Session, PropertiesService и AdminDirectory.


Добавить комментарий