NodeJS Send an email using pinpoint template with variables - aws-sdk

I'm using #aws-sdk/client-pinpoint to send an email to a verified user.
async sendEmail(body: any): Promise<void> {
const fromAddress = 'test#domain.com';
const toAddress = 'test#domain.com';
const projectId = 'XXX-XXXX-XXXX';
const subject = 'Amazon Pinpoint Test (AWS SDK for JavaScript in Node.js)';
const body_text = `Amazon Pinpoint Test (SDK for JavaScript in Node.js)`;
const charset = 'UTF-8';
const params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[toAddress]: {
ChannelType: 'EMAIL',
},
},
MessageConfiguration: {
EmailMessage: {
FromAddress: fromAddress,
SimpleEmail: {
Subject: {
Charset: charset,
Data: subject,
},
HtmlPart: {
Charset: charset,
Data: 'body_html',
},
TextPart: {
Charset: charset,
Data: body_text,
},
},
},
},
},
};
try {
const data = await this.pinpointClient.send(new SendMessagesCommand(params));
const { MessageResponse } = data;
if (!MessageResponse || !MessageResponse.Result) throw Error('Failed!');
const recipientResult = MessageResponse?.Result[toAddress];
if (recipientResult.StatusCode !== 200) {
throw new Error(recipientResult.StatusMessage);
} else {
console.log(recipientResult.MessageId);
}
} catch (err) {
console.log(err.message);
}
}
And everything is working fine. But when I try to use a pre-defined template, it is not being send for some reason and no errors were shown as well! I'm lost on how to pass template Name/ARN with substitution. Any idea on how to achieve that?
Cheers!

use Template Configuration in message configuration
TemplateConfiguration: {
EmailTemplate: {
'Name': 'template name',
'Version': 'latest'
}
}
async sendEmail(body: any): Promise<void> {
const fromAddress = 'test#domain.com';
const toAddress = 'test#domain.com';
const projectId = 'XXX-XXXX-XXXX';
const subject = 'Amazon Pinpoint Test (AWS SDK for JavaScript in Node.js)';
const body_text = `Amazon Pinpoint Test (SDK for JavaScript in Node.js)`;
const charset = 'UTF-8';
const params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[toAddress]: {
ChannelType: 'EMAIL',
},
},
MessageConfiguration: {
EmailMessage: {
FromAddress: fromAddress,
SimpleEmail: {
Subject: {
Charset: charset,
Data: subject,
},
HtmlPart: {
Charset: charset,
Data: 'body_html',
},
TextPart: {
Charset: charset,
Data: body_text,
},
},
},
},
TemplateConfiguration: {
EmailTemplate: {
'Name': 'template name',
'Version': 'latest'
}
}
},
};
try {
const data = await this.pinpointClient.send(new SendMessagesCommand(params));
const { MessageResponse } = data;
if (!MessageResponse || !MessageResponse.Result) throw Error('Failed!');
const recipientResult = MessageResponse?.Result[toAddress];
if (recipientResult.StatusCode !== 200) {
throw new Error(recipientResult.StatusMessage);
} else {
console.log(recipientResult.MessageId);
}
} catch (err) {
console.log(err.message);
}
}

Related

how to get md5checksum in search (google drtive api)

