I'm trying to publish all the users who have an active account between two date ranges. My code doesn't seem to be working, any thoughts?
Meteor.publish('classAuction', function (group) {
if (Roles.userIsInRole(this.userId, ['is_teacher'], group)) {
var users = Meteor.users.find({roles:'is_student', "accountStatus.isUserAccountActive": true}); // Get active candidates
var today = new Date().toDateString();
var startDate = Date(accountStatus.startDate).toDateString();
if (today >= startDate) {
return Meteor.users.find({});
} else {
// user not authorized. do not publish secrets
this.stop();
return;
}
}
});
You can use a mongo query for this, something like:
var today = new Date();
return Meteor.users.find({
"accountStatus.startDate": { $gte: today},
roles:'is_student',
"accountStatus.isUserAccountActive": true
});
Related
i've to edit a web application already existing that i don't know at all.
into a web page this code create an unique number:
Fingerprint2.get(function (components) {
try {
var values = components.map(function (component) { return component.value });
var murmur = Fingerprint2.x64hash128(values.join(''), 31);
$("#id-fingerprint").val(murmur);
} catch (err) {
}
});
our customers are working on cloned pc, same hardware and software, so it happens two different users generate the same unique number.
my purpose is to add username to existing code.
is this a good way to do it?
Fingerprint2.get(function (components) {
try {
var values = components.map(function (component) { return component.value });
var username = $("#username").val();
values.push(username);
var murmur = Fingerprint2.x64hash128(values.join(''), 31);
$("#id-fingerprint").val(murmur);
} catch (err) {
}
});
You can add a custom component, you can learn more in the Extending FingerprintJS guidelines. Simply put, you just need to add your id into the components object.
const result = await fp.get()
const components = {
...result.components,
foo: username
}
const visitorId = FingerprintJS.hashComponents(components)
I try to use reactive vars to filter the published data, on a data list page, users can pickup 2 dates to show the data created during the dates; all works great until i got few computers to access this page at same time; the data changes would not push to every computers automatically- only the computer which makes the change has the new data listed. other computers have to refresh the page manually to see the new data or updated data.
if i remove the reactive vars in the sub/pub, all are good - if one computer changes the data, all computers get the new data immediately and automatically.
i even put the date filter to the helper - still same - no DDP push, same as in the sub/pub.
any ideas? any input are very appreciated.v
sub
Template.TestRV.onCreated(function () {
this.startDate = new ReactiveVar({});
this.endDate =new ReactiveVar({});
var sDate = new Date(new Date().setDate(new Date().getDate() - 30));
var eDate = new Date();
//show last 30 days data by default
this.startDate.set(sDate);
this.endDate.set(eDate);
this.autorun(() => {
this.subscribe('shipAllRV',this.startDate.get(),this.endDate.get());
});
//this.autorun(() => {
//this.subscribe('shipAll');
//});
});
Template.TestRV.helpers({
testListRV: function () {
let start = Template.instance().startDate.get();
let end = Template.instance().endDate.get();
return SHIP.find(
{createdAt: { $lte: end, $gte: start }},
{ sort: { createdAt: -1 } }
);
},
testList: function(){
return SHIP.find({},{ sort: { createdAt:-1} });
}
});
pub -SHIP is my collection
Meteor.publish('shipAll', function() {
return SHIP.find({});
});
Meteor.publish('shipAllRV', function(startDate,endDate) {
return SHIP.find({createdAt:{$lte:endDate,$gte:startDate}},{ sort: { createdAt: -1 } });
});
BTW,
1. i tried session variable is same;
2. if i don’t update the createdAt field in my SHIP.update method, it seems all good even the reactive vars in sub/pub
how can i do it correctly? i need the date filter and DDP push. thanks
Robin
I'm working on a presence-like system in firebase with following layout:
firebase {
user1 {
isOnline: true
}
user 2 {
isOnline: true
}
user3 {
isOnline: false
}
}
The isOnline booleans are what I am going to use later to output the names of the users that are online to the console
So for example, in the case above it would say:
user1 is online.
user2 is online.
Here is my code:
var gameRef = new Firebase("https://xxx.firebaseio.com/");
var userOnline = new Firebase('https://xxx/.info/connected');
userOnline.on('value', function (snapshot) {
if (snapshot.val()) {
gameRef.child(user).update({
isOnline : true
});
}
else {
gameRef.child(user).update({
isOnline : false
});
}
});
// for each user that is online, output to the console
gameRef.forEach(function (snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
});
There seems to be a problem with my forEach, how can I fix this?
Thanks.
You cannot forEach over a ref, but only over a snapshot.
// for each user that is online, output to the console
gameRef.on('value', function(function(gamesSnapshot) {
gamesSnapshot.forEach(function (snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
}
});
This code has two snapshot variables:
gameSnapshot is the data in the parent node
snapshot is the data of a specific player
Alternative
The approach above will download all players, even though you are only looking to deal with players that are online. It is more efficient in this case, to query Firebase so that it only returns players that are online.
// for each user that is online, output to the console
var onlinePlayers = gameRef.orderByChild('isOnline').equalTo(true);
onlinePlayers.on('child_added', function(function(snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
});
The code now listens for the child_added event, since Firebase spoon-feeds us the players one at a time. You will probably also have to handle child_changed and child_removed, once you map the players to HTML elements.
Even though this will result in a bit more code, I would normally recommend using querying and the child_* events, since they limit the data that Firebase sends you both initially and when e.g. a player goes offline.
I want to implement a parameter based publication in Meteor but I am running into some problems.
Here is what I have.
As the user types the keyup event that subscribes to publication and passes the value of the input.
'keyup #customerSearch': function(event, template){
var keyword = template.find('#customerSearch').value;
if(keyword){
if(keyword.length >= 3){
Meteor.subscribe('sessioncustomers', keyword);
}
}
}
The publication uses this keyword to return the records.
Meteor.publish("sessioncustomers", function(keyword){
if(keyword ){
if(keyword.length >= 3){
query.name = new RegExp(regExpQuoted(keyword), 'i' );
Customers.find(query);
} else {
return null;
}
}else{
return null;
}
});
The problem.
It works and documents are received except when the client changes the keyword or rather as the keywords changes the publication publishes additional documents that match the keywords but the client collection never removes the old documents.
How do I get the old documents that no longer match out of the client collection?
I thought that because the parameters of the subscription had changed that the non-matching documents would be unsubscribed and only the new matching documents would be subscribed.
In your keyup callback you need to "unsubscribe" to the previous publication,
otherwise you'll keep the old documents.
var sessionCustomersHandler = false;
'keyup #customerSearch': function(event, template) {
var keyword = template.find('#customerSearch').value;
if (keyword && keyword.length >= 3)
var newSessionCustomersHandler = Meteor.subscribe('sessioncustomers', keyword);
if (sessionCustomersHandler)
sessionCustomersHandler.stop();
sessionCustomersHandler = newSessionCustomersHandler;
}
Moreover, don't forget to check(keyword, String) in your publish function, for security.
Meteor.publish("sessioncustomers", function(keyword){
check(keyword, String)
if (keyword.length >= 3)
return Customers.find({
name: new RegExp(regExpQuoted(keyword), 'i' )
});
});
Make a local unnamed client collection
this.SessionCustomers = new Meteor.Collection(null);
Call a server method to get the results you want. Make the callback clear (remove all) and then insert to that local collection.
return Meteor.call('sessioncustomers', query, function(err, data) {
if (err) {
return console.log(err.message);
} else {
SessionCustomers.remove({});
var item, _i, _len;
for (_i = 0, _len = data.length; _i < _len; _i++) {
item = array[_i];
SessionCustomers.insert(item);
}
}
});
So im doing the leaderboard example on the meteor site but instead of the predefined data I start off with, I want to create a new name and score that automatically appears on the screen when someone creates an account, so at this point I get the name and the score on the screen only after I create an account and hit the refresh button on the browser, what do I want to do so that I don't have to hit the refresh button and the user login name and score automatically appears on the screen?
do I want to use deps.flush() or meteor.render somehow?
server.js
// newUser Method
Meteor.methods({
newUser: function() {
var user = Meteor.user();
userVar = {
name: user.username,
score: 0
};
Players.insert(userVar);
}
});
client.js
Deps.autorun(function() {
Meteor.call('newUser');
});
Template.leaderboard.players = function () {
return Players.find({}, {sort: {score: -1, name: 1}});
};
Template.leaderboard.selected_name = function () {
var player = Players.findOne(Session.get("selected_player"));
return player && player.name;
};
Template.player.selected = function () {
return Session.equals("selected_player", this._id) ? "selected" : '';
};
Template.leaderboard.events({
'click input.inc': function () {
Players.update(Session.get("selected_player"), {$inc: {score: 5}});
}
});
Template.player.events({
'click': function () {
Session.set("selected_player", this._id);
}
});
If your starting point is a working version of the example then you should be seeing reactive changes to the web page each time the Players collection changes. Deps.flush or Meteor.render are unnecessary.
The Deps.autorun() function you have is only called once when the client starts. At that point you may not have a user and your method will fail when you try to get a username from the null variable, 'user'.
To trigger the autorun each login and when you have a user you need it to refer to a reactive data source. If you rewrite it like this you should see a new player showing up each time a user logs in:
//on client
Deps.autorun( function(){
if ( Meteor.userId() ){
Meteor.call('newUser');
}
});
I also wonder if your method on the server will have a problem as this.userId is how I usually get the user information inside a method. Here is an alternative to avoid the method and just insert the player on the client:
//on client
Deps.autorun( function(){
var user = Meteor.user();
if ( user ) { //insert will run on login or any change in the user
var userVar = {
name: user.username,
score: 0
};
Players.insert(userVar);
}
});
So I assume then that "player" records belong to a user in some way? So when you create a new user, you create their new default player record?
Maybe you just need your helpers to check that a player record for the user exists, and if not, create it.
Template.leaderboard.players = function () {
var players = Players.find({/* Get players for this user */ }, {sort: {score: -1, name: 1}});
if(!players) {
players = /* Insert default player record */
}
return players;
};