Variable is not changed in local function - javascript

I am trying get specific string from email body and return it. Inside simpleParser function I assign output of substring to token variable which I declare earlier. Why when I print token in getEmails function I get empty string and in simpleParse I get string with value that I wanted?
const Imap = require('imap');
const {simpleParser} = require('mailparser');
const imapConfig = {
user: '',
password: '',
host: 'imap.gmail.com',
port: 993,
tls: true,
tlsOptions: {
rejectUnauthorized: false
}
};
let token = "";
async function getEmails() {
try {
const imap = new Imap(imapConfig);
imap.once('ready', () => {
imap.openBox('INBOX', false, () => {
imap.search(['UNSEEN'], (err, results) => {
const f = imap.fetch(results, {bodies: ''});
f.on('message', msg => {
msg.on('body', stream => {
simpleParser(stream, async (err, parsed) => {
// const {from, subject, textAsHtml, text} = parsed;
// console.log(parsed);
let tokenNr = parsed.html.search('token');
token = parsed.html.substring(tokenNr+6, tokenNr+66);
console.log(token);
});
});
});
f.once('error', ex => {
return Promise.reject(ex);
});
f.once('end', () => {
console.log('Done fetching all messages!');
imap.end();
});
});
});
});
imap.once('error', err => {
console.log(err);
});
imap.once('end', () => {
console.log('Connection ended');
});
imap.connect();
} catch (ex) {
console.log('an error occurred');
}
console.log(token);
return token;
};

Related

auth.getAccessToken() is not a function - Azure AD PowerBI + NodeJS integration

Still am able to get the accessToken successfully but don't understand why I'm getting auth.getAccessToken is not a function
index.js
$.ajax({
type: "GET",
url: "/getSingRpt",
dataType: "json",
success: function (embedData) {
let reportLoadConfig = {
type: "report",
tokenType: models.TokenType.Embed,
accessToken: embedData.accessToken,
embedUrl: embedData.embedUrl[0].embedUrl
};
tokenExpiry = embedData.expiry;
let report = powerbi.embed(reportContainer, reportLoadConfig);
report.off("loaded");
report.on("loaded", function () {
console.log("Report load successful");
});
report.off("rendered");
report.on("rendered", function () {
console.log("Report render successful");
});
report.off("error");
report.on("error", function (event) {
let errorMsg = event.detail;
console.error(errorMsg);
return;
});
},
error: function (err) {
let errorContainer = $(".error-container");
$(".embed-container").hide();
errorContainer.show();
let errMsg = JSON.parse(err.responseText)['error'];
let errorLines = errMsg.split("\r\n");
let errHeader = document.createElement("p");
let strong = document.createElement("strong");
let node = document.createTextNode("Error Details:");
let errContainer = errorContainer.get(0);
strong.appendChild(node);
errHeader.appendChild(strong);
errContainer.appendChild(errHeader);
errorLines.forEach(element => {
let errorContent = document.createElement("p");
let node = document.createTextNode(element);
errorContent.appendChild(node);
errContainer.appendChild(errorContent);
});
}
});
Server.js
app.get('/getSingRpt', async (req, res) => {
try {
await embedToken.getEmbedParamsForSingleReport().then((result) => {
console.log(result);
res.status(200).send({ success: true, data: result });
})
} catch (e) {
console.error(e);
res.status(400).send({ success: false, message: 'problem in getting report' });
}
});
embedSConfigService.js
async function getEmbedParamsForSingleReport(workspaceId, reportId, additionalDatasetId) {
const reportInGroupApi = `https://api.powerbi.com/v1.0/myorg/groups/${workspaceId}/reports/${reportId}`;
const headers = await getRequestHeader();
const result = await fetch(reportInGroupApi, {
method: 'GET',
headers: headers,
})
console.log('result', result);
if (!result.ok) {
throw result;
}
const resultJson = await result.json();
const reportDetails = new PowerBiReportDetails(resultJson.id, resultJson.name, resultJson.embedUrl);
const reportEmbedConfig = new EmbedConfig();
reportEmbedConfig.reportsDetail = [reportDetails];
let datasetIds = [resultJson.datasetId];
if (additionalDatasetId) {
datasetIds.push(additionalDatasetId);
}
reportEmbedConfig.embedToken = await getEmbedTokenForSingleReportSingleWorkspace(reportId, datasetIds, workspaceId);
return reportEmbedConfig;
}
async function getRequestHeader() {
let tokenResponse;
let errorResponse;
try {
tokenResponse = await auth.getAccessToken();
} catch (err) {
if (err.hasOwnProperty('error_description') && err.hasOwnProperty('error')) {
errorResponse = err.error_description;
} else {
errorResponse = err.toString();
}
return {
'status': 401,
'error': errorResponse
};
}
const token = tokenResponse;
console.log('TOKEN==>', tokenResponse)
return {
'Content-Type': "application/json",
'Authorization': utils.getAuthHeader(token)
};
}
Auth.js
const adal = require('adal-node');
const config = require(__dirname + '/../config/config.json');
const getAccessToken = () => {
return new Promise((resolve, reject) => {
try {
const authMode = config.authenticationMode.toLowerCase();
const AuthenticationContext = adal.AuthenticationContext;
let authorityUrl = config.authorityUri;
if (authMode === 'masteruser') {
new AuthenticationContext(
authorityUrl,
).acquireTokenWithUsernamePassword(
config.scope,
config.pbiUsername,
config.pbiPassword,
config.clientId,
(err, token) => {
if (err) reject(err);
resolve(token);
},
);
} else if (authMode === 'serviceprincipal') {
authorityUrl = authorityUrl.replace('common', config.tenantId);
new AuthenticationContext(
authorityUrl,
).acquireTokenWithClientCredentials(
config.scope,
config.clientId,
config.clientSecret,
(err, token) => {
if (err) reject(err);
resolve(token);
},
);
} else {
reject(new Error('Unknown auth mode'));
}
} catch (err) {
console.error(err);
reject(err);
}
});
};
getAccessToken()
.then((token) => console.log(token))
.catch((err) => console.error(err));
updated
utilities.js
let config = require(__dirname + "/../config/config.json");
function getAuthHeader(accessToken) {
// Function to append Bearer against the Access Token
return "Bearer ".concat(accessToken);
}

