How to create a referral link in nodejs - node.js

Am trying to figure out a way of creating a unique referral link that directs to my site for each user that signs up for my site, but to be sincere i don't really know how it works out for sure, I have tried googling for it, but i can't find a perfect answer for it, any plugin needed or any way around that.
The user model, no much code i don't have any idea of this
var UserSchema = new mongoose.Schema({
username: String,
password: String,
referralLink: String
})
UserSchema.plugin(passortLocalMongoose);
module.exports = mongoose.model("User", UserSchema )
user sign up
router.post("/register", function(req,res){
var newUser = new User({username: req.body.username,referral: req.body.referral});
User.register(newUser, req.body.password, function(error, user){
if(error){
console.log(error)
req.flash("signerror", error.message)
return res.redirect("/register")
}
//Do the referral link creation stuff here, don't know for sure
})
})
if there is a way for this, would be glad if you help out

How to create a referral link?
Let this be a platform/language agnostic how-to:
Every time new User is created, generate unique link for him to be his unique referral link and store it in DB (For simplicity this could be _id which is unique in MongoDB and is auto-generated - in this case you don't have to create another field). Let's also keep count of how many people registered through this person's link, let it be referredCount.
Referral link could look for example like this: /register?referrer=${_id}, where ${_id} is user unique ID.
Send referral link to user, so he can pass it along to other people, or make it visible in his /account page - obvious step
When someone registers via this link, create new User as usual and after succesful creation, get req.query.referrer from the URL, look into DB for user with this particular ID and increase his referredCount.
Note that it's just a way of doing that, I'm sure there might be many different strategies for it.

I suggest that you create a table/collection for referrals.
Schema could contain:
userId (the user who generated the link)
numberOfUses (the number of times the link can be used)
expires at (incase you want to limit the validity to a specific period)
MongoDB will generate a _id aka referralId
You can modify the registration endpoint to accept an optional param referralId
Whenever someone uses a referal you just get the userId of the person who created the invite link.

To address Your question from the comment:
You can follow #Tomasz suggestion however to keep referral link You can use cookies.
A cookie is a small piece of data which is stored in a user’s web browser when they visit a website. When a customer comes to your website via an affiliate referral link (i.e. yoursite.com/?ref=123), application should store two main browser cookies in order to track the referring affiliate, and the visit. Their names are:
aff_ref - this cookie stores the affiliate's unique ID
aff_ref_visit_id - this cookie stores the visit ID (the visit ID increments by 1, each time any referral link is used until the cookie expires or is deleted).
So You are able to detect if user came to website using referral link by checking the cookie. It is worth to mention that
cookies should remain in the browser throughout the purchase or conversion process to track the correct affiliate so a referral can be generated for that affiliate. The cookies should also remain in the customer's browser for a period of time specified by the site admin or until the customer clears their cookies.

in the user schema .. have a field named referral (either be a name, number or takes another user's Id ) ...on the main site. create a button that will generate a user's personal referral link (using Javascript) so that the link will look like "your-domain.com/register?register=${user._id} ... then on the registration page ... there will be an hidden input field ... which will automatically be field with the query param ...
location.search so that when a user register ... the person that referred them will also be registerd ... then the route will be like
app.post('/register',(req,res) =>{
user.update({id:(req.query.register)},{referral:req.body.name})
...remaining registration routing ...
})

Related

How can I generate user's QR-code in node.js?

First off, I need some suggestions regarding QR code in my app.
I am building a parking-management app in node.js in which there are different tables like user, booking, parking etc.
Now, Users will search for parking availability and book one parking-slot and based on that details the QR code will be generated. now whenever user go to that parking place he needs to show that QR-code to the parking attendant. The parking attendant will scan the QR code and will verify the details and the in database there is a field called isStarted will become true(Initially it was false). So the questions are:
Do I need to generate QR-code in the back-end and store it to the database or It will be generated from the front-end Side?(I think I don't need to generate it in the backend I just need to decrypt it)
If it generates on the front-end then what approach should I take to decrypt it?
It is not related to the QR-code but still asking. I want to notify the merchant(parking-owner) about the details of user who wants to park their vehicle in the merchant's space. How can I do that with node.js? I have some code already written by someone which is as following but I don't understand what it is.
let notification_data = {
name: `${owner.basicInfo.fullName}`,
date: dayjs(req.body.date).format("MMM DD, YYYY"),
startTime: req.body.startTime,
};
let { title, body } = notificationTypes.addBooking(notification_data);
let data = {
senderId: req.data.id,
receiverId: req.body.walkerId,
title,
body,
};
sendNotification(data);
Can anyone here help me with above queries?
you're welcome,
You can create a token user data in the backend by using the JWT library,
and append in query link you want for example:
https://example.com/page1?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlNWI4OTdmODhlMDYxMzFlZjA2MDA5OSIsInR5cGUiOiJ2aWV3ZXIiLCJ0b2tlblR5cGUiOiJhY2FkZW15IiwiaWF0IjoxNjU5MzU4MDE0f
and in page example.com/page1 send request to back-end with token in query and in back-end decrypt token and use it.
for notification use https://www.npmjs.com/package/fcm-node and send notification This link can help you : https://code-boxx.com/push-notifications-nodejs/
You can leave the creation of the QR code to the frontend, but with the data that the backend sends to the frontend, and in this way, the frontend can also scan the photo and send the scanned data to the backend, and any necessary operation can be done in this way.
You can also have the QR code through the back through the link below:
https://www.npmjs.com/package/qrcode
Regarding question number three, you can also use FCM and web push mechanism.

Stripe - create / retrieve customer in one call

Is there a stripe API call that we can use to create a user if they don't exist, and retrieve the new user?
say we do this:
export const createCustomer = function (email: string) {
return stripe.customers.create({email});
};
even if the user with that email already exists, it will always create a new customer id. Is there a method that will create a user only if the user email does not exist in stripe?
I just want to avoid a race condition where more than one stripe.customers.create({email}) calls might happen in the same timeframe. For example, we check to see if customer.id exists, and does not, two different server requests could attempt to create a new customer.
Here is the race condition:
const email = 'foo#example.com';
Promise.all([
stripe.customers.retrieve(email).then(function(user){
if(!user){
return stripe.customers.create(email);
}
},
stripe.customers.retrieve(email).then(function(user){
if(!user){
return stripe.customers.create(email);
}
}
])
obviously the race condition is more likely to happen in two different processes or two different server requests, than the same server request, but you get the idea.
No, there is no inbuilt way to do this in Stripe. Stripe does not require that a customer's email address be unique, so you would have to validate it on your side. You can either track your users in your own database and avoid duplicates that way, or you can check with the Stripe API if customers already exist for the given email:
let email = "test#example.com";
let existingCustomers = await stripe.customers.list({email : email});
if(existingCustomers.data.length){
// don't create customer
}else{
let customer = await stripe.customers.create({
email : email
});
}
Indeed it can be solved by validating stripe's customer data retrieval result against stored db.
And then call another API to create afterward.
However for simplicity sake, i agree with #user7898461 & would vouch for retrieveOrCreate customer api :)
As karllekko's comment mentions, Idempotent Keys won't work here because they only last 24 hours.
email isn't a unique field in Stripe; if you want to implement this in your application, you'll need to handle that within your application - i.e., you'll need to store [ email -> Customer ID ]s and do a lookup there to decide if you should create or not.
Assuming you have a user object in your application, then this logic would be better located there anyways, as you'd also want to do this as part of that - and in that case, every user would only have one Stripe Customer, so this would be solved elsewhere.
If your use case is like you don't want to create a customer with the same email twice.
You can use the concept of stripe idempotent request. I used it to avoid duplicate charges for the same order.
You can use customer email as an idempotent key. Stripe handles this at their end. the two request with same idempotent key won't get processed twice.
Also if you want to restrict it for a timeframe the create an idempotent key using customer email and that time frame. It will work.
The API supports idempotency for safely retrying requests without
accidentally performing the same operation twice. For example, if a
request to create a charge fails due to a network connection error,
you can retry the request with the same idempotency key to guarantee
that only a single charge is created.
You can read more about this here. I hope this helps

REST API Endpoint for changing email with multi-step procedure and changing password

I need help for creating the REST endpoints. There are couple of activities :
To change the email there are 3 URL requests required:
/changeemail : Here one time password (OTP) is sent to the user's mobile
/users/email : the user sends the one time password from previous step and system sends the email to the new user to click on the email activate link
/activateemail : user clicks on the link in the new email inbox and server updates the new email
To change password :
/users/password (PATCH) : user submits old password and new password and system accordingly updates the new password
Similarly, there are other endpoints to change profile (field include bday, firstname and last name)
after reading online I believe my system as only users as the resource --> so to update the attributes I was thinking of using a single PATCH for change email and change password and along with that something like operation field so the above two features will look like :
For changing email :
operation : 'sendOTPForEmailChange'
operation : 'sendEmailActivationLink'
operation : 'activateEmail'
For changing password :
operation : 'changePassword'
and I will have only one endpoint for all the above operations that is (in nodejs) :
app.patch('/users', function (req, res) {
// depending upon the operation I delegate it to the respective method
if (req.body.operation === 'sendOTPForEmailChange') {
callMethodA();
} else if (req.body.operation === 'sendEmailActivationLink') {
callMethodB();
} else if (req.body.operation === 'activateEmail') {
callMethodC();
} else if (req.body.operation === 'changePassword') {
callMethodC();
} else sendReplyError();
});
Does this sound a good idea ? If not, someone can help me form the endpoints for changeemail and changepassword.
Answer :
I finally settled for using PATCH with operation field in the HTTP Request Body to indicate what operation has to be performed.
Since I was only modifying a single field of the resource I used the PATCH method.
Also, I wanted to avoid using Verbs in the URI so using 'operation' field looked better.
Some references I used in making this decision :
Wilts answer link here
Mark Nottingham' blog link article
and finally JSON MERGE PATCH link RFC
You should make the links that define the particular resource, avoid using PATCH and adding all the logic in one link keep things simple and use separation of concern in the API
like this
1- /users/otp with HTTP Verb: GET -> to get OTP for any perpose
2- /users/password/otp with HTTP Verb: POST -> to verify OTP for password and sending link via email
3- /users/activate with HTTP Verb: POST to activate the user
4- /users/password with HTTP Verb: PUT to update users password
Hashing Security is a must read, IMHO, should you ever want to implement your own user account system.
Two-factor identification should always be considered, at least as an opt-in feature. How would you integrate it into your login scheme ?
What about identity federation ? Can your user leverage their social accounts to use your app ?
A quick look at Google yielded this and this, as well as this.
Unless you have an excellent reason to do it yourself, I'd spend time integrating a solution that is backed by a strong community for the utility aspects of the project, and focus my time on implementing the business value for your customers.
NB: my text was too long for the comments
Mostly agree with Ghulam's reply, separation of concerns is key. I suggest slightly different endpoints as following:
1. POST /users/otp -> as we are creating a new OTP which should be returned with 200 response.
2. POST /users/email -> to link new email, request to include OTP for verification.
3. PUT /users/email -> to activate the email.
4. PUT /users/password -> to update users password.

Using customer object information in private app

I'm currently trying to build a private app which will allow me to create a form which customers can use to update info like name, email address, etc.
I know that I can access this information in my template through the customer object:
https://help.shopify.com/themes/liquid/objects/customer
I also believe that I can send http requests through the admin api which would allow me to update a given customer object:
https://help.shopify.com/api/reference/customer#update
This is an example PUT request from that page
PUT /admin/customers/#{id}.json
{
"customer": {
"id": 207119551,
"email": "changed#email.address.com",
"note": "Customer is a great guy"
}
}
I think that in order to use this api (or at least use it securely) I need to use a private app. I found the following npm package which I would use to create the private app:
https://www.npmjs.com/package/shopify-node-api
This is an example of a PUT request from that page (I think this can be modified for customers):
var put_data = {
"product": {
"body_html": "<strong>Updated!</strong>"
}
}
Shopify.put('/admin/products/1234567.json', put_data, function(err, data, headers){
console.log(data);
});
Does anyone have any experience doing this as I'm unsure about a few things.
Will this PUT request be called when the url is loaded? So if I have an
<a> tag with href="/admin/products/1234567.json the request would load?
If so, this seems quite useless with the customer ID hardcoded in. Can I pass in the customer ID of whoever is logged in and clicking the link and use that as the last part of the request url somehow? In addition to this would it be possible to grab the form data that the user enters to use as the value for "email" or "note?
You should check out this answer shopify app proxy: send customer data or only customer ID for some pointers, discussion and links.
tl/dr; Don't rely on only the logged in customer id or you'll be opening yourself up to easy hackery.
So bascially you update the customer with the PUT you outlined in your question.
To get the id securely you:
Create a form with the customer id and make sure you have a server generated hash of that customer id to thwart bots (that's the reference post)
You post the customer data to a an app via a proxy url
You update the customer via a PUT to a constructed url.

Pulling user's name and photo with Passport.js

I am developing a node.js app and recently figured out how to authenticate via GitHub. I want to know if there is a way to pull a user's profile photo and name so I can display it elsewhere in the app. I found this question, but it looks like Facebook and Google use different methods of obtaining these things.
Can someone point me in the right direction?
Passport module developers usually normalize the user profile object so some standard fields are available in the same way across all modules in this way:
profile.id - assigned by the provider
profile.username - their 'login'
profile.displayName - full name of the user
profile.profileUrl - user's profile page on the provider's site
profile.emails - array of email addresses, but usually just a single address
Thus, you already have the username and/or displayname. One down!
These cover what is consistently needed, but providers can return other information. This naturally depends upon (a) what kind of services the provider offers and (b) the requested scopes.
The provider-specific info isn't lost. It is stored in profile._json next to the normalized properties...and inspecting this will show what else you have to work with.
For Github profile photos/images, you'll be looking for a gravatar_id property to get the user's photo URL.
You can confirm this, using the boilerplate example from passport-github for illustration purposes only, you could do something like this to see what Github is handing back to you so you can evaluate the entire provider response:
passport.use(new GitHubStrategy({
// authentication stuff here, per `passport-github` docs
},
function(accessToken, refreshToken, profile, done) {
// skipping error handling &c for brevity...
fs.writeFile("githubProfile.json", JSON.stringify(profile));
return done(null, profile);
});
}
));
If correct, you could then grab the user photo URL from profile._json.gravatar for use in whatever way you need (saving to database, inserting into a profile page, etc).

Resources