Create hyperlink in Telegram message sent by bot via script / google sheets - google-apps-script

My current script is:
function EnviarTelegram(botSecret, chatId, body) {
var response = UrlFetchApp.fetch("https://api.telegram.org/bot" + botSecret + "/sendMessage?text=" + encodeURIComponent(body) + "&chat_id=" + chatId + "&parse_mode=HTML");
}
The formula in Google Sheets I use to send the message is:
=EnviarTelegram("Code to Bot","Code to ChatId","Created Message")
I would like to be able to create the following message:
"Full list of games tomorrow
Click here to access"
In Click here to access I wish there was a hyperlink for example: www.google.com/testtesttesttest
Is there any way to be able to adjust the script or the text created for this?

In your query parameter, parse_mode=HTML is used. So I thought that in this case, HTML tags can be used for text. When you want to use =EnviarTelegram("Code to Bot","Code to ChatId","Created Message"), how about the following modification?
From:
=EnviarTelegram("Code to Bot","Code to ChatId","Created Message")
To:
=EnviarTelegram("Code to Bot","Code to ChatId","Full list of games tomorrow\n\n<a href='https://www.google.com/testtesttesttest'>Click here to access</a>")

Related

How to obtain initial OAuth2.0 code from browser?

I have made a javascript script in Google Apps Script, attached to a google sheet. I ultimately want to connect the Google Sheet to the Google Fit API and have my fitness data automatically inputted to the Google Sheet. At step 0, I made my Google Console project and OAuth2.0 client ID & secret. I am at step 1, where I need to obtain the authentication code from the initial 'GET' request.
My request is correct and I can send the request correctly using the callback notation; the code below is run in a callback in a timed for loop such that the html object (html_objet) remains active for a certain amount of time, waiting to get the code. I can see the code in the browser url when I have finished approving with the Google popup, but I do not know how to import this code value from the client browser(popup) into my javascript program. I open the client browser(popup) using :
var html_texte = '<html><head><script>'
+ 'const winRef = window.open("'+js2html_data+'");'
+ 'winRef ? google.script.host.close() : window.alert("Allow popup to redirect to url");'
+ 'window.onload=function(){document.getElementById("'+js2html_data+'").href ="'+js2html_data+'";};'
+ '</script></head><body>'
+ '</body></html>';
var html_objet = HtmlService.createHtmlOutput(html_texte).setWidth(90).setHeight(1);
html_objet.js2html_data = js2html_data;
SpreadsheetApp.getUi().showModalDialog(html_objet, "Opening ...");
This works. But, I can not do anything with the window once it is open (ie: reload the window, get the current url).
I tried modifying the html_texte variable to the text below, such that I can return the url of the authenticated page. It does not work, how can I update the js2html_data variable such that it shows the url of the final Google user authenticated page? Or, pass the url to another html variable (html2js_data) out to my javascript program?
var html_texte = '<html><head><script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>'
+ '<script>'
+ 'const winRef = window.open("'+js2html_data+'");'
+ 'winRef ? google.script.host.close() : window.alert("Allow popup to redirect to url");'
+ 'window.onload=function(){document.getElementById("'+js2html_data+'").href ="'+js2html_data+'";};'
// + '$(document).ready(function getUrl(){ document.getElementById("'+html2js_data+'").innerHTML=window.location.href; });'
+ '$(document).ready(function getUrl(){ document.getElementById("'+html2js_data+'").href=window.location.href; });'
//+ '$(document).ready(function getUrl(){ document.getElementById(<?="'+html2js_data+'"?>).href=window.location.href; });'
+ '</script></head><body>'
// + '<h3 id="html2js_data" onclick="getUrl()">OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO</h3>'
+ '<div id="html2js_data"></div>'
+ '</body></html>';
Any suggestions would be great...I tried a lot of things...

Limiting OAuth scope for Google App Script

