Connecting peers doesn't work as expected - PeerJS - meteor

I am building audio calling application using PeerJS. In the call receiver, I have the following code inside peer.on('call', function(call) { ... }:
var conn = peer.connect(call.peer);
var receiveCall = bootbox.dialog({
className: "modal-danger nonumpad",
closeButton: false,
animate: true,
title: 'Call Recieved',
message: "Accept or Decline",
onEscape: null,
buttons: {
pickup: {
label: "<i class=\"fa fa-phone\"></i> Answer",
className: "btn-warning btn-lg pull-left",
callback: function(){
conn.send('ACCEPT') // send ACCEPT to the other client
window.currentCall = call;
call.answer(stream); // Answer the call with an A/V stream.
call.on('stream', function(remoteStream) {
var audio = $('<audio autoplay />').appendTo('body');
audio[0].src = (URL || webkitURL || mozURL).createObjectURL(stream);
});
return false;
}
},
hangup: {
label: "<i class=\"fa fa-phone\"></i> Decline",
className: "btn-warning btn-lg pull-left",
callback: function(){
conn.send('DECLINED') // send DECLINED to the other client
window.currentCall.close()
stream.getTracks().forEach(track => track.stop());
return false;
}
}
}
});
I can see the data is successfully received to the other client (the client who made the call). I am using the following code to receive the data:
callDialog.init(function(){
peer.on('connection', function(conn) {
conn.on('data', function(data){
console.log(call);
if(data == "ACCEPT"){
$("#test").text("This is dynamic msg");
$("#hangup").text("Hangup");
} else if (data == "DECLINED"){
stream.getTracks().forEach(track => track.stop());
}
});
});
});
The problem is here that I am using the same code in the client who is making the call to send data to the call receiver but it doesn't work and no error is showing in the console.
This is the code in the call initializer client:
var conn = peer.connect(destinationPeerId);
var callDialog = bootbox.dialog({
title: 'Making Call',
message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i><span id="test"> Waiting for Reply... </span></div>',
onEscape: null,
buttons: {
hangup: {
label: "<span id='hangup' <i class=\"fa fa-phone\"></i> Cancel </span>",
className: "btn-warning btn-lg pull-left",
callback: function(){
conn.send('DECLINED'); // sent to the call receiver
stream.getTracks().forEach(track => track.stop());
return false;
}
}
}
});
Why the same code sends data from the call receiver to the initializer, but not the other way around?
And how should I go with it to be able to send data the other way around?

Related

How to use web push notifications with Meteor?

I am just hoping to find some good examples, but I haven't found anything. Pushjs is working on localhost, but how do I use the service worker correctly? I have linked the file, but this:
self.addEventListener('push', function (event) {
console.log('Received a push message', event);
// var notificationOptions = {
// body: 'The highlights of Google I/O 2015',
// icon: 'images/icon#192.png',
// tag: 'highlights-google-io-2015',
// data: null
// };
var notificationOptions = {
body: "Martin matches 89% with you!",
icon: '/images/LogoStore.jpg',
timeout: 4000,
link: "/",
onClick: function () {
window.focus();
this.close();
}
}
if (self.registration.showNotification) {
self.registration.showNotification('Timely News', notificationOptions);
return;
} else {
new Notification('Timely News', notificationOptions);
}
});
does not work.

Vue-Full-Calendar refetch-events error

I am having issues refreshing events when I add a new one. The event gets inserted into the database fine, but the call to
this.$refs.calendar.$emit('refetch-events')
Throws the following error:
[Vue warn]: Error in event handler for "refetch-events": "TypeError: $(...).fullCalendar is not a function"
Here is some more of the code to further demonstrate what I am trying to do:
<template>
<div>
<full-calendar ref="calendar" :event-sources="eventSources" #day-click="daySelected" #event-selected="eventSelected" :config="config"></full-calendar>
<!-- Modal Component -->
<b-modal ref="my_modal" title="New Appointment" #ok="submit" #shown="clearModalValues">
<form #submit.stop.prevent="submit">
<label>Client:</label>
<b-form-select v-model="selectedClient" :options="clientOptions" class='mb-3'></b-form-select>
<label>Service:</label>
<b-form-select multiple v-model="selectedService" :options="serviceOptions" class='mb-3'></b-form-select>
<label>Start time:</label>
<time-picker v-model="myTime"></time-picker>
<label>Notes:</label>
<b-form-input textarea v-model="notes" placeholder="Notes"></b-form-input>
</form>
</b-modal>
<!-- /Modal Component -->
</div>
</template>
<script>
export default {
props: {
staff:{
type: Number,
required: true
},
},
data() {
return {
myTime: new Date(),
selectedService: [null],
selectedClient: null,
selectedStartTime: new Date(),
notes: null,
serviceOptions: [],
clientOptions: [],
events: [],
config: {
timeFormat: 'h(:mm)',
eventClick: (event) => {
console.log('Event Clicked: '+event.title);
},
},
selected: {},
};
},
computed: {
eventSources() {
return [
{
events(start, end, timezone, callback) {
axios.get('/getEvents').then(response => {
callback(response.data)
})
}
}
]
}
},
mounted() {
this.myTime = new Date()
axios.get('/getClients').then(response => this.clientOptions = response.data);
axios.get('/getServices').then(response => this.serviceOptions = response.data);
},
methods: {
clearModalValues() {
this.selectedService = [null];
this.selectedClient = null;
this.selectedStartTime = new Date();
this.myTime = new Date();
this.notes = null;
},
submit(e) {
axios.post('/addEvent/',{'selectedService':this.selectedService,'selectedClient':this.selectedClient,'selectedStartTime':this.selectedStartTime,'notes':this.notes}).then(function(response){
//console.log(response.data);
new PNotify({
title: 'Success',
text: 'New event has been created',
icon: 'icon-checkmark3',
type: 'success'
});
this.selectedService = [null];
this.selectedClient = null;
this.selectedStartTime = new Date();
this.notes = null;
this.myTime = new Date();
// ******** I HAVE TRIED THESE CALLS AS PER DOCUMENTATION **********
//this.$refs.calendar.fireMethod('refetch-events')
//this.$refs.calendar.fullCalendar.$emit('refetch-events');
//this.$refs.calendar.$emit('refetch-events');
console.log(this.$refs.calendar);
}.bind(this));
},
eventSelected(event) {
console.log('Event Selected: '+event.title);
},
daySelected(date,event,view){
this.$refs.my_modal.show();
this.selectedStartTime = date.format("YYYY-MM-DD HH:mm:ss");
this.myTime = date.toDate();
},
},
};
</script>
According to the documentation it should be correct. I know its late and I have been at this for a couple hours so I might be overlooking something simple. Again this is vue-full-calendar and not regular full-calendar. I just need to call refetchEvents when I add the new events in the submit method. Thanks!
I have found the issue, thanks to Brock for the help. I had multiple versions of jquery running(the html template I was using was also calling it).

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?

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

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'
});
}
}

