Calling javascript function on load pug - setting localStorage with param - javascript

What I am attempting to do is invoke a JS function from a pug template that will set an item on the localStorage. The value of this item will be a param that was passed to the pug template "token".
Similar questions have been asked in the past and I took inspiration from these answers as they seem to be similar:
Pug call js function from another file inside template
Express / Jade / Pug: Calling a javascript object's functions
My resulting code is:
users.js
import setToken from "../src/setToken";
router.post("/signin", (req, res) => {
...
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function(result) {
res.render("congrats", {
title: "Congrats",
token: result.getAccessToken().getJwtToken(),
setToken: setToken
});
},
onFailure: function(err) {
next(err);
}
});
});
setToken.js
export default (token) => {
console.log("::: setToken :::");
localStorage.setItem("cognitoToken", token);
};
congrats.pug
extends layout
block scripts
script
| var setToken = #{setToken};
| setToken(#{token})
block content
...
layout.pug includes a client-side JS script which also has a function storeToken. I have attempted to call that as well but nothing .
Nothing is output to the console and nothing is set in localStorage. I am unsure if this is the best way to even achieve this but it appears my JS is not even being executed.
Is it also best practice to pass this function reference through when rendering the template or to include it on the client?
EDIT
When looking in the markup, I can see that my JS is rendering correctly within the <script> of my template:
<script>
console.log("token: ", **token value**);
var setToken = function (token) {
console.log("::: setToken :::");
localStorage.setItem("cognitoToken", token);
};
setToken(**token value**)
</script>
EDIT 2
I have 4 pug pages that I load sequentially depending on the stage the user is at registering for Cognito. I have tested injecting JS into the other 3 templates and all of that code works fine. For example:
block scripts
script(type="text/javascript")
| var page = "confirm";
I can then call page in the console which prints out "confirm". I try the same variable declaration in my congrats.pug and returns undefined. So, I imagine, this has something to do with how I render the pages. Here's the comparison of 1 that works and the 1 that doesn't. I cannot see any difference here (extension of users.js):
/*
* Works
*/
router.post("/confirm", (req, res, next) => {
const { confirm } = req.body;
cognitoUser.confirmRegistration(confirm, true, function(err, result) {
if (err) {
next(err);
}
res.render("signin", {
title: "Signin"
});
});
});
//////////
/*
* Doesn't work
*/
router.post("/signin", (req, res) => {
const { username, password } = req.body;
const authenticationData = {
Username: username,
Password: password
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function(result) {
res.render("congrats", {
title: "Congrats",
token: result.getAccessToken().getJwtToken(),
setToken: setToken
});
},
onFailure: function(err) {
next(err);
}
});
});
//////////

In the end, for some reason it was the fact that I passed a function reference to my template the way I did. If I take that out, JS worked as it should.
Setting the token, I decided it was too much overhead & added complication to call a function in an external file so just did it directly within a <script> tag within the template. Here is my resulting working template:
extends layout
block scripts
script(type="text/javascript").
var token = "#{token}";
localStorage.setItem("cognitoToken", token);
block content
.container
.col-md-6.mx-auto.text-center
.header-title
h1.wv-heading--title= title
.row
.col-md-4.mx-auto
p You have successfully authenticated with AWS Cognito, your access token is
strong #{token}
Credit to this answer which showed me how to reference a pug param within a <script> tag

Related

Routing within an Angular function

I have a login function here that allows a user to login and will navigate to a certain component (changepw) based on whether a piece of firebase information (active flag) is true or false. Even though I read read the data fine, when it is false, I am not getting a redirection with this code. change pw and /changepw have been tried. Help!
login(email: string, password: string): void {
this.firebaseAuth.signInWithEmailAndPassword(email, password)
.then(value => {
var userId = value.user.uid;
this.db.database.ref(('users/' + userId)).get().then(value => {
var userInfo = value.toJSON();
console.log(userInfo['active'])
if ( userInfo == false ) {
this.router.navigate(['changepw']);
} else {
this.router.navigate(['']);
}
})
})
.catch(err => {
console.log('Something went wrong:', err.message);
alert(err.message);
});
}
if you have something like this in app-routing.module.ts
const routes : Routes = [
{path:"changepw",component abcComponent}
]
then you should add front slash in navigate
this.router.navigate(['/changepw']);
share Routes in appRouting module also share if you have any error in console
I am not sure if you have tried this approach or not
this.router.navigate(['/', 'changepw']);
What this does is, after the / it will append the changepw route.
Since this.router.navigate([]); is an array, you need to split the path if it has a / or something lke that .