I'm using drive v3 of google drive api, and I want google files name, id, mimeType and md5Checksum.
/** serarch files from google
* #param query
* #returns {Promise} with the result of the search
*
*/
async search(query, token) {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
q: `name contains '${query}' and trashed=false and mimeType != 'application/vnd.google-apps.shortcut' and mimeType != 'application/vnd.google-apps.folder'`,
fields: '*',
spaces: 'drive',
pageSize: 13,
},
};
if(query.length === 0 || !token) return [];
const result = [];
try {
const response = await axios.get(
`https://www.googleapis.com/drive/v3/files`,
config
);
const files = await response.data.files;
if (files.length) {
files.map(file => {
let googleObject = {};
googleObject.id = file.id;
googleObject.name = file.name;
googleObject.icon = file.iconLink;
googleObject.mimeType = file.mimeType;
googleObject.md5Checksum = file.md5Checksum;
result.push(googleObject);
});
} else {
result.push({
id: '',
name: 'No results',
icon: 'my-icon',
mimeType: '',
});
}
return JSON.stringify(result);
} catch (error) {
console.log('error ', error);
return null;
}
}
So i get a response from the server, something like this :
{
"id": "****",
"name": "test"
"icon": "https://drive-thirdparty.googleusercontent.com/16/type/application/vnd.google-apps.spreadsheet",
"mimeType": "application/vnd.google-apps.spreadsheet"
}
I can't figure out what I'm doing wrong, I try to replace
fields: 'files(id,name,mimeType,iconLink,md5Checksum)',
with
fields: '',* but i still have the same error (only id, name, mimetype and icon)

RTC Peer connections

I'm building social media application using node js and react js, I have problem when it comes to video / audio calls;
case 1: i call from computer to mobile phone and both are in same network, it works--
case 2: i call from mobile phone browser to computer and both are in same network, remote stream does not work--
case 3: i call from different network, remote stream does not work;--
i tried to change turn and stun servers but it did not work either;
The code;
function createPeer(userID: string, type: 'audio' | 'video') {
const peer = new RTCPeerConnection(configuration);
peer.ontrack = onTrackEvent;
peer.onicecandidate = onIceCandidateEvent(userID);
return peer;
}
function onTrackEvent(e: RTCTrackEvent) {
if (remoteStream.current) {
e.streams[0].getTracks().forEach((track) => {
remoteStream.current!.addTrack(track)
});
}
}
function onIceCandidateEvent (userID: string) {
return (e: RTCPeerConnectionIceEvent) => {
if (e.candidate) {
socket.emit('ice-candidate', {
userID,
candidate: e.candidate.candidate,
sdpMLineIndex: e.candidate.sdpMLineIndex,
sdpMid: e.candidate.sdpMid
})
}
}
}
function handlingAnswer({ sdp, myData, type }: { sdp: RTCSessionDescriptionInit, myData: any, type: 'audio' | 'video' } ) {
if (peerConnection.current) {
const desciption = new RTCSessionDescription(sdp);
peerConnection.current.setRemoteDescription(desciption)
.then(() => {
if (type === 'video') {
dispatch(callActions.gettingAnswerVideoCall(myData));
}
if (type === 'audio') {
dispatch(callActions.gettingAnswerVoiceCall(myData));
}
})
}
}
const makeCall = async (userID: string, type: 'audio' | 'video') => {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = {
video: true, audio: true
}
}
if (type === 'audio') {
constraints = {
audio: true
}
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
});
const sdp = await peerConnection.current!.createOffer();
await peerConnection.current!.setLocalDescription(sdp);
const payload = {
to: userID,
caller: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
sdp,
type
}
dispatch(callActions.callUser({
callType: type,
userID
}))
socket.emit('offer', payload)
} catch (error) {
console.log(error);
}
}
async function acceptCall(userID: string, sdp: RTCSessionDescriptionInit, type: 'video' | 'audio') {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = { video: true, audio: true }
}
if (type === 'audio') {
constraints = { audio: true }
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
})
const sessionDescription = new RTCSessionDescription(sdp);
await peerConnection.current.setRemoteDescription(sessionDescription);
const answer = await peerConnection.current.createAnswer();
await peerConnection.current.setLocalDescription(answer)
if (type === 'audio') {
dispatch(callActions.acceptVoiceCall())
}
if (type === 'video') {
dispatch(callActions.acceptVideoCall())
}
const payload = {
caller: userID,
sdp: answer,
myData: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
type
}
socket.emit('answer', payload)
} catch (error) {
alert(JSON.stringify(error))
}
}
socket.on('offer', handlingOffer);
socket.on('answer', handlingAnswer);
socket.on('ice-candidate', async ({ candidate, sdpMLineIndex, sdpMid }) => {
if (peerConnection.current) {
const rtcIceCandidate = new RTCIceCandidate({ candidate, sdpMLineIndex, sdpMid });
await peerConnection.current.addIceCandidate(rtcIceCandidate)
}
})
// In the Call Component
function CallComponent() {
useEffect(() => {
remoteVideoRef.current.srcObject = remoteStream.current
myVideoRef.current.srcObject = localStream.current
}, [])
return JSX .............................
}

Web3js BatchRequest Balances from List of Tokens Fails on execute()

This is my batch.js file which contains the relevant code. I am importing some variables from other files but I've isolated the problem to this file:
const Web3 = require('web3')
const fs = require('fs')
const { convertToNumber, getTokens } = require('./utils')
const { abi, bathEndpoint, walletAddress, blockNumber } = require('./constant.js')
const web3 = new Web3(new Web3.providers.HttpProvider(bathEndpoint))
const generateContractFunctionList = ({ tokens, blockNumber }) => {
const batch = new web3.BatchRequest()
tokens.map(async ({ address: tokenAddress, symbol, decimals }) => {
// console.log('tokenAddress :>> ', tokenAddress)
if (tokenAddress != null && tokenAddress != '') {
const contract = new web3.eth.Contract(abi)
contract.options.address = tokenAddress
try {
batch.add(
contract.methods
.balanceOf(walletAddress)
.call.request({}, blockNumber)
)
} catch (error) {
console.error('Error adding request to batch for token ', tokenAddress)
}
}
})
return batch
}
const main = async () => {
//const { tokens } = await getTokens()
const tokens = JSON.parse(fs.readFileSync('./tokenArrayFormatted1.json'));
console.log('tokens retrieved :>> ', tokens.length)
// const batch = generateContractFunctionList({ tokens })
// query block number
const batch = generateContractFunctionList({ tokens, blockNumber: blockNumber })
const tokenBalances = {}
const tokensIgnored = []
let batchData
try {
batchData = await batch.execute()
} catch (error) {
console.error('Error retrieving balances for some tokens')
batchData = error
}
try {
batchData.response.forEach((res, index) => {
const { name, decimals, symbol } = tokens[index]
if (res && res._hex) {
tokenBalances[name] = `${convertToNumber(res._hex, decimals)} ${symbol}`
} else {
tokensIgnored.push(name)
}
})
} catch (error) {
console.error('Error retrieving balances for some tokens')
batchData = error
}
console.log(
'The following tokens returned an error when checking balance:',
tokensIgnored
)
console.log('----------')
console.log(
`Balance checked for ${Object.keys(tokenBalances).length} tokens:`
)
console.log(tokenBalances)
}
main()
tokenArrayFormatted1.json looks like this:
[
{
"chainId": 1,
"address": "0xf3AE5d769e153Ef72b4e3591aC004E89F48107a1",
"name": "Deeper Network",
"symbol": "DPR",
"decimals": 18
},
{
"chainId": 1,
"address": "0xf680429328caaaCabee69b7A9FdB21a71419c063",
"name": "Butterfly Protocol Governance Token",
"symbol": "BFLY",
"decimals": 18
}
]
When I run node batch.js I keep getting an error telling me that batchData.response is undefined when the code tries to do a forEach over it. I logged batch to the console and it looked like this.
Batch {
requestManager: RequestManager {
provider: HttpProvider {
withCredentials: false,
timeout: 0,
headers: undefined,
agent: undefined,
connected: false,
host: 'https://USERNAME:PASSWORD#BASEURLOFGETHNODE.com',
httpsAgent: [Agent]
},
providers: {
WebsocketProvider: [Function: WebsocketProvider],
HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider]
},
subscriptions: Map(0) {}
},
requests: [
{
params: [Array],
callback: undefined,
method: 'eth_call',
format: [Function: bound ]
},
{
params: [Array],
callback: undefined,
method: 'eth_call',
format: [Function: bound ]
}
]
}
Where USERNAME,PASSWORD, and BASEURLOFGETHNODE refer to my actual credentials.
And then batchData which is created by the line let batchData = await batch.execute() is undefined when logged to the console. So clearly await batch.execute() is producing nothing. I am using Chainstack Geth node API's (with an archive node) and web3js as indicated above. What seems to be the problem?
let batchData = await batch.execute()
batch.execute() does not return a promise if you read the source code, in fact it sends the JSON RPC batch request and call each request callback individually, so what you need to do is turn the execute function into asynchronous one returning an array of responses, and this is how to do it :
const Jsonrpc = require('web3-core-requestmanager/src/jsonrpc');
var { errors } = require('web3-core-helpers');
function executeAsync(batch) {
return new Promise((resolve, reject) => {
var requests = batch.requests;
batch.requestManager.sendBatch(requests, (err, results) => {
results = results || [];
var response = requests.map((request, index) => {
return results[index] || {};
}).map((result, index) => {
if (result && result.error) {
return errors.ErrorResponse(result);
}
if (!Jsonrpc.isValidResponse(result)) {
return errors.InvalidResponse(result);
}
return requests[index].format ? requests[index].format(result.result) : result.result;
});
resolve(response);
});
})
}
To use this function :
(async () => {
var batch = new web3.BatchRequest();
batch.add(web3.eth.getBlock.request("latest"));
var batchResponse = await executeAsync(batch);
console.log(batchResponse);
})()

'fetch' from router - how to have 'res.status(400).json('Enter failure message here')' be handled as an error in .then .catch?

I have the following code as part of a Button in one of my React Native components. Observe how there is no .catch to handle a possible 'no results' case from server; it is handled with if-statements instead (e.g.: else if (acceptMatchRequestData['status']==='failure') which I was what I'm trying to get away from.
await acceptMatchRequest(match['matchId'], userId, getUserInfoData[0]['ratings'][matchType])
.then(acceptMatchRequestData => {
if (acceptMatchRequestData['status']==='success') {
setMatchInvites(prevState => {
return prevState.filter((observation, i) => observation['matchId'] !== match['matchId'])
})
setMatchScreenParentState('loading')
sendToUserDeviceNotification('matchFound', userId, match['matchedUserId'])
} else if (acceptMatchRequestData['status']==='failure') {
Alert.alert('', acceptMatchRequestData['message'])
}
})
acceptMatchRequest function code:
export async function acceptMatchRequest(matchId, userId, rating) {
console.log('Attempting to accept match request');
info = { matchId, userId, rating }
const firebaseIdToken = await AsyncStorage.getItem('#firebaseIdToken')
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + firebaseIdToken },
body: JSON.stringify(info)
};
const response = await fetch(ngrokOrLocalhost + '/acceptmatchrequest', requestOptions)
const data = await response.json()
return data
}
And server code:
router.post('/acceptmatchrequest', async (req, res) => {
const { matchId, userId, rating } = req.body;
const results = await Match.find({ 'usersInfo.userId': userId, 'matchRecords.matchConfirmed': { $nin: [true] } }).limit(5)
if (results.length===5) {
res.status(400).json({'status': 'failure', 'message': 'You already have 5 active matches. Please finish a match first before you can accept this match.'})
} else {
var filter2 = { '_id': matchId }
var update2 = { 'isCustomRequest_IsAccepted': true, '$push': { 'usersInfo': { 'userId': userId, 'location': { 'type': 'Point', 'coordinates': [0, 0] }, 'rating': rating } } }
var response2 = await Match.findOneAndUpdate(filter2, update2, { new: true, sort: { 'matchCreatedTimestamp': 1 } })
if (response2) {
// Document was updated
res.status(200).json({'status': 'success', 'message': 'Match request was accepted successfully'})
} else {
console.log('Match request was not accepted successfully');
res.status(400).json({'status': 'failure', 'message': 'Match request was not accepted successfully'})
}
}
})

How do you mock MySQL (with node-orm2) in Node.js/Express?

I am using node.js/express with https://github.com/dresende/node-orm2 to use my MySQL database.
I am new to the node.js world and I am quite stuck so far, I don't know how to unit test (not integration test) a simple function.
Here is my server.js, loading my user model (ORM)
var express = require('express'),
orm = require('orm'),
config = require('./config/config.js'),
auth = require('./services/authentication'),
helper = require('./middlewares/helper.js'),
friends = require('./modules/friends.js');
var app = express();
app.use(orm.express('mysql://' + config.mysql.username + ':' + config.mysql.pwd + '#' + config.mysql.host + ':' + config.mysql.port + '/' + config.mysql.db, {
define: function(db, models, next) {
db.load("./models/models.js", function(err) { // loaded!
models.user = db.models.user;
});
}
}));
var middlewares = [auth.authenticate, helper.retrieveUser];
app.get('/friends', middlewares, friends.findActiveFriends);
app.listen(3000);
console.log('Listening on port 3000...');
here is the user model :
module.exports = function (db, cb) {
var User = db.define('user', {
uid : { type: 'number', rational: false, unique: true, required: true },
first_name : { type: 'text', size: 100, required: true },
last_name : { type: 'text', size: 100, required: true },
picture : { type: 'text', size: 255, required: false },
email : { type: 'text', size: 255, required: true },
creation_date : { type: 'date', time: true },
modification_date : { type: 'date', time: true }
}, {
methods: {
fullName: function () {
return this.first_name + ' ' + this.last_name;
}
},
hooks: {
beforeCreate: function (next) {
if (this.creation_date == undefined) {
this.creation_date = new Date();
}
if (this.modification_date == undefined) {
this.modification_date = new Date();
}
return next();
}
}
});
// CUSTOM FUNCTIONS
User.getByUid = function(uid, callback) {
this.find({ uid: uid }, function(err, users) {
if(err) callback(err);
if (users.length == 1) {
callback(null, users[0]);
} else {
callback('No user found with uid=' + uid);
}
});
};
User.hasMany("friends", User, {
status: { type: 'enum', values: ['pending', 'refused', 'active'] }
}, {
reverse: 'friendsrev', mergeId: 'user_id', mergeAssocId: 'friend_id'
});
return cb();
};
and here is my methods to find active friends in friends.js:
var _findActiveFriends = function(req, res) {
req.currentUser.getFriends({
status: 'active'
}, function(err, friends) {
if (err) throw err;
res.send(JSON.stringify(friends));
});
};
I would like to know how can I write a simple test (with mocha and sinon.js ?) by mocking the database connection and the request also. I need to mock the value of req.currentUser which is a user returned by the ORM in a middleware.
I just want to run unit tests and do not use a real DB or make some HTTP calls.
thanks for your help.
If you want to mock the req using sinon.js, you can do something like the following.
var sinon = require('sinon');
var friend = require('./friend');
it('some test', function(done) {
var req = {
currentUser: {
// Add all the properties/functions that you are concerned with here.
// and you can/should wrap them around sinon.spy().
// If you are not concerned with that function (i.e. you are not using it)
// then you can simply use sinon.stub() to return a stub function.
}
};
var res = {
send: sinon.spy(function(obj) {
assert.ok(obj); // yes object exists
done(); // end of test
};
};
var next = function() {};
friend.findActiveFriend(req, res, next);
});
This way you shouldn't be connecting to the model, which tests friend.js only.
Also, since I just noticed you are using orm.express, you may also want to simply mock req.models with the stubbed function you desire as above.