Automate user creation using google app script in Google Admin SDK - javascript

I want to automate user creation in google as an Admin where I use app script to do it, however from the documentation I'm reading I'm not quite sure if I'm doing it right since I'm getting some errors in my code, like after POST and the Script not working.
function createUsers() {
const userjson = {
"primaryEmail": "atest#example.com",
"name": {
"givenName": "afirstName",
"familyName": "alastName"
},
"suspended": false,
"password": "pass2022",
"hashFunction": "SHA-1",
"changePasswordAtNextLogin": true,
"ipWhitelisted": false,
"orgUnitPath": "myOrgPath",
};
const optionalArgs = {
customer: 'my_customer',
orderBy: 'email'
};
POST https://admin.googleapis.com/admin/directory/v1/users
try {
const response = AdminDirectory.Users.list(optionalArgs);
const users = response.users;
//check if user exists
if (!users || users.length === 0)
//create new user
return AdminDirectory.newUser(userjson);
// Print user exists
Logger.log('User Existing');
} catch (err) {
// TODO (developer)- Handle exception from the Directory API
Logger.log('Failed with error %s', err.message);
}
}

As per the official documentation, if you want to do it with Google Apps Script, you should format your code as follows:
function createUsers() {
const userInfo = {
"primaryEmail": "jvd#domain.com",
"name": {
"givenName": "Jackie",
"familyName": "VanDamme"
},
"suspended": false,
"password": "thisisasupersecret",
"changePasswordAtNextLogin": true,
"ipWhitelisted": false
};
try{
AdminDirectory.Users.insert(userInfo);
console.log("User added");
} catch(error){
const {code, message} = error.details;
if(code === 409 && message === "Entity already exists."){
console.log("User already exists");
} else {
console.log(`${code} - ${message}`);
}
}
}
If you have any doubts about how to use the user resource payload, please refer to the official documentation of the REST API.

Related

Cypress doesn't stub my requests when using fixtures