Cannot Stub Function Returning Promise

I was trying to stub an arrow function removeUserEntry, but when executing acctRmRouter in the test, my stub seems being ignored. I have to explicitly stub the UserModel's deleteOne method to get the test successfully, I am wondering why the ignorance happens, thank you
acctRoute.js
const removeUserEntry = (username) => {
const condition = {username: username};
return UserModel.deleteOne(condition)
.then((res) => {
if (res.n < 1) {
throw new Error('User not exists');
}
return true;
}, (err) => {throw err})
.catch(err => err);
};
const acctRmRouter = function(httpReq, httpRes, next) {
if (!argValidate(httpReq.body, 'string')) {
httpRes.locals = {api: { success: false }};
// return to avoid running downwards
return next(new Error('bad argument'));
}
// perform DB rm user
return removeUserEntry(httpReq.body).then((res) => {
if (res === true) {
httpRes.locals = {api: { success: true }};
next();
} else {
httpRes.locals = {api: { success: false }}
next(res);
}
});
};
acctRoute.spec.js
it('should remove user handler pass success request', async () => {
shouldDbReset = false;
const mockRequestURL = "/api/account/rm-user";
const mockRequest = httpMocks.createRequest({
method: "POST",
url: mockRequestURL,
headers: {
"Content-Type": "text/plain"
},
body: 'validRmUser',
});
const mockResponse = httpMocks.createResponse();
const spyNext = sinon.spy();
const stubRemoveUserEntry = sinon.stub(accountRouterHelper, 'removeUserEntry');
stubRemoveUserEntry.callsFake(function(){
return Promise.resolve(true);
}); // Expecting this function to be stubbed, and always return true
await accountRouterHelper.acctRmRouter(mockRequest, mockResponse, spyNext);
/* But when running the function, it returns error object with "User not exists"
which is not what intended */
const firstCallArgs = spyNext.getCall(0).args[0];
expect(spyNext.called).to.be.true;
console.log(`firstCallArgs: ${firstCallArgs}`)
expect(firstCallArgs instanceof Error).to.be.false;
expect(spyNext.args[0].length).to.equal(0);
expect(mockResponse.statusCode).to.equal(200);
expect(mockResponse.locals.api.success).to.be.true;
stubRemoveUserEntry.resetHistory();
stubRemoveUserEntry.restore();
});
The following indeed stubbed successfully with similar pattern to removeUserEntry.
acctRoute.js
const createUserEntry = (userData) => {
const updatedUserData = filterInput(userData);
const userDoc = new UserModel(updatedUserData);
return userDoc.save()
.then((userObj) => userObj._doc
,(err) => { throw err;})
.catch(err => err);
};
const acctCreateRouter = function (httpReq, httpRes, next) {
// do something in mongodb
return createUserEntry(userCondition)
.then((response) => {
if (!(response instanceof Error)) {
httpRes.locals = {api: { success: true}};
next();
} else {
httpRes.locals = {api: { success: false}};
next(response);
}
}, (err) => {
httpRes.locals = {api: { success: false}};
next(err);
})
.catch((err) => {
httpRes.locals = {api: { success: false}};
next(err);
});
};
const acctOutputRouter = function(req, res, next) {
if (res.locals) {
res.send(res.locals.api);
} else {next()}
};
acctRoute.spec.js
it("should return and save the success result to response locals for next route", () => {
shouldDbReset = false;
const mockResponse = httpMocks.createResponse();
const stubCreateUserEntry = sinon.stub(accountRouterHelper, 'createUserEntry');
const mockNext = sinon.spy();
stubCreateUserEntry.callsFake(function(){
return Promise.resolve();
}); // Unlike removeUserEntry, stubbing neatly with desired output
return accountRouterHelper.acctCreateRouter(mockRequest, mockResponse, mockNext)
.then(() => {
expect(mockNext.called).to.be.true;
expect(mockResponse.locals.api.success).to.be.true;
})
.finally(() => {
mockNext.resetHistory();
stubCreateUserEntry.restore();
});
});
Issue
sinon.stub(accountRouterHelper, 'removeUserEntry') replaces the module export.
acctRmRouter() is not calling the module export, it is calling removeUserEntry() directly so stubbing the module export does nothing.
Solution
Refactor acctRmRouter() to call the module export for removeUserEntry().
ES6
// import module into itself
import * as self from './acctRoute';
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using the module
return self.removeUserEntry(httpReq.body).then((res) => {
...
Node.js module
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using module.exports
return module.exports.removeUserEntry(httpReq.body).then((res) => {
...

JavaScript class TypeError X is not a function

this is something I couldn't resolve for a while. I am creating an ES6 class:
const https = require('https');
class LetsGrowHandler {
constructor() {
}
connectLG() {
return new Promise(function(resolve, reject) {
const post_options =
{
host: 'api.letsgrow.com',
path: '/Token',
method: 'POST'
};
const postData = require('querystring').stringify(
{
username: '',
password: '',
grant_type: 'password',
signin: 'Sign in'
});
let data;
const response = https.request(post_options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', () => {
resolve(data);
});
});
response.on('error', (e) => {
reject(e);
});
response.write(postData);
response.end();
});
}
}
module.exports = LetsGrowHandler;
Then I want to test whether the function works properly with a simple unit test:
describe('LetsGrowHandler', function () {
describe('retrieve token', function () {
it('connectLG should succeed', function (done) {
// This was missing: const lgh = new LetsGrowHandler();
lgh.connectLG()
.then(function (value) {
//console.log(value);
chai.assert(value.access_token !== null);
done();
})
.catch(function (err) {
console.log(err);
chai.assert(1 === 3);
done();
});
});
});
});
Unfortunately, I get the result
lgh .connectLG()
^
TypeError: lgh.connectLG is not a function
at Suite.<anonymous> (D:\Code\ghdb\tests\LetsGrowHandler_test.js:7:15)
What does Suite.<anonymous> mean? Is that a pointer to the problem already?
What am I missing here?
Thank you,
Jens

How to store the RFC822 message body body as String?

var inbox = require("inbox");
var client = inbox.createConnection(false, "imap.gmail.com", {
secureConnection: true,
auth:{
user: "myemail#gmail.com",
pass: "mypass"
}
});
client.connect();
client.on("connect", function(){
client.openMailbox("INBOX", function(error, info){
if(error) throw error;
client.listMessages(-10, function(err, messages){
var datas = [];
var data;
messages.forEach(function(message){
data = message.UID + ": " + message.title;
datas.push(data);
});
var messageStream = client.createMessageStream(22048);
console.log(messageStream);
client.close();
});
});
});
The above code returns
Stream {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined }
But by replacing
var messageStream = client.createMessageStream(22048);
console.log(messageStream);
with
client.createMessageStream(123).pipe(process.stdout, {end: false});
I get the entire RFC822 message body in terminal
How to store the RFC822 message body body as String?
I tried my best to do it but everytime it returns the same
how can i do it?
Since its a readable stream you can use NodeJS - Class: stream.Readable
You can use data event to get the message from stream and end event to know when there is no more data
Event: 'data'
const readable = getReadableStreamSomehow();
readable.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});
Event: 'end'
const readable = getReadableStreamSomehow();
readable.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});
readable.on('end', () => {
console.log('There will be no more data.');
});
P.S. createMessageStream accepts as argument a message UID.
In your case you might have to wrap this up with some promise base functions
Example
var inbox = require("inbox");
var client = inbox.createConnection(false, "imap.gmail.com", {
secureConnection: true,
auth: {
user: "myemail#gmail.com",
pass: "mypass"
}
});
client.connect();
client.on("connect", function() {
client.openMailbox("INBOX", function(error, info) {
if (error) throw error;
var emails = [];
var promises = [];
new Promise(function(resolve, reject) {
client.listMessages(-10, function(err, messages) {
if (err) {
reject(err)
return;
};
messages.forEach(function(message) {
var promise = new Promise(function(resolve, reject) {
var email = {
UID: messages.UID,
title: message.title,
body: ""
}
client.createMessageStream(message.UID)
.on('data', (chunk) => {
email.body += chunk.toString();
}).on('end', () => {
//return the email object
resolve(email);
}).on('error', (err) => {
reject(err);
});
})
promises.push(promise);
});
resolve();
});
}).then(() => {
return Promise.all(promises).then(function(emails) {
console.log(emails);
console.log("closing");
client.close();
})
})
});
});