I am trying to limit my OAuth scopes in my script that sends an email after a form has been submitted. I want to limit it so that it has the least permission needed. If I click run, it tries to authorize the correct permissions. If I set up the on form submit trigger, it wants to authorize read, change, delete on all spreadsheets and change on all forms.
If I give the script full access to sheets and forms, it runs as intended. I just want to reduce some of the permissions. The screenshot shows that it is asking for more permission than what is specified in the appsscript.json file.
This script is attached to the responses sheet generated from my form.
From my appsscript.json:
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/forms.currentonly",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
The code:
/**
* #OnlyCurrentDoc
*/
function onFormSubmit(e) {
var values = e.namedValues;
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
GmailApp.sendEmail(values['Recipient Email'],'SHOUT OUT!!!!!!','',
{from:'email#domain.com',
htmlBody:htmlBody});
}
Google Form/Sheet Questions/Columns
Timestamp
Name of Sender
Name of Recipient
Name of Recipient's Boss
Shoutout
Recipient Email
Recipient's Boss Email
OAuth Permissions Screenshot:
Project Details OAuth Scopes:
View your email messages and settings https://www.googleapis.com/auth/gmail.readonly
Send email on your behalf https://www.googleapis.com/auth/gmail.send
See, edit, create, and delete only the specific Google Drive files you use with this app https://www.googleapis.com/auth/drive.file
View and manage forms that this application has been installed in https://www.googleapis.com/auth/forms.currentonly
View and manage spreadsheets that this application has been installed in https://www.googleapis.com/auth/spreadsheets.currentonly
By default, See, edit, create, and delete all your Google Sheets spreadsheets is a required scope if you added an Installable Trigger that has event source of From Spreadsheet and View and manage your forms in Google Drive is also added if the event type is On form submit. This is to give script the access to the changes that may happen in the spreadsheet caused by submitting response. As a result, it will return the user an Event Object containing information about the context that caused the trigger to fire.
The script will also work if you manually press Run but there is no Event Object that will be passed to the function parameter.
You can try using Time-driven as event source and it will show the same scope as you declared in appsscript.json since the trigger doesn't need to access the spreadsheet to execute the trigger.
Example:
Time Driven:
From spreadsheet and On Open:
From spreadsheet and On form submit:
References:
Event Object
Installable Triggers
I believe your goal is as follows.
From your question, you want to restrict the scopes for your showing script of The code: as follows.
/**
* #OnlyCurrentDoc
*/
function onFormSubmit(e) {
var values = e.namedValues;
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
GmailApp.sendEmail(values['Recipient Email'],'SHOUT OUT!!!!!!','',
{from:'email#domain.com',
htmlBody:htmlBody});
}
It seems that when GmailApp.sendEmail of Gmail Service is used, the scope is constant as https://mail.google.com/. It seems that this is the current specification. So when you want to restrict the scopes, I think that you can achieve it using Gmail API. When your script is converted using Gmail API, it becomes as follows.
Modified script:
Before you use this script, please enable Gmail API at Advanced Google services.
/**
* #OnlyCurrentDoc
*/
// This is from https://stackoverflow.com/a/66088350
function convert_(toEmail, fromEmail, subject, textBody, htmlBody) {
const boundary = "boundaryboundary";
const mailData = [
`MIME-Version: 1.0`,
`To: ${toEmail}`,
`From: ${fromEmail}`,
`Subject: =?UTF-8?B?${Utilities.base64Encode(subject, Utilities.Charset.UTF_8)}?=`,
`Content-Type: multipart/alternative; boundary=${boundary}`,
``,
`--${boundary}`,
`Content-Type: text/plain; charset=UTF-8`,
``,
textBody,
``,
`--${boundary}`,
`Content-Type: text/html; charset=UTF-8`,
`Content-Transfer-Encoding: base64`,
``,
Utilities.base64Encode(htmlBody, Utilities.Charset.UTF_8),
``,
`--${boundary}--`,
].join("\r\n");
return Utilities.base64EncodeWebSafe(mailData);
}
function onFormSubmit(e) {
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
var raw = convert_(values['Recipient Email'], 'email#domain.com', 'SHOUT OUT!!!!!!', "", htmlBody);
Gmail.Users.Messages.send({raw: raw}, "me");
}
In this script, only tne scope of https://www.googleapis.com/auth/gmail.send can be used.
In this sample script, it supposes that e is the correct value you want to use. Please be careful about this.
Note:
About other scopes of "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/forms.currentonly", "https://www.googleapis.com/auth/spreadsheets.currentonly", when I saw your script, those scopes are not required to be used. But, when Google Form is used, https://www.googleapis.com/auth/forms.currentonly might be required to be used. Please be careful this.
For example, when you want to use other methods, please add the scopes for them. My answer is for your showing script in your question. Please be careful about this.
Reference:
Method: users.messages.send

How to take data from Google Sheet and create a pre-filled link to Google Form

