JS convert string to rfc822 - javascript

I am trying the gmail apis. I've done the auth. Now I want to create a draft. But I am getting this error
{ error:
I20161220-15:53:43.486(4)? { errors: [Object],
I20161220-15:53:43.487(4)? code: 400,
I20161220-15:53:43.488(4)? message: 'Media type \'application/octet-stream\' is not supported. Valid media types: [message/rfc822]' } } }
Gmail api require base64 string with rfc822 standard. I am not sure of any good way to convert a string to rfc822. How do I do that?
I am using meteor for my app and here is my code.
import { Meteor } from 'meteor/meteor'
import { HTTP } from 'meteor/http'
Meteor.startup(() => {
// Meteor.call('createDraft')
Meteor.methods({
'createDraft': function () {
console.log(this.userId)
const user = Meteor.users.findOne(this.userId)
const email = user.services.google.email
console.log(email)
const token = user.services.google.accessToken
const dataObject = {
message: {
raw: CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse('dddd'))
},
headers: {
Authorization: `Bearer ${token}`
}
}
HTTP.post(`https://www.googleapis.com/upload/gmail/v1/users/${email}/drafts`, dataObject, (error, result) => {
if (error) {
console.log('err', error)
}
if (result) {
console.log('res', result)
}
})
}
})
})

Base64 encode the message and replace all + with -, replace all / with _, and remove the trailing = to make it URL-safe:
const rawMessage = btoa(
"From: sender#gmail.com\r\n" +
"To: receiver#gmail.com\r\n" +
"Subject: Subject Text\r\n\r\n" +
"The message text goes here"
).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const dataObject = {
message: {
raw: rawMessage
},
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
}
};

I just needed to send content type as message/rfc822. Here is the working code. Note that the raw message has something wrong in ts because the draft that is created has empty content. But the draft itself is created successfully.
import { Meteor } from 'meteor/meteor'
import { HTTP } from 'meteor/http'
Meteor.startup(() => {
// Meteor.call('createDraft')
Meteor.methods({
'createDraft': function () {
console.log(this.userId)
// CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse('dddd'))
const user = Meteor.users.findOne(this.userId)
const email = user.services.google.email
console.log(email)
const token = user.services.google.accessToken
const rawMessage = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(
'From: sender#gmail.com\r\n' +
'To: receiver#gmail.com\r\n' +
'Subject: Subject Text\r\n\r\n' +
'The message text goes here'
)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const dataObject = {
message: {
raw: rawMessage
},
headers: {
'Content-Type': 'message/rfc822',
Authorization: `Bearer ${token}`
}
}
HTTP.post(`https://www.googleapis.com/upload/gmail/v1/users/${email}/drafts`, dataObject, (error, result) => {
if (error) {
console.log('err', error)
}
if (result) {
console.log('res', result)
}
})
}
})
})

Related

Axios and App GET/POST requests to external api

I am new to axios and nodejs/express. Axios calls were made from the React component files themselves, and I decided to move them to a file called "user.service.js" to learn best practices. However they don't work how I expect them to. The following are two scenarios.
For a GET request, this works:
user.service.js:
class UserService {
getDevices() {
return axios.get(process.env.REACT_APP_SERVICE + "/userDevices", {
params: {
access_token: user.access_token,
}
});
}
}
export default new UserService();
server.js:
app.get('/userDevices', (req, res) => {
console.log("grabbing user list of available devices");
axios.get(api_url + "/api/devices", {
headers:
{ 'Authorization': 'Bearer ' + req.query.access_token }
}
).then((response) => {
res.send({ devices: response.data });
}).catch((err) => {
console.log('failed to grab user devices');
res.send('error');
});
});
But this (changing the getDevices function in user.service.js and the header in server.js) doesn't:
user.service.js:
getDevices() {
return axios.get(process.env.REACT_APP_SERVICE + "/userDevices", {
headers: {
authorization: 'Bearer +' user.access_token,
}
});
}
server.js:
app.get('/userDevices', (req, res) => {
console.log("grabbing user list of available devices");
axios.get(api_url + "/api/devices", {
headers: req.headers.authorization
}
).then((response) => {
res.send({ devices: response.data });
}).catch((err) => {
console.log('failed to grab user devices');
res.send('error');
});
});
For a POST request, this doesn't work at all:
user.service.js:
class UserService()
{
addDevice(eid, deviceType, configGroup, name, ip, tenantID) {
return axios.post(process.env.REACT_APP_SERVICE + "/addDevice", {
params :{
eid: eid,
deviceType: deviceType,
configGroup: configGroup,
name: name,
ip: ip,
tenantID: tenantID,
access_token: user.access_token
}
});
}
}
export default new UserService();
server.js:
app.post('/addDevice', (req, res) => {
console.log('Adding new device');
const device = [{
"eid": req.body.eid,
"fields": {
"deviceType": req.body.deviceType,
"configGroup": req.body.configGroup,
"field:name": req.body.name,
"field:ip": req.body.ip
}
}];
axios.post(api_url + "/api/devices", device, {
headers: {
"Authorization": 'Bearer ' + req.query.access_token,
"X-Tenant-ID": req.body.tenantID,
"Content-Type": "application/json"
}
}).then((response) => {
res.send({ status: response.data.message });
}).catch((err) => {
console.log('failed to add device', err);
res.send({ status: 'error' });
});
});
Printing "req.body.tenantID" is undefined. I create a new instance of this class in my React component, and other functions do work. I suspect my calls to "req.body" are not correct, but I'm at a loss right now. Thanks in advance.

