Печать из Google Apps Script / Хабр

«scripterror: для выполнения этого действия требуется авторизация». при запуске n из библиотеки

Искренне Ваш,

Я нашел несколько вопросов относительно этой ошибки, "ScriptError: Authorisation is required to perform that action."но не могу найти ни одного, касающегося
моей проблемы.

Ссылаясь на этот ответ, эти ответы и это сообщение об ошибке, я создал “функцию оболочки” в библиотечном сценарии. Я пытаюсь вызвать файл function.gs из файлов в библиотеке google, где оба файла находятся на этой странице.

Вот что я сделал:

Html в библиотеке:

.gs в библиотеке

.gs в скрипте, используя :

В консоли появляется надпись HERE, за которой следует сообщение INFRENT: ScriptHere, для выполнения этого значения требуется авторизация.

П РИМЕЧАНИЯ. HTML-код предназначен не для настройки веб-приложения, а для немодального диалогового окна в таблицах.

Искренне надеюсь, что кто-нибудь сможет мне помочь. Я благодарен.

Gcp web element

Я попробовал oAuth 2.0, но это оказалось непросто.

. Я не стал тратить много времени на изучение этой темы, потому что у меня уже были готовые ответы. В двух словах, результат плохой. Для отображения в браузере Google Apps Script переписывает код JavaScript. Следовательно, GCP Web Element просто не функционирует. Вот пример кода для создания устройства.


В итоге я остановился пока на oAuth 1.0, как на наиболее тиражируемом варианте (хоть и работоспособен метод до 20 апреля, тем не менее, как

первое

Это лучше, потому что проще объяснить клиенту сложность oAuth 2.0.

Oauth 2.0

O Auth 1.0 в настоящее время находится на последних месяцах своего существования; поддержка протокола будет запрещена после 20 апреля 2022 года. При использовании сервисов Google возникает проблема с client_id и redirect, когда нам нужно воспроизвести решение после перехода на авторизацию oAuth 2.0.

  1. Отправляет пользователя на страницу с запросом на аутентификацию.
  2. Получили ответ с кодом на перенаправленный URL.
  3. Получили маркер с кодом для доступа к услугам.


Проблема возникает именно с редиректом, поскольку каждый скрипт имеет в облаке уникальный идентификатор, и URL редиректа должен соответствовать этому идентификатору. Поэтому, в тиражируемом решении, есть такие варианты:

Все эти методы являются либо внутренней разработкой, которая стоит на втором месте, либо на третьем, что не очень удобно для них самих. На самом деле, ничто в архитектуре oAuth не указывает на то, что ситуация может измениться. Первый вариант, или второй, если клиент согласен предоставить доступ к своей учетной записи или создать нейтральную новую, – вот что я бы посоветовал для повторяемого решения.

Учитывая, что я не писал второй вариант, а только обдумывал его, приведу пример кода первого варианта. Второй вариант идентичен первому в том, что client_id генерируется клиентом или разработчиками.

Аутентификация через oAuth 2.0

Похожее:  Дистанционное обучение | Иркутский государственный университет путей сообщения
Шаг 1. создаем client_id

  1. Откройте Google Developer Console и создайте новый проект.
  2. Перейдите в APIs&auth ->Credentials, нажмите на Create a new client ID.
  3. Тип – веб-приложение; Разрешенные источники JavaScript – script.google.com/; Разрешенные URI перенаправления – найти URL редактора сценария для нашего сценария, не включая /edit, а затем добавить /usercallback в конец.

Обычно в результате должно получиться что-то вроде этого:

Печать из Google Apps Script / Хабр

Шаг 2. код для авторизации

Предоставьте пользователю кнопку, которая направит его на URL для авторизации oAuth 2.0 в данном случае. Функция, которую мы указали, получит перенаправление.

function test() {
  var html = HtmlService.createTemplateFromFile("Auth").evaluate().setSandboxMode(HtmlService.SandboxMode.NATIVE).setTitle("Test");
  SpreadsheetApp.getUi().showModalDialog(html, "Test");
}
function getAuthURL() {
  var options= {
    client_id : "110560935370-jdoq9cc7tvna2r94va4j9o3310m6ghth.apps.googleusercontent.com", // заменить на свой
    scope : "https://www.googleapis.com/auth/cloudprint",
    redirect_uri : "https://script.google.com/macros/d/MDYeOxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/usercallback", // заменить на свой
    state : ScriptApp.newStateToken().withMethod("getAuthResponse").createToken()
  };
  var url = "https://accounts.google.com/o/oauth2/auth?response_type=code&access_type=offline";
  for(var i in options) 
    url  = "&" i "=" encodeURIComponent(options[i]);
  return url;
}

Auth.html:

<a href='<?!= getAuthURL(); ?>' target='_blank'>
<button>Authorize!</button>
</a>

Ключевая функция здесь

ScriptApp.newStateToken()

В описании метода рассказывается, как создать параметр для метода.

usercallback

Влекущий вызов указанной функции ()

getAuthResponse

). Вы можете посмотреть, что происходит при использовании YouTube.

