Use the Mailchimp API - node.js

I'd like to use the Mailchimp Node.js API in my Parse Cloud Hosting app to subscribe a user to a mailing list. Parse doesn't support NPM but, given that the Mailchimp API has no dependencies, I thought I'd be able to copy the code into my project. However, the Mailchimp API uses the "https" module which Parse doesn't support.
Does anyone know of a way around this?

I've been unable to use the Mailchimp API directly but the REST API is pretty easy to use.
In main.js, create a Cloud Function. Enter your API key and update the REST URL to point at the correct Mailchimp data center (http://apidocs.mailchimp.com/api/2.0/)
var mailchimpApiKey = "<<REPLACE_WITH_YOUR_KEY>>";
Parse.Cloud.define("SubscribeUserToMailingList", function(request, response) {
if (!request.params ||
!request.params.email){
response.error("Must supply email address, firstname and lastname to Mailchimp signup");
return;
}
var mailchimpData = {
apikey : mailchimpApiKey,
id : request.params.listid,
email : {
email : request.params.email
},
merge_vars : request.params.mergevars
}
var url = "https://<<REPLACE_WITH_DATA_CENTRE>>.api.mailchimp.com/2.0/lists/subscribe.json";
Parse.Cloud.httpRequest({
method: 'POST',
url: url,
body: JSON.stringify(mailchimpData),
success: function(httpResponse) {
console.log(httpResponse.text);
response.success("Successfully subscribed");
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
console.error(httpResponse.text);
response.error('Mailchimp subscribe failed with response code ' + httpResponse.status);
}
});
});
Then, in the code which calls this function... (replace your list ID)
Parse.Cloud.run("SubscribeUserToMailingList", {
listid : "<<REPLACE_WITH_LIST_ID>>",
email : email,
mergevars : {
FNAME : firstName,
LNAME : lastName
}
})
.then(function(success){
console.log("Successfully subscribed");
// ...
},
function(error){
console.log("Unable to subscribe");
// ...
});

Install mailchimp in your project
npm install mailchimp-api
From client controller call the server-controller with required data
Don't forget to add $http to the top of controller
$http({
method : 'POST',
url : '/mailchimp-users/subscribe',
data : {user:this.name}}).
success(function(response) {
console.log("hai this is basic test" + response);
$scope.send = response.message;
}).error(function(response) {
$scope.error = response.message;
});
In server controller
Add this to the beginning of page
var MailchimpUser = mongoose.model('MailchimpUser'),
_ = require('lodash'),
mcapi = require('mailchimp-api');
var apiKey = '4bf6fb8820c333da4179216c3c2ef8fb-us10';
// Change this to your Key
var listID = 'ebbf193760';
var mc = new mcapi.Mailchimp(apiKey, {version: '2.0'});
Add this function
exports.subscribe = function(req, res) {
var entry = req.body.user;
var mcReq = {
apikey: '4bf6fb8820c333da4179216c3c2ef8fb-us10',
id: 'ebbf193760',
email: {email: entry + '#gmail.com'},
merge_vars: {
FNAME: 'subscriber-first-name',
LNAME: 'subscriber-last-name'
},
'double_optin': false,
'send_welcome': true
}
// submit subscription request to mail chimp
mc.lists.subscribe(mcReq, function(data) {
console.log(data);
}, function(error) {
console.log(error);
});
};
Add this route your route file
app.route('/mailchimp-users/subscribe')
.post(mailchimpUsers.subscribe);

Here's how I got it to work using the MailChimp API v3.0, the method below supports adding/updating a subscriber, as well as adding/removing him to/from a Group!
Prerequisite:
You need to get an MD5 hash method to convert the user's email into a hash.
Here's the one I used: http://www.webtoolkit.info/javascript-md5.html#.Vuz-yjZOwXV
Copy the code in the link, and paste it into a newly created file, name it "md5js.js" for example.
Update the code you copied to start with exports.MD5 = function (string) {
You can test the conversion you got from the copy/pasted module by comparing the result with this online tool: http://www.miraclesalad.com/webtools/md5.php
var jsmd5 = require('cloud/md5js.js');
// here replace that with your own data center (by looking at your API key).
var datacenter = "us13";
var MAILCHIMP_URL = "https://<any_string>:<apikey>#" + datacenter + ".api.mailchimp.com/3.0/";
var MAILCHIMP_LIST_NEWSLETTER_ID = <yourlistId>;
Parse.Cloud.define("SubscribeUserToMailingList", function(request, response) {
if (!request.params ||
!request.params.email){
response.error("Must supply email address, firstname and lastname to Mailchimp signup");
return;
}
var email = request.params.email;
var firstName = request.params.firstname;
var lastName = request.params.lastname;
// this converts the email string into an MD5 hash.
// this is Required if you want to use a "PUT" which allows add/update of an entry, compared to the POST that allows only adding a new subscriber.
var emailHash = jsmd5.MD5(email);
var mailchimpData = {
'email_address': email,
'status': "subscribed",
'merge_fields': {
'FNAME': firstName,
'LNAME': lastName
},
'interests': {
"<groupID>": true // optional, if you want to add the user to a "Group".
}
};
var url = MAILCHIMP_URL + "lists/" + MAILCHIMP_LIST_NEWSLETTER_ID + "/members/" + emailHash;
// using a "PUT" allows you to add/update an entry.
Parse.Cloud.httpRequest({
method: 'PUT',
url: url,
body: JSON.stringify(mailchimpData),
success: function(httpResponse) {
console.log(httpResponse.text);
response.success("Successfully subscribed");
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
console.error(httpResponse.text);
response.error('Mailchimp subscribe failed with response code ' + httpResponse.status);
}
});
});

Related

register webhooks on nodejs when order created

I have a shopify store mystore and I have an nodejs app myapp. I need to do is when something happens on mystore a webhook will be created/registered in my nodejs app. I have tried https://www.npmjs.com/package/#shopify/koa-shopify-webhooks this package but it is not working for me and I don't think that it is the same thing that I want. I just want that when let suppose order is created in store a webhook is registered.
if you just have to register a webhook you can use this code.
You just have to change the webhook topic and the endpoint.
This is for orders/create webhook registration
add shopify-api-node and request-promise packages and require them
const ShopifyAPIClient = require("shopify-api-node");
const request = require("request-promise");
then
const createOrderWebhook = await registerWebhook(yourShopDomain, yourShopAccessToken, {
topic: "orders/create",
address: "Your node app end point" //www.example.com/webhooks/createOrder,
format: "json",
});
add your registerWebhook function
const registerWebhook = async function (shopDomain, accessToken, webhook) {
const shopify = new ShopifyAPIClient({
shopName: shopDomain,
accessToken: accessToken,
});
const isCreated = await checkWebhookStatus(shopDomain, accessToken, webhook);
if (!isCreated) {
shopify.webhook.create(webhook).then(
(response) => console.log(`webhook '${webhook.topic}' created`),
(err) =>
console.log(
`Error creating webhook '${webhook.topic}'. ${JSON.stringify(
err.response.body
)}`
)
);
}
};
for checking the webhook already not created at Shopify you can use following code
const checkWebhookStatus = async function (shopDomain, accessToken, webhook) {
try {
const shopifyWebhookUrl =
"https://" + shopDomain + "/admin/api/2020-07/webhooks.json";
const webhookListData = {
method: "GET",
url: shopifyWebhookUrl,
json: true,
headers: {
"X-Shopify-Access-Token": accessToken,
"content-type": "application/json",
},
};
let response = await request.get(webhookListData);
if (response) {
let webhookTopics = response.webhooks.map((webhook) => {
return webhook.topic;
});
return webhookTopics.includes(webhook.topic);
} else {
return false;
}
} catch (error) {
console.log("This is the error", error);
return false;
}
};
Happy coding :)
You can not create/register a new webhook when the order created.
Webhooks are a tool for retrieving and storing data from a certain event. They allow you to register an https:// URL where the event data can be stored in JSON or XML formats. Webhooks are commonly used for:
Placing an order
Changing a product's price
Notifying your IM client or your pager when you are offline
Collecting data for data-warehousing
Integrating your accounting software
Filtering the order items and informing various shippers about the order
Removing customer data from your database when they uninstall your app

Node.js POST Request through Angular application returns Error 404 “not found"

I am making an API using Node.js that connects to an SQL Server database. My GET requests work well, but my POST request gives me errors. I have divided my node project into two files, a routes file and a controllers file.
The code in my routes file is as follows:
module.exports = (app) => {
const UsrContrllr = require('../Controllers/users.controllers');
//1. GET ALL USERS
app.get('/api/users', UsrContrllr.getAllUsers);
//2. POST NEW USER
app.post('/api/user/new', UsrContrllr.addNewUser);
};
And the code in my controllers file is given below:
const mssql = require('mssql');
exports.getAllUsers = (req, res) =>
{
// Validate request
console.log(`Fetching RESPONSE`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `SELECT * FROM USERS`;
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() === '') {
res.send('Oops!!! Required data not found...');
}
else {
// send records as a response
res.send(recordset);
}
};
});
};
exports.addNewUser = (req, res) =>
{
// Validate request
console.log(`INSERTING RECORD ${req.body}`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `INSERT INTO USERS (USERCODE, PASSWORD, LANGUAGE, USERCLASS, FIRSTNAME, LASTNAME, CONTACTNO) VALUES ('${req.body.usercode}', '${req.body.password}', 'EN', '0', '${req.body.firstname}', '${req.body.lastname}', '${req.body.contactno}');`;
console.log(queryStr);
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() == '') {
res.send('Oops!!! Required data not found...');
}
else {
// Send records as response
res.send(recordset);
}
};
});
};
When I run the POST request from my angular application, I get an HttpErrorResponse, Error 404 not found.
error: “Error: Cannot POST /api/users/new"
message: "Http failure response for http://url:port/api/users/new: 404 Not Found"
name: "HttpErrorResponse"
ok: false
status: 404
statusText: "Not Found”
url: "http://url:port/api/users/new”
The angular code in the service file is as follows:
private url = 'http://url:port/api/users';
signup(fName: string, lName: string, usrCode: string, pwd: string, cntctNbr: string) {
const headers = new HttpHeaders().set('Content-Type', 'application/json');
const newUsr = {
usercode: usrCode,
password: pwd,
firstname: fName,
lastname: lName,
contactno: cntctNbr
}
this.http.post(this.url + '/new', JSON.stringify(newUsr), { headers: headers }).subscribe(data => {
console.log(data);
});
}
I don’t understand why I am unable to add in new users. I’ve been told my code appears fine, but I don’t see any results. Where am I going wrong?
You are receiving a 404 (Not found) error because your POST route is defined as /user/new but in your angular app you are calling http://url:port/api/users/new
Correct the code to the following in your API:
app.post('/api/users/new', UsrContrllr.addNewUser);

Send an otp to the desired mobile number using nodejs

I am using Plivo to send sms to the user for otp verification and i am unable to update mobile number and message parameters for different users, here is my code
global.params = {
'src': 'xx-xxxx', // Sender's phone number with country code
'dst' : '91'+'xxxxxxxxxx', // Receiver's phone Number with country code
'text' : "Hi, message from Plivo", // Your SMS Text Message - English
'url' : "https://intense-brook-8241.herokuapp.com/report/", // The URL to which with the status of the message is sent
'method' : "GET" // The method used to call the url
};
module.exports={
foo: function createOTPverify(mobile_number, id){
var motp = randomize('0',4);
console.log("motp "+motp);
global.params.dst = mobile_number;
global.params.text = "Hi, your verification one time password is "+motp;
p.send_message(global.params, function(status, response){
console.log('Status: ', status);
console.log('API Response:\n', response);
})
}
}
here everything is working fine but unable to update parameters, i tried it using global but still not able to do, please help
You're not updating your config array anywhere. Hence, the issue
Check the below gist, it should help you send OTP
https://runkit.com/isanjayachar/plivo-send-otp
const plivo = require('plivo').RestAPI({
authId: '<your AUTH ID>',
authToken: '<your AUTH TOKEN>',
})
function getParmas(phone, otp) {
return {
'src': 'xx-xxxx',
'dst' : '91'+ phone,
'text' : "Your OTP for verification is " + otp,
'url' : "https://intense-brook-8241.herokuapp.com/report/",
'method' : "GET"
}
}
function sendOTP(phone) {
var otp;
// Generate your OTP here
plivo.make_call(getParmas(phone, otp), function(status, response) {
console.log('Status:' + status)
console.log('Reponse:' + response)
})
}
sendOTP('9999999999');

How to retrieve user's additional information from Azure Mobile/App Services?

I need to get the user's extra information from social accounts like Facebook and Google+. When I first read about Azure Mobile Services I thought it to be the holy grail of social authentication. Well, after a full week of hair pulling I'm starting to reconsider my first impression. It does authenticate as easily as it could possibly do. I configured Google+ and FB to work with Azure, configured Azure to use the key/secret from each provider and it all just worked. I was able to login perfectly. The problem started when I tried to get information from the logged user, which I honestly think is basic!
Azure Mobile Services returns the UserId and a Token that you can not use to request the extra info on the selected provider. So even if I were to create a second request using FB's graph API for instance, that wouldn't work (I've tried!). That token is Azure's own token. So I found out from several Carlos Figueira (SE at Azure) posts that I should customize my Azure script, make a request to Azure and then I'd be able to get it working.
I've also read several posts from Carlos Figueira on how to implement that extra functionality and even though that was not what I was looking for (customizing the server) I decided to work with that. But my return type is a MobileServiceUser and that type only has 2 properties: UserId and MobileServiceAuthenticationToken. So even after adding the server script from Carlos I couldn't retrieve the extra information from my Xamarin App.
I've read a lot of things, researched a lot and couldn't find an answer =/ By the way this is not the answer:
How to get user name, email, etc. from MobileServiceUser?
Did anyone manage to make it work?
PS: I'm not posting any code here because it's working. If you think checking some part of my code would help decipher the problem just let me know.
Thanks in advance!
EDIT:
Script
function insert(item, user, request) {
item.UserName = "<unknown>"; // default
user.getIdentities({
success: function (identities) {
var url = null;
var oauth = null;
if (identities.google) {
var googleAccessToken = identities.google.accessToken;
url = 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' + googleAccessToken;
} else if (identities.facebook) {
var fbAccessToken = identities.facebook.accessToken;
url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
} else if (identities.microsoft) {
var liveAccessToken = identities.microsoft.accessToken;
url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + liveAccessToken;
} else if (identities.twitter) {
var userId = user.userId;
var twitterId = userId.substring(userId.indexOf(':') + 1);
url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
}
if (url) {
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
item.UserName = userData.name;
request.execute();
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
if (oauth) {
reqOptions.oauth = oauth;
}
req(reqOptions, requestCallback);
} else {
// Insert with default user name
request.execute();
}
}
});
}
You're talking about the token on the client side correct? That token is specific only to the client. If you're using Server Side flow, the server is the only one with that token. If you want to send that to the client, you need to do that via a custom API you create.
This class you're talking about does only contain those two properties. But on your server side, your ServiceUser can access the different identity provider tokens in order to speak to those servers APIs. Your linked post is correct in how you access the token, you're mistaken on where you can access that token, it's only on the server side (if you use the server directed login flow).
Here is the custom API Script I had working in Mobile Services to return the profile of the logged in user. I am working on updating to Mobile Apps as some environment variables appear to have changed. Would love to know if anyone has gotten it to work with Mobile Apps.
exports.get = function (request, response) {
var user = request.user;
user.getIdentities({
success: function (identities) {
var req = require('request');
var url = null;
var oauth = null;
var userId = user.userId.split(':')[1];
console.log('Identities: ', identities);
if (identities.facebook) {
url = 'https://graph.facebook.com/me?access_token=' +
identities.facebook.accessToken;
} else if (identities.google) {
url = 'https://www.googleapis.com/oauth2/v3/userinfo' +
'?access_token=' + identities.google.accessToken;
} else if (identities.microsoft) {
url = 'https://apis.live.net/v5.0/me?access_token=' +
identities.microsoft.accessToken;
} else if (identities.twitter) {
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
url = 'https://api.twitter.com/1.1/users/show.json?' +
'user_id=' + userId + '&include_entities=false';
} else {
response.send(500, { error: 'No known identities' });
return;
}
if (url) {
var reqParams = { uri: url, headers: { Accept: 'application/json' } };
if (oauth) {
reqParams.oauth = oauth;
}
req.get(reqParams, function (err, resp, body) {
if (err) {
console.error('Error calling provider: ', err);
response.send(500, { error: 'Error calling provider' });
return;
}
if (resp.statusCode !== 200) {
console.error('Provider call did not return success: ', resp.statusCode);
response.send(500, { error: 'Provider call did not return success: ' + resp.statusCode });
return;
}
try {
var userData = JSON.parse(body);
response.send(200, userData);
} catch (ex) {
console.error('Error parsing response: ', ex);
response.send(500, { error: ex });
}
});
} else {
response.send(500, { error: 'Not implemented yet', env: process.env });
}
}
});
};

Login With Evernote

I'm trying to connect Evernote with Meteor.
But I'm having a really bad time, trying to get the Oauth token, I was trying to follow this example Evernote Sample Meteor, but is pretty old (2 years), but I tried to follow it and I got the idea.
I can get the connect to evernote, the login page and the email verification, my problem raised on the Meteor Method.
handleCallback, which need the "verify" param, which in this case is the
ouath_token
Second try.
On the evernote npm README they suggest to use oAuthjs, and I try with this code.
var hostName = "http://sandbox.evernote.com";
var options,oauth;
options = {
consumerKey: 'xxxxxxxxx',
consumerSecret: 'xxxxxxxxx',
callbackUrl : 'http://localhost:3000/oauth/auth',
signatureMethod : "HMAC-SHA1",
};
oauth.request({'method': 'GET', 'url': hostName + '/oauth',
'success': function(data){
console.log(data);
}, 'failure': function(data){
console.log(data);
}});
But it returns
(STDERR) No valid request transport found.
So I'm pretty stuck here.
The npm module provided by Evernote includes helper functions to get OAuth working.
Install the Evernote npm module via:
$npm install evernote
Below is the simplest single file example of implementing OAuth in a Evernote application I could put together. Just change the values of CONSUMER_KEY and CONSUMER_SECRET below and it should run just fine if you've installed Evernote:
var Evernote = require('evernote').Evernote;
var http = require("http");
var url = require("url");
CONSUMER_KEY="Put your consumer key here";
CONSUMER_SECRET="put your consumer secret here";
if (CONSUMER_KEY === "Put your consumer key here"){
console.error("\nPlease enter your Evernote consumer key and secret\n\nIf you don't have a key you can get one at:\nhttps://dev.evernote.com/#apikey\n")
process.exit(1)
}
var global = {};
global.oauthToken = '';
global.oauthSecret = '';
function getOauthVerifier(url) {
var regex = new RegExp("[\\?&]oauth_verifier=([^&#]*)"),
results = regex.exec(url);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var handler = function(request, response) {
var params = url.parse(request.url)
var pathname = params.pathname;
console.log("Request for " + pathname + " received.");
var client = new Evernote.Client ({
consumerKey: "Put your consumer key here",
consumerSecret: "put your consumer secret here",
sandbox: true
});
if (pathname == "/"){
var callbackUrl = 'http://localhost:8888/oauth';
client.getRequestToken(callbackUrl, function(err, oauthToken, oauthSecret, results){
if(err) {
console.log(err);
}
else {
global.oauthToken = oauthToken;
global.oauthSecret = oauthSecret;
console.log("set oauth token and secret");
var authorizeUrl = client.getAuthorizeUrl(oauthToken);
console.log(authorizeUrl);
response.writeHead(200, {"Content-Type":"text/html"});
response.write("Please click here to authorize the application");
response.end();
}
});
}
else if (pathname == "/oauth"){
client.getAccessToken(
global.oauthToken,
global.oauthSecret,
getOauthVerifier(params.search),
function(error, oauthAccessToken, oauthAccessTokenSecret, results) {
if(error) {
console.log("error\n\n\n");
console.log(error);
}
else {
response.writeHead(200, {"Content-Type":"text/html"});
response.write(oauthAccessToken);
response.end();
}
}
);
}
else {
response.writeHead(200, {"Content-Type":"text/html"});
response.write("not a valid URL GO HOME ");
response.end();
}
};
http.createServer(handler).listen(8888);

Resources