How to check email overlap using Axios get and post for SignUp with React?

I'm trying to filter overlap validation for SignUp email.
in my api.js
const token = JSON.parse(localStorage.getItem('token'));
const api = axios.create({
baseURL: baseURL, // already set our base URL
headers: {
Authorization: `Bearer ${token}`,
'Access-Control-Allow-Origin': '*',
}
});
and in my authService.js
const register = (countryCode, name, email, password) => {
return axios
.post('/auth/signup', {
countryCode,
name,
email,
password,
})
.then((response) => {
if (response.headers.authorization) {
console.log(response);
localStorage.setItem('user', JSON.stringify(response.headers.authorization));
}
return response.headers.authorization;
});
};
const login = (email, password) => {
api
.post('/auth/signin', {
email,
password,
})
.then((response) => {
if (response.headers.authorization) {
localStorage.setItem('user', JSON.stringify(response.headers.authorization));
}
return response.data;
});
};
const checkEmail = (email) => {
return api.get('/public/email', { email }).then((response) => {
if (response.data.exist === true) {
return localStorage.getItem('user', JSON.stringify(response.data));
}
return response.data;
});
};
This checkEmail will be in the SignUp.js
for onChange={emailChange}
const onChangeEmail = (e) => {
const email = e.target.value;
if (!email.includes('#')) {
setEmailError('Invalid email');
} else if (email.includes('#')) {
setEmailError(null);
}
AuthService.checkEmail(email).then(
(response) => setEmailError('Already Registered Email'),
(error) => {
console.log(error);
}
);
setEmail(email);
};
after this code,
in the console
it error
Error: Request failed with status code 401
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)
I think inn the api.get(URl, {something})
that {something} is wrong but I don't have any idea for hours...
what can I do for this error??
you can't send body parameter in GET , for that POST,PUT will work,
to send with GET then attach data to the GET url.
example
if your using node server at backend then
api.get('/public/email/'+email).then((resp)=>{
log(resp);
}
collect the data using
router.get("public/email/:youremail",(req,res)=>{
req.param.youremail
}

"Missing required key 'Source' in params"

This is my code:
const aws = require('aws-sdk')
const ses = new aws.SES()
// const myEmail = process.env.EMAIL
// const myDomain = process.env.DOMAIN
const getParamsFromUrl = require('./getParamsFromUrl')
module.exports = (options) => {
const { myEmail, myDomain } = options
function generateResponse (code, payload) {
return {
statusCode: code,
headers: {
'Access-Control-Allow-Origin': myDomain,
'Access-Control-Allow-Headers': 'x-requested-with',
'Access-Control-Allow-Credentials': true
},
body: JSON.stringify(payload)
}
}
function generateError (code, err) {
console.log("hi"+ err)
return {
statusCode: code,
headers: {
'Access-Control-Allow-Origin': myDomain,
'Access-Control-Allow-Headers': 'x-requested-with',
'Access-Control-Allow-Credentials': true
},
body: JSON.stringify(err.message)
}
}
function generateEmailParams (body) {
const { email, name, content } = JSON.parse(body)
console.log(email, name, content)
if (!(email && name && content)) {
throw new Error('Missing parameters! Make sure to add parameters \'email\', \'name\', \'content\'.')
}
return {
Source: myEmail,
Destination: { ToAddresses: [myEmail] },
ReplyToAddresses: [email],
Message: {
Body: {
Text: {
Charset: 'UTF-8',
Data: `Message sent from email ${email} by ${name} \nContent: ${content}`
}
},
Subject: {
Charset: 'UTF-8',
Data: `You received a message from ${myDomain}!`
}
}
}
}
async function sendJSON (event) {
try {
const emailParams = generateEmailParams(event.body)
const data = await ses.sendEmail(emailParams).promise()
return generateResponse(200, data)
} catch (err) {
return generateError(500, err)
}
}
return sendJSON
}
/////handler.js
const options = {
myEmail: process.env.EMAIL,
myDomain: process.env.DOMAIN
}
const { sendJSON, sendFormEncoded } = require('./lambdaMailer')(options)
module.exports.sendJSON = sendJSON
I have defined values on node_env and email in secrets.json file. After running a curl link I am getting the error as:
curl --header "Content-Type: application/json" --request POST --data "{\"source\":\"zyx#gmail.com\",\"destination\":\"abc#gmail.com\",\"name\":\"xyz\",\"subject\":\"Hey!\",\"message\":\"Hey!\"}" https://lyt7frokj4.execute-api.us-east-1.amazonaws.com/dev/email/send
"Missing required key 'Source' in params"
I think it maybe the case-sensitivity issue. According to the docs, there should be Source, not source:
Source: 'STRING_VALUE', /* required */

Axios multiple request on interceptor

I'm using the library axios in my react app.
I'm having a problem with the interceptor.
My question is let say I have three requests happening concurrently and I don't have the token, the interceptor calling the getUserRandomToken three time, I want the interceptor will wait until I'm getting the token from the first request and then continue to the others.
P.S. the token he is with an expiration date so I also checking for it and if the expiration date is not valid I need to create a new token.
This is the interceptor:
axios.interceptors.request.use(
config => {
/*I'm getting the token from the local storage
If there is any add it to the header for each request*/
if (tokenExist()) {
config.headers.common["token"] = "...";
return config;
}
/*If there is no token i need to generate it
every time create a random token, this is a axios get request*/
getUserRandomToken()
.then(res => {
/*add the token to the header*/
config.headers.common["token"] = res;
return config;
})
.catch(err => {
console.log(err);
});
},
function(error) {
// Do something with request error
return Promise.reject(error);
}
);
How about singleton object that will handle the token generations? something similar to this:
const tokenGenerator ={
getTokenPromise: null,
token: null,
getToken(){
if (!this.getTokenPromise){
this.getTokenPromise = new Promise(resolve=>{
/*supposed to be a http request*/
if (!this.token){
setTimeout(()=>{
this.token = 'generated';
resolve(this.token);
},0)
}else{
resolve(this.token);
}
})
}
return this.getTokenPromise;
}
you can reference this same object from the interceptors.
see example: JS FIddle
reference: reference
You can return a Promise from interceptor callback to "wait" until promise fullfiles (this will fit your case). Check out this example:
function axiosCall () {
return new Promise((resolve, reject) => {
Axios.post(URL, {apiKey}).then((response) => {
resolve(response.data.message);
}).catch((error) => {
reject(error);
});
});
}
instance.interceptors.request.use((config) => {
return axiosCall().then((tokenResponse) => {
setWebCreds(tokenResponse);
config.headers.Authorization = `Bearer ${tokenResponse}`;
return Promise.resolve(config)
}).catch(error => {
// decide what to do if you can't get your token
})
}, (error) => {
return Promise.reject(error);
});
More details here: https://github.com/axios/axios/issues/754
Following code doing certain tasks:
Update Token on 401
Make a queue of failed requests while the token is refreshing.
Restore the original request after token refreshing.
Once the peculiar request is given 200, remove it from the queue.
Config.js
import axios from 'axios';
import { AsyncStorage } from 'react-native';
import { stateFunctions } from '../../src/sharedcomponent/static';
const APIKit = axios.create({
baseURL: '',
timeout: 10000,
withCredentials: true,
});
const requestArray = [];
// Interceptor for Request
export const setClientToken = token => {
APIKit.interceptors.request.use(
async config => {
console.log('Interceptor calling');
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
config.headers = {
'Authorization': `Bearer ${userToken}`,
'Accept': 'application/json',
"Content-Type": "application/json",
"Cache-Control": "no-cache",
}
// console.log('caling ' , config)
return config;
},
error => {
Promise.reject(error)
});
};
// Interceptor for Response
APIKit.interceptors.response.use(
function (response) {
if (requestArray.length != 0) {
requestArray.forEach(function (x, i) {
if (response.config.url == x.url) {
requestArray.splice(i, 1);
}
});
}
return response;
},
function (error) {
const originalRequest = error.config;
requestArray.push(originalRequest);
let reqData = "username=" + number + "&password=" + pin + "&grant_type=password" + "&AppType=2" + "&FcmToken=null";
// console.log('error ' , error);
if (error.message === "Request failed with status code 401" || error.statuscode === 401) {
if (!originalRequest._retry) {
originalRequest._retry = true;
return axios({
method: 'post',
url: '/api/login',
data: reqData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Cache-Control": "no-cache",
}
})
.then(res => {
let response = res.data;
console.log('successfull Login', response)
if (res.data.StatusCode == 200) {
AsyncStorage.setItem('userToken', JSON.stringify(response.access_token));
stateFunctions.UserId = response.UserId;
stateFunctions.CustomerContactID = response.CustomerContactID;
let obj = {
access_token: response.access_token,
token_type: response.token_type,
expires_in: response.expires_in,
UserId: response.UserId,
CustomerContactID: response.CustomerContactID,
Mobile: response.Mobile,
StatusCode: response.StatusCode
}
AsyncStorage.setItem('logindetail', JSON.stringify(obj));
if (requestArray.length != 0) {
requestArray.forEach(x => {
try {
console.log(x, "request Url");
x.headers.Authorization = `Bearer ${response.access_token}`;
x.headers["Content-Type"] = "application/x-www-form-urlencoded";
APIKit.defaults.headers.common["Authorization"] = `Bearer${response.access_token}`;
APIKit(x)
} catch (e) {
console.log(e)
}
});
}
return APIKit(originalRequest);
}
})
.catch(err => {
console.log(err);
});
}
}
return Promise.reject(error);
}
);
export default APIKit;
Home.js
gettingToken = async () => {
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
await setClientToken(userToken);
}

Using an async function for a route gives me a 404

I'm running an express server trying to use Outlooks API with node,
The routes are now using async and I copied a snippet from the docs:
The handling of the route:
const handle = {};
handle['/mail'] = mail;
and the function is:
async function mail(response, request) {
let token;
try {
token = await getAccessToken(request, response);
} catch (error) {
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.write('<p> No token found in cookie!</p>');
response.end();
return;
}
console.log('Token found in cookie: ', token);
const email = getValueFromCookie(
'node-tutorial-email',
request.headers.cookie
);
console.log('Email found in cookie: ', email);
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.write('<div><h1>Your inbox</h1></div>');
// Create a Graph client
const client = microsoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, token);
}
});
try {
// Get the 10 newest messages
const res = await client
.api('/me/mailfolders/inbox/messages')
.header('X-AnchorMailbox', email)
.top(10)
.select('subject,from,receivedDateTime,isRead')
.orderby('receivedDateTime DESC')
.get();
console.log(`getMessages returned ${res.value.length} messages.`);
response.write(
'<table><tr><th>From</th><th>Subject</th><th>Received</th></tr>'
);
res.value.forEach(message => {
console.log(' Subject: ' + message.subject);
const from = message.from ? message.from.emailAddress.name : 'NONE';
response.write(
`<tr><td>${from}` +
`</td><td>${message.isRead ? '' : '<b>'} ${message.subject} ${
message.isRead ? '' : '</b>'
}` +
`</td><td>${message.receivedDateTime.toString()}</td></tr>`
);
});
response.write('</table>');
} catch (err) {
console.log(`getMessages returned an error: ${err}`);
response.write(`<p>ERROR: ${err}</p>`);
}
response.end();
}
It should be working... I don't see any errors there. Why am I getting a 404?

Categories

Resources