Understanding apps script api calls? - javascript

This script works. It has user id 4 which I am adding their email address to check the google admin API. The resolved column[10] is where managers approve requests. Because some of these usernames are not correctly entered, I was looking for a way to check if they were actually correct user ids. Both .setValue() lines work under try and catch, they also error on same users. I am trying to understand where the actual validation is happening. I guess I am trying to figure how the script knows to check the primary email address? Hope that makes sense.
function getNames() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getActiveSheet();
var values = sheet.getDataRange().getValues();
for(var i = 1; i < values.length; i++){
var data = values[i];
var resolved = data[10];
if(resolved === ""){
try{
var email = sheet.getRange(1+i,4).getValues() + '#buisness.com'
var user = AdminDirectory.Users.get(email);
var name = user.name.fullName;
sheet.getRange(1+i, 5).setValue('Yes this is an employee');//How does this work?
//sheet.getRange(1+i, 5).setValue(name);//This works which I expect
}
catch(errors){
sheet.getRange(1+i,5).setValue(errors);
}
}
}
}

The validation happens through the AdminDirectory.Users.get() function with the help of the try and catch statements.
Admin SDK Directory Service/Get User
This API function gets a user by their email address. If the email address exists, all their data will be logged as a JSON string. Otherwise, it will return an error.
Try and Catch
The try and catch statements belong under JavaScript Errors. The try statement will run a code block that you place in it. If it encounters any error, it will trigger the catch statement (which usually displays the error messages.
Your Code
Your code checks for the validity of the email address with the use of the AdminDirectory.Users.get() function inside the try statement. If the function fails, it returns an error which triggers the catch statement (which usually displays the error messages).
References:
Admin SDK Directory Service/Get User
JavaScript Errors

Related

Unexpected error on UrlFetchApp.fetch in Google Apps Script using basic authentication

I have the following code in Google Apps Script which retrieves CSV data from a webpage via HTTP using basic authentication and places it into a spreadsheet:
CSVImport.gs
function parseCSVtoSheet(sheetName, url)
{
// Credentials
var username = "myusername";
var password = "mypassword";
var header = "Basic " + Utilities.base64Encode(username + ":" + password);
// Setting the authorization header for basic HTTP authentication
var options = {
"headers": {
"Authorization": header
}
};
// Getting the ID of the sheet with the name passed as parameter
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
var sheetId = sheet.getSheetId();
// Getting the CSV data and placing it into the spreadsheet
var csvContent = UrlFetchApp.fetch(url, options).getContentText();
var resource = {requests: [{pasteData: {data: csvContent, coordinate: {sheetId: sheetId}, delimiter: ","}}]};
Sheets.Spreadsheets.batchUpdate(resource, spreadsheet.getId());
}
This has been working up until recently where randomly I get the following error on the UrlFetchApp.fetch line:
Exception: Unexpected error: http://www.myurl.com/data/myfile.csv (line 21, file "CSVImport")
I have tried:
Putting the credentials directly in the URL instead of in an Authorization header (I received a different error saying "Login information disallowed").
Encoding the credentials to base64 right when I pass it into the headers object (didn't work, same error).
Removing authentication altogether (predictably I received a 401 response from the HTTP page).
I'm not sure what else to try and why this randomly broke down all of a sudden. Any advice?
This is related to a new bug, see here
Many users are affected, I recommend you to "star" the issue to increase visibility and hopefully accelerate the process.
I had the same situation. At that time, I could noticed that when the built-in function of Google Spreadsheet is used for the URL, the values can be retrieved. In that case, as the current workaround, I used the following flow.
Put a formula of =IMPORTDATA(URL).
Retrieve the values from the sheet.
When above flow is reflected to your URL of http://www.myurl.com/data/myfile.csv, it becomes as follows.
About basic authorization for URL:
When I saw your script, I confirmed that you are using the basic authorization. In this case, the user name and password can be used for the URL like http://username:password#www.myurl.com/data/myfile.csv.
From your script, when the values of username and password are myusername and mypassword, respectively, you can use the URL as http://myusername:mypassword#www.myurl.com/data/myfile.csv.
Here, there is an important point. If the specific characters are included in username and password, please do the url encode for them.
Sample script:
function myFunction() {
const url = "http://myusername:mypassword#www.myurl.com/data/myfile.csv"; // This is your URL.
// Retrieve the values from URL.
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
sheet.clear();
var range = sheet.getRange("A1");
range.setFormula(`=IMPORTDATA("${url}")`);
// Retrieve the values from sheet to an array.
SpreadsheetApp.flush();
var values = sheet.getDataRange().getValues();
range.clear();
console.log(values)
}
When above script is run, the values from the URL are put to the sheet, and the values are retrieved as 2 dimensional array for values. If you want to leave only values without the formula, I think that you can copy and paste the values.
In this answer, I used IMPORTDATA. But for each situation, other functions might be suitable. In that case, please check them.
Note:
This is the current workaround. So when this issue was removed, I think that you can use your original script.
References:
IMPORTDATA
setFormula()
Disable Chrome V8 Runtime Engine until Google fix this.
To disable:
From Menu click on Run > Disable new Apps Script runtime powered by Chrome V8
As per #346 from the official issue tracker https://issuetracker.google.com/issues/175141974
hey guys I have found a possible solution that is working for me try
inputting empty {} like this
UrlFetchApp.fetch(apiLink, {});
it worked for me
I tried this, and it too is working for me. Works even when using the "new Apps Script runtime powered by Chrome V8".

Apply JavaScript Email Error Box to other elements

I have built a login system with LocalStorage on my website and would like to build an error message if I enter it incorrectly. Since I have already got help for the email error on another page, I would like to add the message that appears there to my other error messages. Is there a solution to apply the Email Error message to other elements or do I have to style and rebuild all messages? If there is a possibility I would like it (below in the code) for the functions "checkRegisterEnter" and "checkRegisterPassword" for the alert replacement. The email check can be seen below.
Javascript code:
function checkRegisterEnter(){}
if(givenname.value == 0){
alert("Name field is Empty!")
}
function checkRegisterPassword(){
if(password.value !== password2.value) {
alert('The first password does not match the second!')
}
}
//Email_Check
const checkrform = document.getElementById("register.form")[0];
const checkremail = document.getElementById("ri3");
let remailerror = checkremail;
while ((remailerror = remailerror.nextSilbing).nodeType != 1);
const remailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
function addEvent(remailelement,remailevent,callback){
let previousEventCallBack = remailelement["on"+remailevent];
remailelement["on"+remailevent] = function (e) {const remailoutput = callback(e);
}
};
(Translated with Google Translate, errors may be included.)
Edit: Problem has still not been solved. Would be helpful if someone knew the answer.
Errors in JavaScript can be displayed without the use of alert boxes but using the alert box is the traditional way to do that. We can show errors with two methods without using the alert box

FormApp.openById not working when i'm not collaborator

I'm creating a script that reads specific emails and retrieves data from them to create responses on a google form.
It is working as a charm when I have a collaborator access to the form, but it throw me this error message when I'm not...
"No item with the given ID could be found, or you do not have permission to access it"
var logEnvironment = "TEST"; // TEST for Testing environment, PRODUCTION for production
// Get Ids for the Google Form and Response Spreadsheet
if (logEnvironment == "TEST") {
var premediaFormId = <MY TEST FORM ID>
var responseWorkbookId = *******;
} else {
var premediaFormId = <MY PRODUCTION FORM ID>;
var responseWorkbookId = *******;
}
// Google Form
var premediaForm = FormApp.openById(premediaFormId);
var premediaFormItems = premediaForm.getItems();
On the production form, I can't give access to everybody running the script as collaborators.. they should have only regular access to create responses.. but we don't want the users to be entering the responses manually if we already have an email from a system with all the information.
Integrating the system with the form is out of the question.
Is there a way to resolve this access issue....

Lotus notes automation from browser

I have been trying to automate Lotus Notes mail fillup from a browser interface.
After refering to Richard Schwartz's answer, i came up with this piece of code using the Lotus.NotesSession class.
function SendScriptMail() {
var mToMail = document.getElementById('txtMailId').value
var mSub = document.getElementById('txtSubject').value
var mMsg = document.getElementById('txtContent').value
var Password = "yyy"
alert("1");
var MailFileServer = "xxx.com"
var MailFile = "C:\Program Files\IBM\Lotus\Notes\mail\user.nsf"
alert("2")
var Session;
var Maildb;
var UI;
var NewMail;
var From = "user#xxx.com"
try {
alert("3")
// Create the Activex object for NotesSession
Session = new ActiveXObject("Lotus.NotesSession");
alert("4")
if (Session == null) {
throw ("NoSession");
} else {
Session.Initialize(Password);
// Get mail database
Maildb = Session.GetDatabase(MailFileServer, MailFile);
alert("5")
if (Maildb == null) {
throw ("NoMaildb");
} else {
NewMail = MailDB.CreateDocument();
if (MailDoc == null) {
throw ('NoMailDoc');
} else {
// Populate the fields
NewMail.AppendItemValue("Form", "Memo")
NewMail.AppendItemValue("SendTo", mToMail)
NewMail.AppendItemValue("From", From)
NewMail.AppendItemValue("Subject", mSub)
NewMail.AppendItemValue("Body", mMsg)
NewMail.Save(True, False)
NewMail.Send(False)
}
}
}
} catch (err) {
// feel free to improve error handling...
alert('Error while sending mail');
}
}
But now, alerts 1,2,3 are being trigerrd, and then the counter moves to the catch block. The lotus notes session is not being started.
In a powershell script that I was previously looking at there was a code regsvr32 "$NotesInstallDir\nlsxbe.dll" /s that was used before the Session = new ActiveXObject("Lotus.NotesSession");. Is there something similar in javascript too, if so how do i invoke that dll.
I think I've realised where I am going wrong. According to me, upto alert("5") things are good. But since Lotus.NotesSession doesn't have a CreateDocument() method, it is throwing the error. I am not sure how to create the document and populate the values though.
Since you've chosen to use the Notes.NotesUIWorkspace class, you are working with the Notes client front-end. It's running, and your users see what's happening on the screen. Are you aware that there's a set of back-end classes (rooted in Lotus.NotesSession) instead of Notes.NotesSession and Notes.NotesUIWorkspace) that work directly with Notes database data, without causing the Notes client to grab focus and display everything that you're doing?
Working with the front-end means that in some cases (depending on the version of Notes that you are working with) you're not going to be working directly with the field names that are standard in Notes messages as stored and as seen in the back-end. You're going to be working with names used as temporary inputs in the form that is used to view and edit the message. You can see these names by using Domino Designer to view the Memo form.
Instead of using 'SendTo', try using:
MailDoc.Fieldsettext('EnterSendTo', mToMail)
Regarding the Body field, there's no temporary field involved, however you haven't really explained the difficulty you are having. Do you not know how to display the interface that you want in the browser? Do you not know how to combine different inputs into a single FieldSetText call? Or are you just dissatisfied with the fact that FieldSetText can't do any fancy formatting? In the latter case, to get more formatting capability you may want to switch to using the back-end classes, which give you access to the NotesRichTextItem class, which has more formatting capabilities.

Checking if an email is valid in Google Apps Script

I'm using the built-in api for scripting against Google Spreadsheets to send some booking confirmations, and currently my script breaks if someone has filled in an invalid email. I'd like it to just save some data to a list of guests that haven't been notified, and then proceed with looping through the bookings.
This is my current code (simplified):
// The variables email, subject and msg are populated.
// I've tested that using Browser.msgBox(), and the correct column values are
// found and used
// The script breaks here, if an incorrect email address has been filled in
MailApp.sendEmail(email, subject, msg)
According to the documentation the only two methods on the MailApp class are to send emails and check the daily quota - nothing about checking for valid email addresses - so I don't really know what criteria must be fulfilled for the class to accept the request, and thus can't write a validation routine.
If you need to validate email addresses beforehand, create a blank spreadsheet in your drive. Then, run the function below, changing the testSheet variable to point to the spreadsheet you created. The function will do a simple regex test to catch malformed addresses, then check if the address is actually valid by attempting to temporarily add it as a viewer on the spreadsheet. If the address can be added, it must be valid.
function validateEmail(email) {
var re = /\S+#\S+\.\S+/;
if (!re.test(email)) {
return false;
} else {
var testSheet = SpreadsheetApp.openById(arbitrarySpreadsheetInYourDrive);
try {
testSheet.addViewer(email);
} catch(e) {
return false;
}
testSheet.removeViewer(email);
return true;
}
}
regex from How to validate email address in JavaScript?
Stay calm, catch and log the exception and carry on:
try {
// do stuff, including send email
MailApp.sendEmail(email, subject, msg)
} catch(e) {
Logger.log("Error with email (" + email + "). " + e);
}
On the otherhand, avoid Checking email in script and get rid of loses quota or try-catch etc. I used that I got a valid email when user attempt to send an email, by signing him in an email and got that email:
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
String s = account.getEmail(); // here is the valid email.
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
}
}
Full procedure Here.
This answer is much later than this question was asked, but I piggy-backed off of remitnotpaucity's answer based on a comment in his answer. It does basically the same thing, adding the email to the spreadsheet and catching the error, however in my case it creates a new spreadsheet, attempts to add the user, and then after attempting to add the user, deletes the spreadsheet. In both cases, that the email is a valid email or not, it deletes the newly created spreadsheet.
Some things to note:
I am not as familiar with regular expressions, so I only check to see if the # symbol is within the email read into the function, and do not check for whitespaces.
I believe that even if it passes the first if-statement, even if it's not a valid email, an error will still be thrown and caught because Google will still catch that it's not a valid email, making the first if-statement redundant
If you are trying to validate an email outside your company, I'm unsure how it would react, so be fore-warned about that
This validation method takes a few seconds because you are creating and then deleting an email all within a single function, so it takes a fair bit longer than remitnotpaucity's
Most importantly, if you are able to, I would use an API. I believe that this one would work perfectly fine and should be free, it just may take some extra elbow-grease to get to work with GAS.
function validateEmail(email){
let ss = SpreadsheetApp.openByUrl(SpreadsheetApp.create('Email Validation Spreadsheet', 1, 1).getUrl())
if(!new RegExp('[#]').test(email)){
return false
} else{
try{
ss.addViewer(email)
} catch(e){
setTrashed()
return false
}
setTrashed()
return true
}
function setTrashed(){
DriveApp.getFilesByName('Email Validation Spreadsheet').next().setTrashed(true)
}
}

Categories