I am trying to create e2e tests using Cypress for my Angular application. So far I managed to get the basics sorted, now I am trying to stub network requests.
I have created some fixtures and created a custom command:
Cypress.Commands.add('login', (email, password, happy = false) => {
let auth_url = Cypress.env('auth_url');
console.log(auth_url);
cy.get('[data-cy=email]').as('email');
cy.get('[data-cy=password]').as('password');
cy.get('[data-cy=login-form]').as('form');
cy.location('pathname').should('equal', '/login');
cy.get('#email').type(email);
cy.get('#password').type(password);
cy.get('#form').submit();
cy.fixture(happy ? 'successful-login.json' : 'failed-login.json').then((json) => {
console.log(json);
cy.intercept(`${auth_url}/connect/token`, json).then(() => {
if (!happy) return;
cy.fixture('current-user.json').then((currentUser) => {
console.log(currentUser);
cy.intercept(`/users/**`, currentUser);
});
});;
});
});
My fixtures are:
successful-login.json:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRGNEVBQzE4N0Y5QUM1MTE4NjhFNTQ5OTA5RUIzOEQxIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2MTYwMDgxNTksImV4cCI6MTYxNjAxMTc1OSwiaXNzIjoiaHR0cHM6Ly9zeHAtZGV2ZWxvcC1pZGVudGl0eS5henVyZXdlYnNpdGVzLm5ldCIsImF1ZCI6WyJzeHAiLCJpZGVudGl0eS1zZXJ2ZXIiXSwiY2xpZW50X2lkIjoiY2xpZW50Iiwic3ViIjoiYTIzM2Q0MDgtMjVjMi00ODZhLWFlMzgtOTMzMTk5YjU2OWRkIiwiYXV0aF90aW1lIjoxNjE2MDA4MTU4LCJpZHAiOiJsb2NhbCIsInJvbGUiOiJBZG1pbmlzdHJhdG9yIiwicGVybWlzc2lvbiI6WyJ1c2VyczpyZWFkIiwidXNlcnM6d3JpdGUiXSwianRpIjoiQTRDNjREMzk0RTcyNEY3QUE1NzRFQUNEMjA2ODM4RkIiLCJpYXQiOjE2MTYwMDgxNTksInNjb3BlIjpbImlkZW50aXR5OnJlYWQiLCJpZGVudGl0eTp3cml0ZSIsInN4cDpyZWFkIiwic3hwOndyaXRlIl0sImFtciI6WyJwd2QiXX0.e-TX3u3o8UJZ9nq7nyuMFWfRyjEh55CwWQSHhfFxt677_qCu6pJ1cuHHOMjMV0lc-hTXjbe-4lZ7oOVfOZA_gByFo6mFpq8co__Npj1YpMt18LOSuewspKldffgCZQm2wIKTqSmMIQoFDRoUmAmcBsbJZIqSx4KMYBz7OfsBmdU7TeNi8bjtLcglzBxgYko7njJuC9j1EarR9BC-tjPIb0eoROclfQlPcYb05T4RRMzi3dpFExEXzFMaiMnR8_q0VOPWzeL0phFcjm-r1nVTVvrRcCtvI3GPPxr5EshT4XHcg6pmxx8BUlWXI6u1gSnWShmvXP5n87HJTCjsJh8sEQ",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "identity:read identity:write sxp:read sxp:write"
}
failed-login.json
{ "error": "invalid_grant", "error_description": "invalid_username_or_password" }
And finally, current-user.json:
{
"success": true,
"failure": false,
"error": null,
"result": {
"jobTitle": null,
"image": null,
"createdBy": "00000000-0000-0000-0000-000000000000",
"updatedBy": "00000000-0000-0000-0000-000000000000",
"dateCreated": "2021-02-26T11:23:18.074899",
"dateUpdated": "2021-02-26T11:23:18.0749379",
"deleted": false,
"roles": null,
"id": "a233d408-25c2-486a-ae38-933199b569dd",
"emailConfirmed": true,
"concurrencyStamp": "0246797d-fd93-4723-a142-95d5213f9ec7",
"phoneNumber": null,
"phoneNumberConfirmed": false,
"twoFactorEnabled": false,
"lockoutEnd": "2021-03-17T16:04:59.7781333+00:00",
"lockoutEnabled": true,
"accessFailedCount": 0
},
"message": null
}
The spec file looks like this:
/// <reference types="Cypress" />
describe('login workflow', () => {
it('does not work with wront credentials', () => {
const email = 'user#example.com';
const password = 'test';
cy.visit('/');
cy.login(email, password).as('loginRequest').then(() => {
cy.contains('.mat-simple-snackbar span', 'Invalid username or password.');
});
});
it('happy path test', () => {
const email = 'user#example.com';
const password = 'test';
cy.visit('/');
cy.location('pathname').should('equal', '/login');
cy.login(email, password, true).as('loginRequest').then(() => {
cy.location('pathname').should('equal', '/');
});
});
});
The issue I have is that even though the tests both say the routes are being stubbed:
The actual request, isn't:
The first test passes because the username and password are incorrect, even without stubbing the response, but the second test fails:
Because it doesn't stub the response:
Does anyone know what I am doing wrong?
Having a new intercept set up inside the .then() of a previous intercept seems like it might be a problem. There's nothing executing after that last intercept that would trigger it.
Since intercepts should be set up before the trigger occurs, the following should be (nearly) logically equivalent,
Cypress.Commands.add('login', (email, password, happy = false) => {
cy.intercept(`/users/**`, { fixture: 'current-user.json' });
const auth_url = Cypress.env('auth_url');
const loginFixture = happy ? 'successful-login.json' : 'failed-login.json';
cy.intercept(`${auth_url}/connect/token`, { fixture: loginFixture });
cy.get('[data-cy=email]').as('email');
cy.get('[data-cy=password]').as('password');
cy.get('[data-cy=login-form]').as('form');
cy.location('pathname').should('equal', '/login');
cy.get('#email').type(email);
cy.get('#password').type(password);
cy.get('#form').submit();
});
The only difference is the /users intercept is set up even if the auth intercept fails, but you are controlling that outcome anyway (with happy), so this should produce the same result