Working example of recaptcha in meteor

Can anyone help with a working example of recaptcha in meteor without using iframes?
I cannot make the recaptcha scripts run even when I try to run them from the client.js using jquery append.
After doing some investigations I found that I had to manually integrate the reCaptcha.
The client side code:
HTML:
<form id="mySecuredForm" novalidate>
<!-- labels and inputs here -->
<div class="row">
<div id="captcha-container">
<div id="rendered-captcha-container">loading...</div>
</div>
</div>
<div class="row">
<button type="submit" id="submit" class="submit-button">Submit</button>
</div>
</form>
JS
if (Meteor.isClient) {
Template.myTemplate.rendered = function() {
$.getScript('http://www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() {
Recaptcha.create('add_your_public_key_here', 'rendered-captcha-container', {
theme: 'red',
callback: Recaptcha.focus_response_field
});
});
}
Template['myTemplate'].events({
'submit form#mySecuredForm': function(event) {
event.preventDefault();
event.stopPropagation();
var formData = {
captcha_challenge_id: Recaptcha.get_challenge(),
captcha_solution: Recaptcha.get_response()
//add the data from form inputs here
};
Meteor.call('submitMySecuredForm', formData, function(error, result) {
if (result.success) {
//set session vars, redirect, etc
} else {
Recaptcha.reload();
// alert error message according to received code
switch (result.error) {
case 'captcha_verification_failed':
alert('captcha solution is wrong!');
break;
case 'other_error_on_form_submit':
alert('other error');
break;
default:
alert('error');
}
}
});
}
Server side code
function verifyCaptcha(clientIP, data) {
var captcha_data = {
privatekey: 'add_private_key_here',
remoteip: clientIP
challenge: data.captcha_challenge_id,
response: data.captcha_solution
};
var serialized_captcha_data =
'privatekey=' + captcha_data.privatekey +
'&remoteip=' + captcha_data.remoteip +
'&challenge=' + captcha_data.challenge +
'&response=' + captcha_data.response;
var captchaVerificationResult = null;
var success, parts; // used to process response string
try {
captchaVerificationResult = HTTP.call("POST", "http://www.google.com/recaptcha/api/verify", {
content: serialized_captcha_data.toString('utf8'),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': serialized_captcha_data.length
}
});
} catch(e) {
return {
'success': false,
'error': 'google_service_not_accessible'
};
}
parts = captchaVerificationResult.content.split('\n');
success = parts[0];
if (success !== 'true') {
return {
'success': false,
'error': 'captcha_verification_failed'
};
}
return {
'success': true
};
}
Meteor.methods({
"submitMySecuredForm": function(data) {
//!add code here to separate captcha data from form data.
var verifyCaptchaResponse = verifyCaptcha(this.connection.clientAddress, data);
if (!verifyCaptchaResponse.success) {
console.log('Captcha check failed! Responding with: ', verifyCaptchaResponse);
return verifyCaptchaResponse;
}
console.log('Captcha verification passed!');
//!add code here to process form data
return {success: true};
});
There is also the possibility to listen to the post event on the server side. The http calls can be done synchronous as above or asynchronous with fibers/futures.
Server side http call to google API was inspired from:
https://github.com/mirhampt/node-recaptcha/blob/master/lib/recaptcha.js

Resources