test()

В диалоговом окне имеется кнопка, ведущая на страницу авторизации.

Шаг 3. получение oauth token и вызов google cloud print

После обратного звонка мы прибываем в интернат.

getAuthResponse()

. Давайте создадим этот метод и используем полученный токен для вызова метода Google Cloud Print:

function getAuthResponse(q) {
  var options = {
    method: "post",
    muteHttpExceptions: true,
    payload: {
      code: q.parameter.code,
      client_id : "110560935370-jdoq9cc7tvna2r94va4j9o3310m6ghth.apps.googleusercontent.com", // заменить на свой
      client_secret : "xxxxxxxxxxxxxxxxxxxxxxxx", // заменить на свой
      redirect_uri: "https://script.google.com/macros/d/MDYeOxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/usercallback", // заменить на свой
      grant_type: "authorization_code"
    }
  }
  var response = JSON.parse(UrlFetchApp.fetch("https://accounts.google.com/o/oauth2/token", options));
  var auth_string = response.token_type " " response.access_token;
  options.method = "get";
  options.payload = null;
  options.headers = {Authorization: auth_string};
  response = UrlFetchApp.fetch("https://www.google.com/cloudprint/search",options);
  return ContentService.createTextOutput(response.getContentText());
}

Если все пойдет по плану, результат нажатия кнопки

Authorize

Появится список подключенных принтеров, откроется окно авторизации.

Я не знаю точно почему, но другой подход лучше работает для меня с точки зрения исполнения.

Грязный хак

Поддерживается токен авторизации Google Apps Script. Вы можете вызвать его для активации.

ScriptApp.getOAuthToken()

. Однако этот маркер не предоставляет никаких привилегий доступа к Google Cloud Print.

Однако существует способ расширить этот список прав. Для этого вызовите окно запроса авторизации и, если необходимо, вызовите сброс текущего токена.

ScriptApp.invalidateAuth()

) и скопируйте адрес этого окна (не закрывайте окно до получения подтверждения! ):

Печать из Google Apps Script / Хабр

В скопированном URL один из параметров будет выглядеть, как «scope=https:// https://» (набор прав, необходимых скрипту). Достаточно добавить в конце данного параметра

 https://www.googleapis.com/auth/cloudprint

В новой вкладке браузера введите измененный URL-адрес, а затем утвердите запрос. После этого сценарию будут предоставлены права доступа к Google Cloud Print, и эти права будут действовать до их возобновления (например, путем вызова).

Похожее:  Крайинвестбанк - вход в личный кабинет

invalidateAuth

У вас есть возможность удалить жетон, если вы хотите сбросить его.

Контент и печать


Если бы API Google Apps Script работал бы так, как указано в документации, жизнь, несомненно была бы намного проще. Google Spreadsheet (точнее, приложение для работы с таблицей SpreadsheetApp) поддерживает конвертацию «на лету» в pdf:

function test() {
   var pdf = SpreadsheetApp.getActiveSpreadsheet().getAs("application/pdf");
}

Планировалось экспортировать выбранный диапазон в PDF из новой электронной таблицы. К сожалению, ошибка Google Apps Script исчезает. Как вы можете ее избежать?

  1. Оказывается, Google Cloud Print знает, как распечатать электронную таблицу Google. Вы можете переместить выделение в новую электронную таблицу и дать команду печати.
  2. Более элегантный способ: в меню Google Spreadsheet есть опция “Загрузить как…” с возможностью выбора формата PDF. И этот вариант, в отличие от преобразования через Google Apps Script, работает.

