How to get (write) token in the ResetPasswordToken Session? - meteor

I wrote a Reset Password function :
the user collection (services>password>reset) is well setted
the mail is sended well
the link in the mail route me to the right url (right token in it)
on this page, the session resetPasswordToken is set but with
undefined value: I can't automatically write the token here - if I write manually the token here, everything's fine, the password is well reseted, the session resetPasswordToken is after that well setted to null.
So how to write the token in the session ? Thanks.
Below my code.
**
The link client to get a new password
<p class="info">Resend verification link</p>
The event on click (client)
Template.UserProfile.events({
//resend verification link function
'click .send-reset-password-link' ( event, template ) {
Meteor.call( 'sendResetPasswordLink', ( error, response ) => {
if ( error ) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
let email = Meteor.user().emails[ 0 ].address;
Bert.alert({
title: 'Reset Password Link sended',
message: 'Please check your mails.',
type: 'info'
});
}
});
}
});
The method to send the link (server)
Meteor.methods({
sendResetPasswordLink() {
let userId = Meteor.userId();
if ( userId ) {
return Accounts.sendResetPasswordEmail( userId );
}
}
});
The resetpassword email template (server)
//resetPassword Template
Accounts.emailTemplates.siteName = "Me";
Accounts.emailTemplates.from = "Me <my#mail.com>";
Accounts.emailTemplates.resetPassword.subject = function (user) {
return "Reset Your Password";
};
// html template
Accounts.emailTemplates.resetPassword.html = function (user, url) {
SSR.compileTemplate( 'htmlEmail', Assets.getText( 'emailverification.html' ) );
let emailAddress = user.emails[0].address,
userAvatar = user.profile.avatar,
urlWithoutHash = url.replace( '#/', '' );
var emailData = {
urlWithoutHash: `${urlWithoutHash}`,
userAvatar: `${userAvatar}`,
};
return SSR.render( 'htmlEmail', emailData );
};
The route
FlowRouter.route( '/reset-password/:token', {
name: 'reset-password',
action( params ) {
BlazeLayout.render('ResetPassword', {content: 'body'});
Accounts.resetPassword( params.token, ( error ) =>{
if ( error ) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
FlowRouter.go( '/' );
}
});
}
});
And finally, the resetpassword template
//resetpassword.html
<template name="ResetPassword">
<form action="/reset-password" class="reset-password" id="resetPasswordForm" method="post">
<input id="resetPasswordPassword" name="password" placeholder="New Password" type="password" >
<!-- <input id="resetPasswordPasswordConfirm" name="password-confirm" placeholder="Confirm" type="password" > -->
<button class="btn-submit" type="submit" value="Reset">Reset</button>
</form>
<!-- end #reset-password-form -->
</template>
//resetpassword.js
if (Accounts.resetPassword) {
Session.set('resetPasswordToken', Accounts.resetPassword);
}
Template.ResetPassword.helpers({
resetPassword: function(){
return Session.get('resetPasswordToken');
}
});
Template.ResetPassword.events({
"submit .reset-password": (event) => {
// Prevent default browser form submit
event.preventDefault();
//let token;
// Get value from form element
const target = event.target;
const password = event.target.password.value;
// If the password is valid, we can reset it.
if (password) {
//Accounts.resetPassword(token, password, (error) => {
Accounts.resetPassword(Session.get('resetPasswordToken'), password, (error) => {
if (error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
Bert.alert({
title: 'Success',
message: 'Account successfully created.',
type: 'success'
});
Session.set('resetPasswordToken', null);
//Router.go('postsList');
}
});
} else {
Bert.alert({
title: 'Error',
message: 'The password cannot be empty.',
type: 'danger'
});
}
}

Related

Is it possible to call a Method inside another Meteor.call?

I've got two methods on a same event click .open-message :
sendEmailContact : this method send a mail
openMessage : this method update the message (from new state to responded state)
The two methods are working fine, but separately.
My idea is to pass Meteor.call('sendEmailContact' and on success only, to pass Meteor.call('openMessage'
Below my current event & my unsuccess try
current event
Template.Users.events({
'click .open-message':function() {
Meteor.call('openMessage', this._id, function(error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {console.log ("ok");}
});
var to = this.email; // catch the to value
var contactmessage = this.message; // catch the original message
swal({
input: 'textarea',
title: "Response to " + to,
text: "H " + contactmessage,
type: "",
showCloseButton: true,
showCancelButton: true,
confirmButtonColor: "#272b35",
confirmButtonText: "Send"
}).then(function (text){
if(message != '') {
var from = "my#mail.com"
var subject = "Response to your message";
var message = text; //catch the value of the textarea
Meteor.call('sendEmailContact', to, from, subject, message, contactmessage, (error) => {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
} else {
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
//target.text.value = ''; // Clear form
Bert.alert({
title: 'Success',
message: 'Message sended.',
type: 'success'
});
}
});
} else {
Bert.alert({
title: 'Error',
message: 'Message error.',
type: 'danger'
});
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
}
}, function (dismiss) {
if (dismiss === 'cancel') {
null
//handle dismiss events like 'cancel', 'overlay', 'close', and 'timer'
}
})
}
});
unsuccess try (no error, the first method ok, but nothing on the second (console.log ("ok"); works))
Template.Users.events({
'click .open-message':function() {
var to = this.email; // catch the to value
var contactmessage = this.message; // catch the original message
swal({
input: 'textarea',
title: "Response to " + to,
text: "H " + contactmessage,
type: "",
showCloseButton: true,
showCancelButton: true,
confirmButtonColor: "#272b35",
confirmButtonText: "Send"
}).then(function (text){
if(message != '') {
var from = "my#mail.com"
var subject = "Response to your message";
var message = text; //catch the value of the textarea
Meteor.call('sendEmailContact', to, from, subject, message, contactmessage, (error) => {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
} else {
Meteor.call('openMessage', this._id, function(error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {console.log ("ok");}
});
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
//target.text.value = ''; // Clear form
Bert.alert({
title: 'Success',
message: 'Message sended.',
type: 'success'
});
}
});
} else {
Bert.alert({
title: 'Error',
message: 'Message error.',
type: 'danger'
});
console.log (to);
console.log (from);
console.log (subject);
console.log (message);
}
}, function (dismiss) {
if (dismiss === 'cancel') {
null
//handle dismiss events like 'cancel', 'overlay', 'close', and 'timer'
}
})
}
});
EDIT
Below the two methods :
//Contact Method
Meteor.methods({
insertMessage: function(message) {
ContactMessages.insert(message);
},
openMessage: function(messageId) {
ContactMessages.update({_id: messageId}, {$set: {new: false, responded: true}});
},
deleteMessage: function(messageId) {
ContactMessages.remove({_id: messageId});
}
});
//Send ContactReply Method
Meteor.methods({
sendEmailContact: function(to, from, subject, message, contactmessage) {
check([to, from, subject, message, contactmessage], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: message + contactmessage
});
}
});
You'll need to pass the messageId as an extra parameter to sendEmailContact from the client but then it should be pretty simple:
Meteor.methods({
insertMessage(message) {
ContactMessages.insert(message);
},
openMessage(messageId) {
ContactMessages.update(messageId, {$set: {new: false, responded: true}});
},
deleteMessage(messageId) {
ContactMessages.remove(messageId);
}
});
//Send ContactReply Method
Meteor.methods({
sendEmailContact(messageId,to, from, subject, message, contactmessage) {
check([messageId, to, from, subject, message, contactmessage], [String]);
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: message + contactmessage
});
Meteor.call('openMessage',messageId);
}
});
You don't even need a callback from the embedded Meteor.call() unless you want to log a potential error there.
in your 2nd example:
Meteor.call('openMessage', this._id, function(error) {
i think it doesn't know what "this" is.
so save it off at the top of the function and use the saved value through closure.
i'm also wondering why it's important that the client be the one to invoke both methods. it's technically possible to handle all that on the server; is that something that makes sense in your app?

Meteor.loginWithPassword() gives undefined

I'm currently working on a project to make a Pinterest clone in Meteor. The users need to fill in three test when they create an account, so I need to make a custom registration/login system. For now, I can create a new account, but when I want to log in with Meteor.loginWithPassword() nothing happens. Even no error or result.
Here's my code:
'submit .login-form': function(event){
event.preventDefault();
var emailVar = event.target.loginEmail.value;
var passwordVar = event.target.loginPassword.value;
console.log('here') // This is shown in the console
console.log(Meteor.loginWithPassword()) // gives undefined
Meteor.loginWithPassword(emailVar, passwordVar, function(err, suc) {
if (err) {
console.log(err); // This isn't shown in the console
} else {
console.log(succ); // This isn't shown in the console
Bert.alert({
title: "Welkom: " + Meteor.user().profile.name,
message: 'You're logged in!',
type: 'success',
style: 'growl-top-right',
icon: 'fa-check'
});
}
});
}
Edit:
As asked here's is the user in Meteor.users:
Image
And here are the strings that are filled in: Image
this should work:
'submit .login-form': function (event) {
event.preventDefault();
var emailVar = event.target.loginEmail.value;
var passwordVar = event.target.loginPassword.value;
Meteor.loginWithPassword(emailVar, passwordVar, function (err) {
if (!err) {
console.log("User logged in");
Bert.alert({
title: "Welkom: " + Meteor.user().profile.name,
message: "You're logged in !",
type: 'success',
style: 'growl-top-right',
icon: 'fa-check'
});
} else{
// Do something on error....
console.log("Not logged in, and error occurred:", err); // Outputs error
}
});
}

sendEmail after form submitted

I've been trying to send an email after a autoform has been successfully submitted. I've tried using the template.events 'submit' which didn't work and I've tried to use metermethod="sendEmail". Nothing I do seems to work. Can someone please tell me what I'm doing wrong.
Path: form.html
{{#autoForm collection="JobOffers" id="jobOfferForm" type="insert" meteormethod="sendEmail"}}
<fieldset>
{{> afQuickField name='firstName'}}
<button type="submit" data-meteor-method="sendEmail" class="btn btn-primary">Submit</button>
</fieldset>
{{/autoForm}}
Path: server/email.js
sendEmail: function (from, subject, userId) {
check([from, subject, userId], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
SSR.compileTemplate( 'htmlEmail', Assets.getText( 'html-email.html' ) );
// to find the users info for the logged in users
// var user = Meteor.user();
var user = Meteor.users.findOne({ _id: userId });
var email = (user && user.emails[0].address);
var emailData = {
// name: (candidate && candidate.profile && candidate.profile.firstName),
name: (user && user.profile && user.profile.firstName),
// favoriteRestaurant: "Honker Burger",
// bestFriend: "Skeeter Valentine"
};
Email.send({
to: email,
from: from,
subject: subject,
html: SSR.render( 'htmlEmail', emailData )
});
console.log('sendEmail sent');
}
});
UPDATE
Path: form.js
AutoForm.hooks({
jobOfferForm: hooksObject
});
var hooksObject = {
after: {
insert: function(error, result){
Email.send({
var otheruserId = FlowRouter.getParam('id');
Meteor.call('sendEmail',
'test#email.com',
'Hello from Meteor!',
otheruserId);
};
}
}
};
You can use callbacks/hooks of autoform. If you want to send email after an insert following would be a solution:
var hooksObject ={
after: {
insert: function(error, result){
//Send email here
}
}
}
UPDATE:
var hooksObject = {
after: {
insert: function(error, result){
var otheruserId = FlowRouter.getParam('id');
Meteor.call('sendEmail',
'test#email.com',
'Hello from Meteor!',
otheruserId);
}
}
};
AutoForm.addHooks('jobOfferForm', hooksObject);
Please refer to autoform documentation for more info.

Meteor: How can I restrict user on a chat?

Im working on a project and my last task is to implement publish and subscribe to prevent users seeing conversations they were not involved in. We were given an example code and I notice a filter on the router.
Router.route('/chat/:_id', function () {
// the user they want to chat to has id equal to
// the id sent in after /chat/...
var otherUserId = this.params._id;
// find a chat that has two users that match current user id
// and the requested user id
var filter = {$or:[
{user1Id:Meteor.userId(), user2Id:otherUserId},
{user2Id:Meteor.userId(), user1Id:otherUserId}
]};
var chat = Chats.findOne(filter);
if (!chat){// no chat matching the filter - need to insert a new one
chatId = Chats.insert({user1Id:Meteor.userId(), user2Id:otherUserId});
}
else {// there is a chat going already - use that.
chatId = chat._id;
}
if (chatId){// looking good, save the id to the session
Session.set("chatId",chatId);
}
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
I thought the filter should be on publish and then subscribe. Here is what I have now.
My HTML
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each recentMessages}}
{{> message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
{{#if currentUser}}
<form class="new-message">
<input class="input" type="text" name="text" placeholder="type a message here...">
<button class="btn btn-default">Send</button>
</form>
{{/if}}
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="message">
<div class = "container">
<div class = "row">
<div class = "username">
<img src="/{{avatar}}" class="avatar_img" >
{{username}}
said: {{messageText}}
</div>
</div>
</div>
</template>
Server Side
Meteor.startup(function () {
if (!Meteor.users.findOne()){
for (var i=1;i<9;i++){
var email = "user"+i+"#test.com";
var username = "user"+i;
var avatar = "ava"+i+".png"
console.log("creating a user with password 'test123' and username/ email: "
+ email);
Meteor.users.insert({
profile:{username:username, avatar:avatar},
emails: [{address:email}],
services:{
password:{"bcrypt" : "PASSWORD REMOVED"}}});
}
}
});
Meteor.publish("messages", function (userId) {
return Messages.find();
});
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
Meteor.publish("userData", function(){
if(this.userId) {
return Meteor.users.find({_id: this.userId},{
fields: {'other':1, 'things': 1}});
} else {
this.ready();
}
return Meteor.users.find({ "status.online": true })
});
Client Side
Meteor.subscribe("messages");
Meteor.subscribe("userStatus");
Meteor.subscribe("userData");
// set up the main template the the router will use to build pages
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// specify the top level route, the page users see when they arrive at the site
Router.route('/', function () {
console.log("rendering root /");
this.render("navbar", {to:"header"});
this.render("lobby_page", {to:"main"});
});
Router.route('/chat/:_id', function () {
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
///
// helper functions
///
Template.message.helpers({
userName: function() {
var userId = this.userId;
var user = Meteor.users.findOne(userId);
var username = user && user.profile && user.profile.username;
var avatar = user && user.profile && user.profile.avatar;
return {
username: username,
avatar: avatar
}
}
})
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.profile.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
recentMessages: function () {
if (Session.get("hideCompleted")) {
return Messages.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
} else {
return Messages.find({}, {sort: {createdAt: 1}});
}
},
hideCompleted: function () {
return Session.get("hideCompleted");
},
incompleteCount: function () {
return Tasks.find({checked: {$ne: true}}).count();
}
});
Template.chat_page.events({
// this event fires when the user sends a message on the chat page
'submit .new-message':function(event){
console.log(event);
event.preventDefault();
var text = event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
// see if we can find a chat object in the database
// to which we'll add the message
Meteor.call("sendMessage", text);
},
});
Collections
Messages = new Mongo.Collection("messages");
Shared-Methods
Meteor.methods({
sendMessage: function (messageText) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Messages.insert({
messageText: messageText,
createdAt: new Date(),
username: Meteor.user().profile.username,
avatar: Meteor.user().profile.avatar,
});
}
});

Meteor method not returning ID to client

I am in the process of integrating stripe payments on my website, but I have run into a problem.
I want to transition the user to a dynamic route upon submitting the payments form (iframe supplied by stripe), but the Meteor method that I call on the client returns undefined instead of the ID of the newly inserted document that I wish to transition to
Any advice?
ERROR
Error: Missing required parameters on path "/purchases/:purchaseId". The missing params are: ["purchaseId"]. The params object passed in was: undefined.
client:
Template.viewTab.events({
'click #download': function(event) {
handler.open({
name: 'Tabr',
description: this.title,
amount: this.price
});
event.preventDefault();
},
});
var handler = StripeCheckout.configure({
key: '..............',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
tabId = Tabs.findOne()._id;
Meteor.call('makePurchase', tabId, token, function(error, purchaseId) {
if (error) {
console.log('makePurchaseError: ' + error);
FlashMessages.clear();
return FlashMessages.sendError(error.message, {
autoHide: true,
hideDelay: 10000
});
}
console.log(purchaseId);
Router.go('viewPurchase', purchaseId);
});
}
});
Server:
Meteor.methods({
/**
* [makePurchase attempts to charge the customer's credit card, and if succesful
* it inserts a new purchaes document in the database]
*
* #return {[String]} [purchaseId]
*/
makePurchase: function(tabId, token) {
check(tabId, String);
tab = Tabs.findOne(tabId);
Stripe.charges.create({
amount: tab.price,
currency: "USD",
card: token.id
}, Meteor.bindEnvironment(function (error, result) {
if (error) {
console.log('makePurchaseError: ' + error);
return error;
}
purchaseId = Purchases.insert({
sellerId: tab.userId,
tabId: tab._id,
price: tab.price
}, function(error, result) {
if (error) {
console.log('InsertionError: ' + error);
return error;
}
return result;
});
}));
console.log(purchaseId);
return purchaseId;
}
});

Resources