Shared files can't access(get list of shared file) using drive.file scope Google Drive API

The file is shared success and the shared user gets an email notification, file display in the user google drive but when we try using API to get shared files, it is not working.
var SCOPES = ["https://www.googleapis.com/auth/drive.file", "profile"];
function createPermissions(fileId, body) {
gapi.client.load("drive", "v3", function() {
gapi.client.drive.permissions
.create({
fileId: fileId,
resource: body
})
.then(function(res) {
//console.log(res);
Swal.fire("Success!", "File has been success shared!", "success");
// do something
})
.catch(function(err) {
//console.log(err);
Swal.fire({
icon: "error",
title: "Oops...",
text: "Something went wrong! Plese try agian later!!",
footer: ""
});
// do something
});
});
}
The above code is working fine, the file is successfully shared but when shared user login in-app user can't access shared files.
Anyone please suggest/help to fix the above issue?
Thanks
I would suggest you call the Drive API in this way:
// This is a good scope for testing
const SCOPES = ["https://www.googleapis.com/auth/drive"];
// This code takes into consideration that you already did all the OAuth2.0 proccess
// correctly to connect to the Drive API
module.exports.init = async function (){
// Create the Drive service
const drive = google.drive({version: 'v3', oauth2Client});
// Create permissions for an user
await createPermissions(drive, null, null);
}
// This function will create the permissions to share a file using Promises
function createPermissions(drive, fileId, body){
// These parameters are for test, past the values you want as arguments
fileId = fileId || "your-file-id";
body = body || {
"role": "writer",
"type": "user",
"emailAddress": "user#domain"
};
// Create the promise and return the value from the promise if you want to
return new Promise((resolve, reject) => {
try {
// Call the endpoint, if there are no errors you will pass the results to resolve
// to return them as the value from your promise
return drive.permissions.create({
fileId: fileId,
resource: body
},
(err, results) => {
if(err) reject(`Drive error: ${err.message}`);
resolve(results);
});
} catch (error) {
console.log(`There was a problem in the promise: ${error}`);
}
});
}
I tried it and the files are shared successfully to the user I wanted. Keep in mind to build your body as:
{
"role": "writer",
"type": "user",
"emailAddress": "user#domain"
};
Docs
Here are some links to know more about the Drive API Permissions:
Permissions.
Permissions: create.

react native TypeError: Cannot read property 'navigation' of undefined