Браузер выбирает второй вариант, щелкая по уникальной ссылке. Введите следующий код для создания PDF из переданного диапазона электронной таблицы:

Однако в коде есть две проблемы, которые не позволяют ему работать. Во-вторых, при попытке передачи файла происходит сбой oAuth 1.0 (привет, ошибки сценариев Google Apps). Во-вторых, URL-адрес для загрузки файла не может быть доступен, а контекст аутентификации сценария не совпадает с контекстом пользователя, вызвавшего сценарий.

Как это работает? – После завершения печати откройте электронную таблицу для “внешнего мира” на время печати. Но в этом случае вам не нужно предоставлять Google Cloud Print URL-адрес загрузки:

Попытка 2. Работает!

function test() {
  var searchAnswer = invokeCloudPrint_("search");
  var url = cloudPrint_("A1:D12",true);
  var payload = {
       printerid: printer,
       xsrf: searchAnswer.xsrf_token,
       title: rangess.getSheet().getName(),
       ticket: "{"version": "1.0","print": {}}",
       contentType: "url",
       content: url
  };
  var drivefile = DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId());
  var oldaccess = drivefile.getSharingAccess();
  var oldpermission = drivefile.getSharingPermission();
  drivefile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
  var printstatus = invokeCloudPrint_("submit",payload);
  drivefile.setSharing(oldaccess, oldpermission);
  Browser.msgBox(printstatus.message);
}

Часть 1. challenge

Просматривая ленту новостей на YouTube, я обнаружил нечто очень похожее.

Наткнулся в приложениях или Google Apps Script. Клиент попросил меня создать сценарий, который бы мгновенно отправлял ему определенную часть электронной таблицы Google.

— Мы сами знаем, что она не имеет решения, — сказал Хунта, немедленно ощетиниваясь. — Мы хотим знать, как её решать.
Аркадий и Борис Стругацкие. Понедельник начинается в субботу


Статья рассчитана на читателей, уже знакомых с Google Apps Script и сопутствующими технологиями.

Часть 2. мучения

Ответ был прост: пользуйтесь услугами “Ростелекома”.

Распечатанный документ можно использовать как PDF. Перед отправкой запроса на печать служба может сначала потребовать аутентификацию. Я настроил службу, распечатал принтеры и выполнил запросы API. Печать из REST-клиента безупречна и функциональна. Пора писать статью.

Шаг 2. код для авторизации


Здесь все просто — показываем пользователю кнопку, которая перебросит его на URL для авторизации по oAuth 2.0. Редирект пойдет назад в указанную нами функцию:

Похожее:  Postfix | Русскоязычная документация по Ubuntu

Шаг 3. получение oauth token и вызов google cloud print

После ответного звонка мы прибываем в город.

getAuthResponse()

. Давайте напишем этот метод и используем полученный токен для вызова одного из методов Google Cloud Print.

Часть 3. итоги


В итоге, после путешествия по лабиринту багов и проблем, печать заработала. Привожу полный код с oAuth 1.0 (как самодостаточное решение):

Печать из Google Apps Script

var contextauth=false;

function cloudPrint_(strrange,portrait,size) {
  var searchAnswer = invokeCloudPrint_("search");
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var rangess = ss.getRange(strrange);
  var gid = rangess.getSheet().getSheetId();
  var r1=rangess.getRow()-1;  
  var c1=rangess.getColumn()-1;  
  var r2=r1 rangess.getHeight();
  var c2=c1 rangess.getWidth();
  
  portrait = typeof portrait !== 'undefined' ? portrait : true;
  size = typeof size !== 'undefined' ? size : 0;
  
  var docurl="https://docs.google.com/spreadsheets/d/" SpreadsheetApp.getActiveSpreadsheet().getId() "/export?format=pdf&size=0&fzr=false&portrait=" portrait "&fitw=true&gid=" gid "&r1=" r1 "&c1=" c1 "&r2=" r2 "&c2=" c2 "&ir=false&ic=false&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&attachment=true";
  var prop = PropertiesService.getUserProperties();
  var printer = prop.getProperty("printer");
  if (printer == null) {
    selectPrinterDlg(strrange,portrait,size);
    return;
  }
  ss.toast("Printing...");
  var drivefile = DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId());
  var oldaccess = drivefile.getSharingAccess();
  var oldpermission = drivefile.getSharingPermission();
  drivefile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
  var payload={
    printerid: printer,
    xsrf: searchAnswer.xsrf_token,
    title: rangess.getSheet().getName(),
    ticket: "{"version": "1.0","print": {}}",
    contentType: "url",
    content: docurl
  };
  var printstatus = invokeCloudPrint_("submit",payload);
  drivefile.setSharing(oldaccess, oldpermission);
  Browser.msgBox(printstatus.message);
}