So when generating a pre-fillend in link for a Google Form I have observed the following:
https://docs.google.com/forms/d/e/{Form ID}/viewform?usp=pp_url&entry.1686820921=Field1+Value&entry.551739295=Field2+Value&entry.1561066553=Field3+Value
Based on this example I created VIA the Google Form > Get pre-filled link, you can see how easy it would be to replace the values and generate this URL based on values pulled form a spreadsheet. Now when I try to do this there are some obvious complications like what if there is a space, what if there is a new line
Google Forms seems to have replaced a space with a + and a new line with a %0A, it does not seem to use the default encoded URL chr (shown below) as most forms use.
Space %20
" %22
< %3C
> %3E
# %23
% %25
| %7C
this is taken from :https://developers.google.com/maps/documentation/urls/url-encoding.
Is there a function or method that I can call to encode the value to a Google Form URL safe values?
Example
sheet.getRange(A1).getValue().someFunctionThatEncodes();
or
someFunctionThatEncodes(sheet.getRange(A1).getValue());
If not does anyone have a function they could share that I would pass a value to it and it would return the encode version that Google Forms requires?
FYI I have tested the encodeURIComponent() and it seems to go a little over kill on it and I get extra special CHRs that don't translate properly
For example, the following values are converted to the pre-filled link,
sample1 ' "<>#%|'
sample2 ' "<>#%|'
sample3 ' "<>#%|'
the following encoded link can be retrieved.
https://docs.google.com/forms/d/e/###/viewform?usp=pp_url&entry.1234567890=sample1+'+%22%3C%3E%23%25%7C'&entry.1234567891=sample2+'+%22%3C%3E%23%25%7C'&entry.1234567892=sample3+'+%22%3C%3E%23%25%7C'
When above link is decoded, it becomes as follows.
https://docs.google.com/forms/d/e/###/viewform?usp=pp_url&entry.1234567890=sample1 ' "<>#%|'&entry.1234567891=sample2 ' "<>#%|'&entry.1234567892=sample3 ' "<>#%|'
From above situation, as a sample script, when above values of sample1 ' "<>#%|', sample2 ' "<>#%|' and sample3 ' "<>#%|' are used for the pre-filled link of your URL, the script is as follows.
Sample script:
When you use this script, please set url and query as follows.
const url = "https://docs.google.com/forms/d/e/{Form ID}/viewform";
const query = {
"usp": "pp_url",
"entry.1686820921": `sample1 ' "<>#%|'`,
"entry.551739295": `sample2 ' "<>#%|'`,
"entry.1561066553": `sample3 ' "<>#%|'`,
}
// This script is from https://gist.github.com/tanaikech/70503e0ea6998083fcb05c6d2a857107
String.prototype.addQuery = function(obj) {
return this + Object.keys(obj).reduce(function(p, e, i) {
return p + (i == 0 ? "?" : "&") +
(Array.isArray(obj[e]) ? obj[e].reduce(function(str, f, j) {
return str + e + "=" + encodeURIComponent(f) + (j != obj[e].length - 1 ? "&" : "")
},"") : e + "=" + encodeURIComponent(obj[e]));
},"");
}
const endpoint = url.addQuery(query);
console.log(endpoint);
In this case, the value of query parameter is encoded by encodeURIComponent.
Reference:
encodeURIComponent()
encodeURIComponent would indeed do the trick if you use JS; if you use google sheets, you have ENCODEURL as a function, so you can do sth like =HYPERLINK(CONCAT("https://docs.google.com/forms/d/e/<some form id>/viewform?usp=pp_url&entry.<some entry id>=Option+2&entry.<some entry id>=",ENCODEURL(F14)))
You start with what you get from Get pre-filled link using field values like FFFIRSTNAMEEE (that are easy to spot). Then, just replace parts that shall be individual and make sure to use ENCODEURL. When also using HYPERLINK, links become click-able in the sheet as well.
Assuming you start out with https://docs.google.com/forms/d/e/``<some form id>/viewform?usp=pp_url&entry.<some entry id>=Option+2&entry.<some entry id>=AAANSWERRR - and apply above formula and put "hey there" into cell F14, you'd get https://docs.google.com/forms/d/e/<some form id>/viewform?usp=pp_url&entry.<some entry id>=Option+2&entry.<some entry id>=hey%20there

YouTube.Search.list ReferenceError

YouTube.Search.list in Google Apps Scripts shows this error: ReferenceError: "YouTube" is not defined (line 22).
Dashboard shows that the request went through each time I ran the code. Youtube Data API is enabled in Apps Script and Dev Console.
Any help appreciated on why I'm getting this error.
/*
YouTube RSS Feeds
Written by #user1535152 http://stackoverflow.com/q/30486682/512127
Based on http://www.labnol.org/internet/twitter-rss-feed/28149/
*/
function doGet(e) {
var title = ("Youtube RSS Feed for " + e.parameter.search),
timez = Session.getScriptTimeZone(),
search = encodeURIComponent(e.parameter.search),
link = ("https://www.youtube.com/results?search_query=" + search),
self = ScriptApp.getService().getUrl() + "?" + search;
var rss='<?xml version="1.0"?>';
rss+='<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">';
rss+='<channel><title>'+title+'</title>';
rss+='<link>'+link+'</link>';
rss+='<atom:link href="'+self+'" rel="self" type="application/rss+xml" />';
rss+='<description>' + title + ' updated on ' + new Date() + '.</description>';
var results = YouTube.Search.list('id, snippet', {
q: search,
maxResults: 50,
order: 'date'
});
for (var i = 0; i < results.items.length; i++){
var item = results.items[i];
rss += "<item>";
rss += "<title>" + item.snippet.title + "</title>";
rss += "<link>http://www.youtube.com/watch?v=" + item.id.videoId + "</link>";
rss += "<description>" + item.snippet.description + "</description>";
rss += "<pubDate>" + Utilities.formatDate(new Date(item.snippet.publishedAt), timez, "EEE, dd MMM yyyy HH:mm:ss Z") + "</pubDate>";
rss += "<guid>http://www.youtube.com/watch?v=" + item.id.videoId + "</guid>";
rss += "</item>";
}
rss+="</channel></rss>";
return ContentService.createTextOutput(rss).setMimeType(ContentService.MimeType.RSS);
}
From your question, it was found that "Youtube Data API is enabled in Apps Script and Dev Console.". But an error of ReferenceError: "YouTube" is not defined occurs, when the script is run. So please confirm a following setting.
In order to use YouTube.Search.list(), it requires not only enabling API at API console, but also enabling at Advanced Google Services. I confirmed that when YouTube Data API is OFF at Advanced Google Services, the same error occurs. In order to enable YouTube Data API at Advanced Google Services, please confirm as follows.
Open script editor that there is the script.
Click Resources -> Advanced Google Services.
Turn on YouTube Data API.
Click OK.
If YouTube Data API is "off", please turn on by clicking. After this, please try to run, again.
If this is not useful for you, I'm sorry.

How to have Google Sheets send an email based on key words from Google Form submission

I am new to this stuff, but have a question that I can't find an answer to. I am making a custom CRM system for my company. When a customer calls, the answering employee will fill out a google form. They have to pick a project manager from a list. When they submit the form, I want an email to be automatically sent to that project manager notifying him that he has a new customer that he needs to contact.
Thanks for your help. Please let me know any additional information I'd need to share to get this created in the Script for the sheet that populates with the results from the GForm.
Well, lets assume that your going to organize your form so that you will get responses in this order and with these headers
TimeStamp,ManagerName,CustomerName,Phone,EmailAddress,
function hookMeUpToFormSubmitTrigger(e)
{
var managerEmail={Brad:'email1#xxx.com',Eric:'email2#xxy.com'};//Could be drawn from contact sheets
var contactTime=Utilities.formatDate(new Date(e.namedValue.TimeStamp), Session.getScriptTimeZone(), "E MMM d, HHmm");
MailApp.sendEmail({to: managerEmail[e.namedValues.ManagerName],subect: 'New Customer: ' + e.namedValues.CustomerName,htmlBody: 'Just letting you know that ' + e.namedValues.CustomerName + ' called at ' + contactTime + ' They would like a call back at your ealiest convenient time. Their phone number is ' + e.namedValues.Phone + ' and their email address is ' + e.namedValues.EmailAddress + '.' });
}
You need to add email id in the dropdown. Then you need to create form bound script and then add below script. Once done you need to schedule a trigger for the below function on submit of form.
function collectResponse(e) {
try {
var itemResponses = e.response.getItemResponses();
var emailAddress = itemResponses[0].getResponse(); //change the index to match your email address dropdown
var customerInfo = itemResponses[1].getResponse(); //change the index to match your customer info input box
MailApp.sendEmail({
to: emailAddress,
subject: "New customer " + customerInfo,
//body: add if you want to send more details
})
} catch (e) {
Logger.log(e)
}
}