I am using the FacebookAuthProvider by firebase to login my users from my platform.
I'm using react native in expo with firestore and it was working fine till I tried to add in some checks to redirect users to the correct screens after login. There are two different roles (administrators and users) which have to be separate right after the login.
if (/* user is administrator */) {
this.props.navigation.navigate('Admin');
} else {
this.props.navigation.navigate('Main');
}
After adding this method to separate users by there roles, I got this error:
react native TypeError: Cannot read property 'navigation' of undefined
Later I will add some more details (log files etc. as soon as I've learned how to grep them from my locale machine).
For better understanding I put my whole code here (sorry for the bad indentations which lesses the readability):
const auth = firebase.auth();
const firebaseUser = '';
const usersRef = firebase.firestore().collection('users');
async handleFacebookButton() {
const { type, token, } = await Facebook.logInWithReadPermissionsAsync(FACEBOOK_APP_ID, {
permissions: ['public_profile', 'email']
});
if (type === 'success') {
//Firebase credential is created with the Facebook access token.
const credential = firebase.auth.FacebookAuthProvider.credential(token);
auth.signInAndRetrieveDataWithCredential(credential)
.then(function(userCredential) {
newUserCheck = userCredential.additionalUserInfo.isNewUser;
console.log('newUserCheck = ', newUserCheck)
});
this.setState({loggedIn: "You are signed in"})
this.setState({signedIn: true})
console.log('you are signed in');
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
firebaseUser = {name: user.displayName, uid: user.uid, email: user.email}
console.log(firebaseUser.name, ' and ', firebaseUser.uid);
var existingRef = usersRef.doc(firebaseUser.uid);
existingRef.get().then(function(documentSnapshot) {
// check if user is registered
if(documentSnapshot) {
data = documentSnapshot.data();
console.log('existing user exists!!');
// check if user is an administrator
if (data.administrator == true) {
console.log('existing administrator exists!!');
this.props.navigation.navigate('Admin');
} else { this.props.navigation.navigate('Main');
}
}
});
(error => {
console.log('user not accessed: ', error);
});
//User is not yet in firebase database and needs to be saved
// double check that user is a new user
if (newUserCheck == true) {
this.ref
.doc(uid)
.set({
id: firebaseUser.uid,
username: firebaseUser.name,
email: firebaseUser.email,
})
this.props.navigation.navigate('ChooseRoute')
}
}
})
}
// If login type is not success:
(error => {
this.setState({loggedIn: "Login failed: log in again"})
this.setState({ errorMessage: error.message });
});
}
I fixed it!! 3 days later - it was a binding issue - after several unsuccessful attempts to work out which were the right parts of the functions to bind I converted both 'auth().onAuthStateChanged' and 'documentSnapshot' into fat arrow functions and the errors are gone!! Thank goodness for ES6...! Hope this helps someone else down the line...

How to handle multiple errors in promise chain?

I'm using AWS Amplify for authentication and Stripe for the payment to create sign up page.
PROBLEM: I can't find a way to combine validations for Email and password section(from AWS Amplify) with payment info section(from Stripe).
My current code creates a Stripe token and call API(with valid payment info) then handles the error message from userSignupRequest which takes care of email and password fields.
How do I validate the email and password with payment info then create account in AWS and Stripe?
// Stripe payment process
this.props.stripe.createToken(
{
email: this.state.email
}
).then(result => {
// PROBLEM: Form server validation from Stripe
if(result.error){
return this.setState({ errors: { errorMsg: result.error.message }, isLoading: false })
}
// if success, create customer and subscription with result.token.id
const apiName = 'NameOfAPI';
const path = '/stripe/signup';
let myInit = {
body: {
"stripeToken": result.token.id,
"email": this.state.email
}
}
API.post(apiName , path, myInit).then(reponse => {
this.props.userSignupRequest(this.state.email, this.state.password, reponse).then(user => {
this.setState({
confirmAccount: true,
isLoading: false,
userEmail: this.state.email,
errors: {}
})
this.props.history.push('/signup#confirm-account')
}).catch(err => {
// PROBLEM: Form server validation
this.setState({ errors: { errorMsg: err.message }, isLoading: false })
})
}).catch(err => {
console.log(err)
this.setState({ errors: { errorMsg: err }, isLoading: false })
});
})
It seems like we have a very similar stack. My solution was to handle everything server-side. You'll need to give your lambda functions the appropriate IAM permissions to access Cognito. The code below is a little long. I use async/await, which really cleans things up for me. You'll need to use Lambda with node 8 to use async/await though.
I validate that everything matches the right format client-side (i.e. emails are really emails, passwords are the right length). I realized the only error that could come up is an "existing user" error from Cognito. The idea is: test if the user exists before you attempt to sign the person up with Stripe. There's no way to "test" if the user's credit card is valid with Stripe. It's all or nothing. If it's valid it will go through, if not, you'll get an error. If it goes through, you can then sign up the user with Cognito, knowing you should not get an error (you've validated the email and password client-side and, you know the use doesn't already exist).
For reference, here's the aws-sdk for cognito.
const AWS = require('aws-sdk');
const cognito = new AWS.CognitoIdentityServiceProvider({
region: "region",
userPoolId: "cognito_user_pool_id",
});
module.exports.signUpUser = (payload) => {
const usernamePayload = {
UserPoolId: "cognito_user_pool_id",
Username: payload.email,
};
// I use emails for usernames.
new Promise((resolve, reject) => {
cognito.adminGetUser(usernamePayload, (error, response) => {
if (error && error.code === 'UserNotFoundException') {
resolve(false);
} else if (error) {
reject(error);
} else {
// if adminGetUser doesn't fail, it means the username exists
resolve(true);
}
});
}).then((usernameExists) => {
if (!usernameExists) {
// run stripe API stuff
// always run before sign up below to catch stripe errors
// and return those errors to client
// before you sign up the user to Cognito
// since you've already verified the user does not exist
// it would be rare for an error to come up here
// as long as you validate passwords and emails client-side
const signUpPayload = {
ClientId: "cognito_user_pool_client_id",
Username: payload.email,
Password: payload.password,
UserAttributes: [
{
Name: 'email',
Value: payload.email,
},
],
};
new Promise((resolve, reject) => {
cognito.signUp(signUpPayload, (error, response) => {
if (error) {
reject(error);
} else {
resolve(response);
}
});
}).catch((error) => {
// you should hopefully encounter no errors here
// once you get everything setup correctly
console.log(error);
})
} else {
// means username already exists, send error to client
// saying username exists
}
}).catch((error) => {
// may want to dispatch this error to client
console.log(error);
});
return null;
};