function selectPrinterDlg(strrange,portrait,size) {
  var searchAnswer = invokeCloudPrint_("search");

  var ui = UiApp.createApplication();
  var panel = ui.createVerticalPanel();
  var lb = ui.createListBox(false).setId('lb').setName('lb');
  strrange = typeof strrange !== 'undefined' ? strrange : "";
  portrait = typeof portrait !== 'undefined' ? portrait : "";
  size = typeof size !== 'undefined' ? size : "";
  var hidden1 = ui.createTextBox().setVisible(false).setValue(strrange).setId("range").setName("range");
  var hidden2 = ui.createTextBox().setVisible(false).setValue(portrait.toString()).setId("portrait").setName("portrait");
  var hidden3 = ui.createTextBox().setVisible(false).setValue(size.toString()).setId("printsize").setName("printsize");
  for (var i in searchAnswer.printers) {
    var connPrinter = searchAnswer.printers[i];
    lb.addItem(connPrinter.displayName, connPrinter.id);
  }
  var button = ui.createButton("Save");
  var handler = ui.createServerHandler("SavePrinter_").addCallbackElement(panel);
  button.addClickHandler(ui.createClientHandler().forEventSource().setEnabled(false).setText("Saving..."));
  button.addClickHandler(handler);
  panel.add(lb).setCellHorizontalAlignment(button, UiApp.HorizontalAlignment.CENTER);
  panel.add(hidden1);
  panel.add(hidden2);
  panel.add(button);
  ui.add(panel);
  SpreadsheetApp.getUi().showModalDialog(ui, "Select printer");
  return;
}

function clear() {
  PropertiesService.getUserProperties().deleteProperty("printer");
  ScriptApp.invalidateAuth();
}

function SavePrinter_(e) {
  var ui = UiApp.getActiveApplication();
  PropertiesService.getUserProperties().setProperty("printer", e.parameter.lb);
  ui.close();
  if (e.parameter.range != "")
    cloudPrint_(e.parameter.range,e.parameter.portrait == "true",parseInt(e.parameter.printsize));
  return ui;
}

function invokeCloudPrint_(method,payload) {
  var baseurl = "https://www.google.com/cloudprint/";
  var options = {
    method: "post",
    muteHttpExceptions: true,
    oAuthServiceName: "print",
    oAuthUseToken: "always"
  };
  if (payload != undefined)
    options.payload = payload;
  authorize_();
  var response = UrlFetchApp.fetch(baseurl method,options);
  if (response.getResponseCode() == 403) {
    Browser.msgBox("Please authorize me to print!");
  }
  return JSON.parse(response.getContentText());
}

function validate() {
  var searchAnswer = invokeCloudPrint_("search");
}

function authorize_() {
  if (contextauth)
    return;
  var oauthConfig = UrlFetchApp.addOAuthService("print");
  oauthConfig.setConsumerKey("anonymous");
  oauthConfig.setConsumerSecret("anonymous");
  oauthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope=https://www.googleapis.com/auth/cloudprint");
  oauthConfig.setAuthorizationUrl("https://accounts.google.com/OAuthAuthorizeToken");    
  oauthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
  contextauth = true;
}

function onOpen() {
  SpreadsheetApp.getUi().createMenu("Printing").addItem("Select printer...", "selectPrinterDlg").addToUi();
}

function Print() {
  cloudPrint_("A1:D12",true);
}

В дополнение к разобранным фрагментам кода добавлен диалог (и пункт меню) для выбора принтеров. Рекомендации по установке:

  1. Вперед: Настройте Google Cloud Print, протестируйте печать
  2. Создайте новую таблицу Google, введите что-нибудь в диапазоне A1:D12
  3. Откройте Script Editor, создайте новый пустой проект
  4. Скопируйте код, сохраните, вызовите validate – для утверждения всех необходимых разрешений
  5. Вызовите функцию Print. При первом вызове открывается диалоговое окно выбора принтера на вкладке Таблица
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector