MailChimp API 3.0 Subscribe - asp.net

I am having trouble sorting out the new MailChimp API (V3.0). It does not seem like there is a way to call a subscribe method. It seems like I have to use their Sign Up Form. Am I correct?

If by "subscribe" you mean that your application will add someone to a mailing list, you may want to take a look at the List Members Collection portion of their documentation.
http://kb.mailchimp.com/api/resources/lists/members/lists-members-collection

Adding/editing a subscriber via MailChimp v3.0 REST API.
// node/javascript specific, but pretty basic PUT request to MailChimp API endpoint
// dependencies (npm)
var request = require('request'),
url = require('url'),
crypto = require('crypto');
// variables
var datacenter = "yourMailChimpDatacenter", // something like 'us11' (after '-' in api key)
listId = "yourMailChimpListId",
email = "subscriberEmailAddress",
apiKey = "yourMailChimpApiKey";
// mailchimp options
var options = {
url: url.parse('https://'+datacenter+'.api.mailchimp.com/3.0/lists/'+listId+'/members/'+crypto.createHash('md5').update(email).digest('hex')),
headers: {
'Authorization': 'authId '+apiKey // any string works for auth id
},
json: true,
body: {
email_address: email,
status_if_new: 'pending', // pending if new subscriber -> sends 'confirm your subscription' email
status: 'subscribed',
merge_fields: {
FNAME: "subscriberFirstName",
LNAME: "subscriberLastName"
},
interests: {
MailChimpListGroupId: true // if you're using groups within your list
}
}
};
// perform update
request.put(options, function(err, response, body) {
if (err) {
// handle error
} else {
console.log('subscriber added to mailchimp list');
}
});

Related

In Meteor with Iron router how would I redirect to a thank you URL stored in the database after form submission

I have a system written in meteor where when someone submits a form it currently just shows a thankyou message in a modal. My client wants to be able to allow for multiple different thank you pages based on a thank you URL field on a clients record.
I am using iron router. I have successfully setup a server side route but I'm unable to even call that.
What I would like is to on form submission update the database then pull the clients thankyou URL and redirect the user to that. Sorry for not code to tweak but I'm just looking for the best way to handle it.
UPDATE:
Client Side
Meteor.call(
"addSendLeads",
{
bookingType: bookingType,
ad_platfrom: ad_platform,
senderID: email,
facebookPageID: fbPageID,
first_name: first_name,
last_name: last_name,
event_name: event_name,
startDate: startDate,
email: email,
phone: phone,
comments: comments,
},
(err) => {
if (err) {
console.log(err);
swal(
"Error",
"Sorry, there was an error. Please try again later."
);
} else {
target.firstName.value = "";
target.lastName.value = "";
target.email.value = "";
target.phone.value = "";
target.comments.value = "";
Router.go("/thankyou/" + url);
}
}
);
The Route in server/routes.js
Router.route("/thankyou/:url", { where: "server" }).get(function () {
this.response.writeHead(302, {
Location: url,
});
this.response.end();
});
Hope this helps to clarify...
Your submit form method should return your user custom URL, unless you pull that in the initial stage when you open the form.
With a method, you have a callback (pre Node16) or a .then(result => do_something_with_it). Async methods are already usable in Meteor 2.10.
Your call back or your async effect can call your routing:
Meteor.callAsync('submitForm', form) // or Meteor.call('name', {object data}, (err, res) => do_something_with_res)
.then(url => Router.go(url)
.catch(methodErrors => console.log(methodErros))

Contact Form 7 Recaptcha 3 headless site

I am building a wordpress headless site (frontend using Nuxt.js) and am trying to use recaptcha v3 in contact form 7 . I have already setup the integration using the built in cf7 integration.
But, the problem is contact form 7 is marking all of my emails as spam. Therefore I installed Flamingo plugin just to see the error log. Apparently the error log says reCAPTCHA response token is empty. Which makes sense because the recaptcha is setup in WordPress while since my frontend is decoupled, it doesn't get the token.
I have read about using vue-recaptcha but that means setting up a new recaptcha that is entirely separate from the recaptcha I setup in WordPress. I can't find a way to link the recaptcha for WordPress and my frontend together.
Any advice would be very much appreciated, thanks!
A post that I found similar to mine:
https://www.reddit.com/r/Wordpress/comments/o48hd1/contact_form_7_plugin_endpoint_for_recaptcha/
, but no clear answers.
I am successful in implementing recaptcha at the frontend right now but I have no idea how to make use of the recaptcha token from WordPress for the backend and frontend to work together. The recaptcha certainly cannot be only at the frontend because else people would be able to use Postman to spam my endpoint. This is how I did it:
async function verifyCaptcha() {
try {
// #ts-ignore
recaptchaToken.value = await context.$recaptcha.execute();
const response = await axios.post(
`/captcha-api/siteverify?secret=${process.env.SECRET_KEY}&response=${recaptchaToken.value}`
);
// console.log(response)
return response;
} catch (error) {
return error;
}
}
async function onSubmit(e: any) {
const recaptchaResponse = await verifyCaptcha();
// Display error message if verification was not successful
if (!recaptchaResponse.data.success) {
// #ts-ignore
context.$recaptcha.reset()
return;
}
// If verification was successful, send the message
await submit(e);
}
I have found the solution. We simply need to pass some specific recaptcha 3 responses required by contact form 7 back to contact form 7.
const token = await context.$recaptcha.execute('login')
// console.log('ReCaptcha token:', token)
const emailBody = {
"your-name" : form.name,
"email" : form.email,
"enquiry" : form.enquiry,
"message" : form.message,
//recaptcha responses to pass back to CF7
"_wpcf7_recaptcha_response" : token,
"wpcf7_recaptcha_response" : token,
"recaptcha_response" : token,
"recaptcha" : token,
"token" : token
}
const body = new FormData()
for (const field in emailBody) {
// #ts-ignore
body.append(field, emailBody[field])
}
const headers = {
'Content-Type': 'multipart/form-data',
}
const response = await axios.post('https://yourdomain.com/wp-json/contact-form-7/v1/contact-forms/{id}/feedback', body, { headers: headers})
// Use responseData to check its status to do some logic
const responseData = response.data
onMounted(async () => {
await context.$recaptcha.init()
})
onBeforeUnmount(() => {
context.$recaptcha.destroy()
})

How to check if logged in via 3rd party service in Meteor framework?

How do you check whether a user is logged in via third party (Google, Facebook, ...) in the Meteor framework? Also, is this possible from the client?
There are multiple ways to do it. On the Server side you would have a function like Accounts.onCreateUser((options, user) => {... }).
If you already publish minimum data of the user, you can add a key using onCreateUser and save something like: loginVia: "email" or "FB" etc. Then you publish that key or get its value with a method.
The straight forward solution is to check if the social service exists if look for a particular service.
For Example:
const isFBUser: Meteor.users.find({ _id :.... }, { 'services.facebook': { $exists: true } }).count() // results in 1 record or 0 records = true / false
of if you want to know if the user is coming via email and not third party you can check for emails
const isThirdParty = Meteor.users.find({_id: ...}, emails: { $exists: true })
It is pretty common to also use a merge accounts system so that someone coming from FB with the email gigi#gmail.com will letter be allowed to log in to you app with the email instead of the social account. In this case, you would need to eventually save the source of the last login.
I'll leave here for you part of my onCreateUser as example of how to pull data out of a 3rd party user and save it in the use profile. On the same lines you can save the 3rd party source (as suggested above)
if (user.services) {
const fb = user.services.facebook
const google = user.services.google
let avatar = null
let fbi = null // I use this to keep a record of the FB user Id
let ggli = null // // I use this to keep a record of the Google user Id
if (fb) {
/**
* I upload to S3 and I don't wait for a response. A little risky...
*/
put_from_url(`https://graph.facebook.com/${fb.id}/picture?width=500&height=500`, `avatar/${fb.id}.jpg`, (err, res) => {
if (err) {
console.log('Could not upload FB photo to S3, ', err)
} else {
// console.log(res)
}
})
user.profile = extend(user.profile, {
firstName: fb.first_name,
lastName: fb.last_name,
email: fb.email,
displayName: fb.name,
gender: startCase(toLower(fb.gender)),
avatar: `${fb.id}.jpg`
})
avatar = `${fb.id}.jpg`
fbi = fb.id
roles = ['user', 'social']
}
if (google) {
/**
* I upload to S3 and I don't wait for a response. A little risky...
*/
put_from_url(google.picture + '?sz=500', `avatar/${google.id}.jpg`, err => {
if (err) {
console.log('Could not upload Google photo to S3, ', err)
}
})
user.profile = extend(user.profile, {
firstName: google.given_name,
lastName: google.family_name,
email: google.email,
displayName: google.name,
gender: startCase(toLower(google.gender)),
avatar: `${google.id}.jpg`
})
avatar = `${google.id}.jpg`
ggli = google.id
roles = ['user', 'social']
}
/**
* Create a slug for each user. Requires a display name for all users.
*/
let slug
slug = Meteor.call('/app/create/slug', user.profile.displayName, 'user')
Also please check the user object structure:
And check this out. Users via 3rd party don't have the email field so you can check its existence.

Reading firebase data to answer Dialogflow query from Firebase Database

Thanks for your time in reading this query. I am implementing a Dialogflow bot using google cloud functions and firebase.
The use case, I wish to design is that
User says "I wish to know information about New York"
Dialog flow captures the intent "lookingForInformation" with Geo.City parameter as "New York" and Action as getInfo.
I have set up Google cloud functions and integrated with Apiai as well as Firebase.
My Firebase Json looks like
{
information :
{
1 :
{
destinationName : "New Jersey",
DestinationInfo : "Its a nice place"
},
2 :
{
destinationName : "London",
DestinationInfo : "Its a lovely place"
},
}
}
My Google cloud function like this
function processV1Request (request, response) {
let action = request.body.result.action; // https://dialogflow.com/docs/actions-and-parameters
let parameters = request.body.result.parameters; // https://dialogflow.com/docs/actions-and-parameters
let inputContexts = request.body.result.contexts; // https://dialogflow.com/docs/contexts
let requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
const googleAssistantRequest = 'google'; // Constant to identify Google Assistant requests
const app = new DialogflowApp({request: request, response: response});
// Create handlers for Dialogflow actions as well as a 'default' handler
const actionHandlers = {
// The default welcome intent has been matched, welcome the user (https://dialogflow.com/docs/events#default_welcome_intent)
// Default handler for unknown or undefined actions
'checkDestination': () =>{
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
if (requestSource === googleAssistantRequest) {
let responseToUser = {
speech: 'I wish to check destinations', // spoken response
text: 'I wish to check destinations' // displayed response
};
sendGoogleResponse(responseToUser);
} else {
console.log(mySet);
let responseToUser = {
speech: 'I wish to check destinations', // spoken response
text: 'I wish to check destinations' // displayed response
};
sendResponse(responseToUser);
}
},
};
I wish to update the above cloud function above to query the firebase database, if the parameter geo.city exist as valid destination in my database. If yes, it should return the information from database, if 'No', it should respond with "Sorry, I don't have information about this city".
Warm Regards

How to make sign-up invitation only?

Using Meteor accounts (and accounts-ui) is there an easy way to make new user sign-ups invitation only? For example by providing an invitation link or an invitation code.
The only thing related I could find in the Meteor documentation is Meteor.sendEnrollmentEmail but it doesn't solve my problem.
You can do this with the built in package, but I found it alot easier and powerful to roll a simple implementation.
You'll need to:
Create a collection, eg UserInvitations to contain the invites to become a user.
Create UI for making UserInvitations / insert some using meteor mongo
Using iron-router or similar create a route, eg:
Router.map ->
#route 'register',
path: '/register/:invitationId'
template: 'userRegistration'
data: ->
return {
invitationId: #params.invitationId
}
onBeforeAction: ->
if Meteor.userId()?
Router.go('home')
return
When the form in userRegistration is submitted - call
Accounts.createUser({invitationId: Template.instance().data.invitationId /*,.. other fields */})
On the server, make an Accounts.onCreateUser hook to pass through the invitationId from options to the user
Accounts.onCreateUser(function(options, user){
user.invitationId = options.invitationId
return user;
});
Also, on the server make an Accounts.validateNewUser hook to check the invitationId and mark the invitation as used
Accounts.validateNewUser(function(user){
check(user.invitationId, String);
// validate invitation
invitation = UserInvitations.findOne({_id: user.invitationId, used: false});
if (!invitation){
throw new Meteor.Error(403, "Please provide a valid invitation");
}
// prevent the token being re-used.
UserInvitations.update({_id: user.invitationId, used: false}, {$set: {used: true}});
return true
});
Now, only users that have a valid unused invitationId can register.
EDIT: Oct 2014 - Updated to use meteor 0.9.x API's
To do it with the built in stuff, you can plumb together the existing Accounts.sendEnrollmentEmail - however it's a little more complicated than the other solution given.
Using the example code below, call the enroll method as such:
Meteor.call('enroll', 'john.smith', 'js#harvard.edu', {name: 'John Smith'});
Meteor will then email the user a link (You can configure the template with Accounts.emailTemplates)
When they click the link, meteor calls the function passed to Accounts.onEnrollmentLink - in this case you can take them to a password setup page; but you have to mess around with their done callback.
Modify the following code, where it says INSERT XXX HERE ; then in your code call SomeGlobalEnrollmentObjectThing.cancel() if the user cancels, or SomeGlobalEnrollmentObjectThing.complete(theUsersNewPassword) if they submit the new password.
if (Meteor.isServer){
Meteor.methods({
"enroll": function(username, email, profile){
var userId;
check(username, String);
check(email, String); // Or email validator
check(profile, {
name: String
}); // your own schema
// check that the current user is privileged (using roles package)
if (!Roles.isInRole(this.userId, 'admin')){
throw new Meteor.Error(403);
}
userId = Accounts.createUser({
username: username,
email: email,
profile: profile
});
Accounts.sendEnrollmentEmail(userId);
}
});
} else {
// uses `underscore`, `reactive-var` and `tracker` packages
function Enrollment(){
this.computation = null;
this.token = new ReactiveVar(null);
this.password = new ReactiveVar(null);
this.cancelled = new ReactiveVar(false);
this.done = null;
this._bind();
}
_.extend(Enrollment.prototype, {
_bind: function(){
Accounts.onEnrollmentLink(_.bind(this.action, this));
},
reset: function(){
this.token.set(null);
this.password.set(null);
this.cancelled.set(false);
this.done = null;
if (this.computation !== null){
this.computation.stop();
this.computation = null;
}
},
cancel: function(){
this.cancelled.set(true);
},
complete: function(password){
this.password.set(password);
},
action: function(token, done){
this.reset();
this.token.set(token);
this.done = done;
this.computation = Tracker.autorun(_.bind(this._computation, this));
// --- INSERT REDIRECT LOGIC HERE [TAKE TO PASSWORD SETUP PAGE]--- //
},
_computation: function(){
var password;
if (this.cancelled.get()){
this.reset();
this.done();
// --- INSERT REDIRECT LOGIC HERE [USER CANCELLED]--- //
} else {
password = this.password.get();
if (password !== null){
Accounts.resetPassword(this.token.get(), password, _.bind(this._complete, this));
}
}
},
_complete: function(err){
// TODO - check if we were reset before callback completed
this.reset();
this.done();
if (err){
// --- INSERT REDIRECT LOGIC HERE [RESET FAILED] --- //
} else {
// --- INSERT REDIRECT LOGIC HERE [SUCCESS] --- //
}
}
});
SomeGlobalEnrollmentObjectThing = new Enrollment();
}
I have created a specific solution to this, since all the other solutions only allow you to explicitly create password-based accounts. The t3db0t:accounts-invite package allows account creation with any service only when you allow them, such as with an 'accept invitation' route. Live demo here.

Resources