Create gist on github with User ID using Node

I'm trying to create a gist on github.com using the user ID. Currently I can create anonymous gist with the node-github module.
This is the code
github.gists.create({
"description": "the description for this gist",
"public": true,
"files": {
"BONE101TEST_2.md": {
"content": "<html><h1>This is a Test!</h1><b>Hello</b><img src=></html>"
}
}
}, function(err, rest) {
console.log(rest);
});
According to the github documentation " to read or write gists on a user’s behalf the gist OAuth scope is required." This will give me the tokens for the user.
But how do I specify that I want that the gist has to be created using the user X. I'm reading the node-githu documentation but doesn't tells me this. Any idea?
Updated
I can create a programatic token according to the docs. Still not sure how to identify the id of the user for creating the gist, if the create method doesn't make reference to it.
github.authorization.create({
scopes: ["user", "public_repo", "repo", "repo:status", "gist"],
note: "what this auth is for",
note_url: "http://url-to-this-auth-app",
headers: {
"X-GitHub-OTP": "two-factor-code"
}
}, function(err, res) {
if (res.token) {
//save and use res.token as in the Oauth process above from now on
}
});
In one of the links you share with me had the answer. Just modify it.
Here's the code if someone needs it.
http.createServer(function(req, res) {
var url = Url.parse(req.url);
var path = url.pathname;
var query = querystring.parse(url.query);
if (path == "/" || path.match(/^\/user\/?$/)) {
// redirect to github if there is no access token
if (!accessToken) {
res.writeHead(303, {
Location: oauth.getAuthorizeUrl({
redirect_uri: 'http://localhost:3000/github-callback',
scope: "user,repo,gist"
})
});
res.end();
return;
}
// use github API
github.gists.create({
"description": "the description for this gist",
"public": true,
"files": {
"TEST_2.md": {
"content": "<html><h1>This is a Test!</h1><b>Hello</b><img src=></html>"
}
}
}, function(err, rest) {
console.log(rest);
});
return;
}
// URL called by github after authenticating
else if (path.match(/^\/github-callback\/?$/)) {
// upgrade the code to an access token
oauth.getOAuthAccessToken(query.code, {}, function (err, access_token, refresh_token) {
if (err) {
console.log(err);
res.writeHead(500);
res.end(err + "");
return;
}
accessToken = access_token;
// authenticate github API
github.authenticate({
type: "oauth",
token: accessToken
});
//redirect back
res.writeHead(303, {
Location: "/"
});
res.end();
});
return;
}
res.writeHead(404);
res.end("404 - Not found");
}).listen(3000);

Categories

Resources