«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.
- Отправляет пользователя на страницу с запросом на аутентификацию.
- Получили ответ с кодом на перенаправленный URL.
- Получили маркер с кодом для доступа к услугам.
Проблема возникает именно с редиректом, поскольку каждый скрипт имеет в облаке уникальный идентификатор, и URL редиректа должен соответствовать этому идентификатору. Поэтому, в тиражируемом решении, есть такие варианты:
Все эти методы являются либо внутренней разработкой, которая стоит на втором месте, либо на третьем, что не очень удобно для них самих. На самом деле, ничто в архитектуре oAuth не указывает на то, что ситуация может измениться. Первый вариант, или второй, если клиент согласен предоставить доступ к своей учетной записи или создать нейтральную новую, – вот что я бы посоветовал для повторяемого решения.
Учитывая, что я не писал второй вариант, а только обдумывал его, приведу пример кода первого варианта. Второй вариант идентичен первому в том, что client_id генерируется клиентом или разработчиками.
Шаг 1. создаем client_id
- Откройте Google Developer Console и создайте новый проект.
- Перейдите в APIs&auth ->Credentials, нажмите на Create a new client ID.
- Тип – веб-приложение; Разрешенные источники JavaScript – script.google.com/; Разрешенные URI перенаправления – найти URL редактора сценария для нашего сценария, не включая /edit, а затем добавить /usercallback в конец.
Обычно в результате должно получиться что-то вроде этого:
Шаг 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()
) и скопируйте адрес этого окна (не закрывайте окно до получения подтверждения! ):
В скопированном 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 исчезает. Как вы можете ее избежать?
- Оказывается, Google Cloud Print знает, как распечатать электронную таблицу Google. Вы можете переместить выделение в новую электронную таблицу и дать команду печати.
- Более элегантный способ: в меню Google Spreadsheet есть опция “Загрузить как…” с возможностью выбора формата PDF. И этот вариант, в отличие от преобразования через Google Apps Script, работает.
Браузер выбирает второй вариант, щелкая по уникальной ссылке. Введите следующий код для создания PDF из переданного диапазона электронной таблицы:
Однако в коде есть две проблемы, которые не позволяют ему работать. Во-вторых, при попытке передачи файла происходит сбой oAuth 1.0 (привет, ошибки сценариев Google Apps). Во-вторых, URL-адрес для загрузки файла не может быть доступен, а контекст аутентификации сценария не совпадает с контекстом пользователя, вызвавшего сценарий.
Как это работает? – После завершения печати откройте электронную таблицу для “внешнего мира” на время печати. Но в этом случае вам не нужно предоставлять Google Cloud Print URL-адрес загрузки:
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. Редирект пойдет назад в указанную нами функцию:
Шаг 3. получение oauth token и вызов google cloud print
После ответного звонка мы прибываем в город.
getAuthResponse()
. Давайте напишем этот метод и используем полученный токен для вызова одного из методов Google Cloud Print.
Часть 3. итоги
В итоге, после путешествия по лабиринту багов и проблем, печать заработала. Привожу полный код с oAuth 1.0 (как самодостаточное решение):
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);
}
В дополнение к разобранным фрагментам кода добавлен диалог (и пункт меню) для выбора принтеров. Рекомендации по установке:
- Вперед: Настройте Google Cloud Print, протестируйте печать
- Создайте новую таблицу Google, введите что-нибудь в диапазоне A1:D12
- Откройте Script Editor, создайте новый пустой проект
- Скопируйте код, сохраните, вызовите validate – для утверждения всех необходимых разрешений
- Вызовите функцию Print. При первом вызове открывается диалоговое окно выбора принтера на вкладке Таблица