Testing express middleware

I have following code to test:
const Status = require('http-status-codes');
const passport = require('passport');
const Users = require('../models/users.js');
const authentication = {
// Authenticate User Middleware
authenticateUser: function authenticateUser(req, res, next) {
return passport.authenticate('bearer', { session: false, failWithError: false },
(err, user, info) => {
if (err) {
return res.status(500).json({ message: err });
}
if (user) {
return Users.findOne({ auth_ref: user.auth_ref })
.populate('groups')
.exec((e, doc) => {
if (e) {
return res.status(500).json({ message: e });
}
req.authInfo = info;
req.user = doc;
return next(null, doc, info);
});
}
return res.status(Status.UNAUTHORIZED).json({ message: 'Access denied' });
}
)(req, res, next);
},
};
module.exports = authentication.authenticateUser;
My test file:
const test = require('ava');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const Util = require('../util');
Util.beforeEach(test, (t) => {
const authenticateStub = sinon.stub();
const passportStub = {
authenticate: authenticateStub,
};
const authenticationMocked = proxyquire('../../../middleware/authentication', { passport: passportStub });
t.context.authenticateStub = authenticateStub;
t.context.authenticationMocked = authenticationMocked;
});
Util.afterEach(test);
Util.after(test);
test('[middleware/authentication] authenticateUser function call succeed', sinon.test(async (t) => {
// given
const func = t.context.authenticationMocked;
t.context.authenticateStub.withArgs(sinon.match.any, sinon.match.any, sinon.match.any).yields('error', { statusCode: 500 }, 'sampleUser');
const nextSpy = sinon.spy();
const fakeReq = { user: { email: '' } };
const res = {
status: () => res,
json: () => res,
};
// when
func(fakeReq, res, nextSpy);
// then
})
My problem is that I somehow can't mock the res parameter in a way so that no error occurs.
This code produces the following error:
Rejected promise returned by test. Reason:
TypeError {
message: 'passport.authenticate(...) is not a function', }
If I remove the res object to {} the error is res.status is not a function
Am I doing something wrong with the initialization or is my res object wrong?
I now found the following solution:
// given
const func = t.context.authenticationMocked;
t.context.authenticateStub.withArgs(sinon.match.any, sinon.match.any, sinon.match.any).yields('error', { statusCode: 500 }, 'sampleUser').returns(() => {});
const nextSpy = sinon.spy();
const fakeReq = { user: { email: '' } };
const rootRouteStub = {
status: sinon.stub(),
json: sinon.spy(),
};
rootRouteStub.status.returns(rootRouteStub);
// when
func(fakeReq, rootRouteStub, nextSpy);

Categories