yahooFinance module with sapper

I am making a project where I want to use darta from yahooFinance.
I have found this project https://www.npmjs.com/package/yahoo-finance.
I have also used the basic sapper template.
Basically what I am trying is to retrive data from YF and show them on the FE.
I gave this piece of code:
<script>
import yahooFinance from 'yahoo-finance';
let response;
async function searchStock (){
yahooFinance.historical({
symbol: 'AAPL',
from: '2020-01-01',
to: '2020-12-31',
}, function (err, quotes) {
console.log(quotes)
});
}
</script>
But everytime I try to compile I get:
Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
1: {
2: "version": "2020d",
^
3: "zones": [
4: "Africa/Abidjan|LMT GMT|g.8 0|01|-2ldXH.Q|48e5",
So I gave tried to import it thus way var yahooFinance = require('yahoo-finance');
But then I get Uncaught (in promise) ReferenceError: require is not defined in to the console.
You won't be able to use the yahoo-finance package on the front end, since it uses Node APIs. Since you're using Sapper, you can use the package in a server route and fetch it from the client.
Create the file yahoo.json.js and place it in src/routes. Then copy + paste the following into it. This will call the historical method from yahoo-finance and return the result as JSON.
import yahooFinance from 'yahoo-finance';
export async function get(req, res, next) {
const response = await new Promise((resolve, reject) => {
yahooFinance.historical({
symbol: 'AAPL',
from: '2020-01-01',
to: '2020-12-31',
}, function (err, quotes) {
if (err) reject(err);
resolve(quotes);
});
})
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response));
}
You can then call this server route from within a Svelte component. This uses the Sapper preload method to fetch the data before the page renders.
<script context="module">
export async function preload() {
const res = await this.fetch('/yahoo.json');
const data = await res.json();
return {data};
}
</script>
<script>
export let data;
</script>
{JSON.stringify(data)}
You will likely want to enhance the server route to add request parameters and better error handling, but this shows you how to get it working.

Adding multiple BigQuery JSON credential files in Node project

I've been working on a Node project that involves fetching some data from BigQuery. Everything has been fine so far; I have my credential.json file (from BigQuery) and the project works as expected.
However, I want to implement a new feature in the project and this would involve fetching another set of data from BigQuery. I have an entirely different credential.json file for this new dataset. My project seems to recognize only the initial credential.json file I had (I named them differently though).
Here's a snippet of how I linked my first credential.json file:
function createCredentials(){
try{
const encodedCredentials = process.env.GOOGLE_AUTH_KEY;
if (typeof encodedCredentials === 'string' && encodedCredentials.length > 0) {
const google_auth = atob(encodedCredentials);
if (!fs.existsSync('credentials.json')) {
fs.writeFile("credentials.json", google_auth, function (err, google_auth) {
if (err) console.log(err);
console.log("Successfully Written to File.");
});
}
}
}
catch (error){
logger.warn(`Ensure that the environment variable for GOOGLE_AUTH_KEY is set correctly: full errors is given here: ${error.message}`)
process.kill(process.pid, 'SIGTERM')
}
}
Is there a way to fuse my two credential.json files together? If not, how can I separately declare which credential.json file to use?
If not, how can I separately declare which credential.json file to use?
What I would do I would create a function which is the exit point to BigQuery and pass an identifier to your function which credential to generate, This credential will then be used when calling BigQuery.
The below code assume you changed this
function createCredentials(){
try{
const encodedCredentials = process.env.GOOGLE_AUTH_KEY;
To this:
function createCredentials(auth){
try{
const encodedCredentials = auth;
And you can use it like this
import BigQuery from '#google-cloud/bigquery';
import {GoogApi} from "../apiManager" //Private code to get Token from client DB
if (!global._babelPolyfill) {
var a = require("babel-polyfill")
}
describe('Check routing', async () => {
it('Test stack ', async (done, auth) => {
//Fetch client Auth from local Database
//Replace the 2 value below with real values
const tableName = "myTest";
const dataset = "myDataset";
try {
const bigquery = new BigQuery({
projectId: `myProject`,
keyFilename: this.createCredentials(auth)
});
await bigquery.createDataset(dataset)
.then(
args => {
console.log(`Create dataset, result is: ${args}`)
})
.catch(err => {
console.log(`Error in the process: ${err.message}`)
})
} catch (err) {
console.log("err", err)
}
})
})

Does there need to be the same number of parameters passed into a javascript function as the number defined in the function

I could do with some javascript function help.
The code below is an example from stripe using node.js and basically is posting a code back to stripe to get some user details.
app.get('/oauth/callback', function(req, res) {
var code = req.query.code;
// Make /oauth/token endpoint POST request
request.post({
url: TOKEN_URI,
form: {
grant_type: 'authorization_code',
client_id: CLIENT_ID,
code: code,
client_secret: API_KEY
}
}
});
I need to set up a similar function but the main difference is that I already have that code and want to pass the code into the function.
At the moment my function looks like:
var getAccountDetails = function(req, res) {
// Make /oauth/token endpoint POST request
request.post({
url: 'https://connect.stripe.com/oauth/token';,
form: {
grant_type: 'authorization_code',
client_id: 'ca_XXXXXXXXXXXXXXXXXXXXXXXXX',
code: code,
client_secret: API_KEY
}
}, function(err, r, body) {
});
};
I am calling getAccountDetails() from within another function but wanted to pass in to getAccountDetails(code) but i'm still struggling a little with javascript functions.
*************** Update **************
On the google cloud function console i keep getting a timeout message. If anyone sees anything obviously wrong with the code let me know.
function getAccountDetails(code)
{
console.log(code)
return function(req, res) {
// Make /oauth/token endpoint POST request
request.post({
url: 'https://connect.stripe.com/oauth/token',
form: {
grant_type: 'authorization_code',
client_id: 'xxxxxxxxx',
code: code,
client_secret: 'xxxxxxxxxxxx'
}
}, function(err, r, body) {
// var accessToken = JSON.parse(body).access_token;
console.log(body);
});
}
}
exports.authCode = functions.https.onRequest((req, res) => {
console.log(req)
var code = req.query.code;
console.log(code);
getAccountDetails(code)
});
Thanks.
The short answer to your title question is no. Javascript is very flexible about whether the number of arguments in a function definition match the number of arguments passed in when calling the function.
Handling differing numbers of arguments is handled like this:
If a function is invoked with fewer arguments than in the definition, the arguments not included will be undefined in the function execution.
If a function is invoked with more arguments than in the definition, the excess arguments don't cause any problems
In fact, in the second case, you can still access the extra arguments passed in using the arguments keyword:
function example(p1, p2) {
console.log(arguments[2]);
}
example('one', 'two', 'three'); // logs: 'three'
However, the function you are using looks like it may be part of a framework. How you can use it depends on what framework, and where it is in that framework.
You can modify the function definition:
var getAccountDetails = function(req, res, code) {
// ...
and this is fine as long as no other part of the framework is calling that function, possibly expecting something else to be there in that third argument (for ex, lots of express-based apps might be expecting the third argument to be a callback function, often labelled next, etc).
As a best guess, if you created this function as a helper, or service for yourself, then I would say modify it as needed and experiment. However, if it's in a highly structured part of a framework, modifying it may break something.
Try this:
exports.authCode = functions.https.onRequest((req, res) => {
console.log(req)
var code = req.query.code;
console.log(code);
getAccountDetails(code)(req, res);
});
getAccountDetails(code) is returning a Function that expects (req, res), so you just need to call that Function with the req and res provided. Since you're not actually calling that Function, nothing is happening - you're not doing anything with res - so it's timing out.
In javascript a function (A) can return another functions (B). The function B returned can remember whatever the function A was called with. This is called closures. So
function getAccoudnDetailsWith(code) {
return function (req, res) { //this function is stored in getAccountDetails
request.post({
url: 'https://connect.stripe.com/oauth/token',
form: {
grant_type: 'authorization_code',
client_id: 'ca_XXXXXXXXXXXXXXXXXXXXXXXXX',
code: code,///this code is whatever you pass in
client_secret: API_KEY
}
}, function (err, r, body) {
});
}
}
var getAccountDetails = getAccoudnDetailsWith(code);
Edit 1:
You wouldn't need closures for this from your changed code.
exports.authCode = functions.https.onRequest((req, res) => {
var code = req.query.code;
// Make /oauth/token endpoint POST request
request.post({
url: TOKEN_URI,
form: {
grant_type: 'authorization_code',
client_id: CLIENT_ID,
code: code,
client_secret: API_KEY
}
}, function(err, r, body) {
// var accessToken = JSON.parse(body).access_token;
console.log(body);
});
});

How to validate if its a login page using webdriverio

I am using Javascript, webdriverio (v2.1.2) to perform some data extraction from an internal site. The internal site is SSO enabled, so if I have been authenticated on another application, I need not login for this application (common in enterprise intranet applications).
I plan to achieve the below,
Create a client with required capabilities
Pass the required URL
For fun : Print the title of the page
Check if an element exist on the page. If yes, then it's a login page. If not, then it's not login page
login = function (username, password) {
if (!browserClientUtil) {
throw "Unable to load browserClientUtil.js";
}
browserClientUtil
.createClient()
.url(_Url)
.title(function (err, res) {
console.log('Title is: ' + res.value);
}) .isExisting('input#login_button.login_button', function (err, isExisting) {
browserClientUtil.getCurrentClient()
.setValue('input#USER.input', username)
.setValue('input#PASSWORD.input', password)
//.saveScreenshot('ultimatixLoginDetails.png')
.click('input#login_button.login_button')
.pause(100);
handlePostLogin();
});
};
Is this the best way to do? I tried to separate the code for verifying login page in a separate function, it didn't work as everything in webdriver happens as part of callback and I am not sure if I am doing it in a right way.
How do I return from a callback, that will in-turn be the final value returned by that function?
login = function (username, password) {
if (!browserClientUtil) {
throw "Unable to load browserClientUtil.js";
}
browserClientUtil
.createClient()
.url(_Url)
.title(function (err, res) {
console.log('Title is: ' + res.value);
});
if(isThisLoginPage()){
browserClientUtil.getCurrentClient()
.setValue('input#USER.input', username)
.setValue('input#PASSWORD.input', password)
//.saveScreenshot('ultimatixLoginDetails.png')
.click('input#login_button.login_button')
.pause(100);
handlePostLogin();
}
};
isThisLoginPage = function() {
var client = browserClientUtil.getCurrentClient();
if(!client) {
throw "Unable to get reference for current client, hence cannot validate if this is login page.";
}
client.isExisting('input#login_button.login_button', function (err, isExisting) {
if(isExisting) {
return true;
}
});
return false;
};
You can create your own workflow by creating own commands that wrap other ones. For example you can make an own command to login:
browserClientUtil.addCommand("login", function(url, user, pw, cb) {
this.url(url)
.setValue('#username', user)
.setValue('#password', pw)
.submitForm('#loginForm')
.call(cb);
});
This allows you to hide "complex" asynchronous webdriver actions behind a simple function. It is easy to create an powerful toolchain. At the end your test script looks like:
browserClientUtil
.login("http://example.com/login", "john.doe", "testpass")
.getTitle(function(err, title) {
console.log(title);
})
// ...
Cheers

Categories