Meteor - UserIsInRole always returning false - meteor

I Have added allaning:roles in my meteor-react project but
Roles.userIsInRole(Meteor.userId(), ["ADMIN"]) always returning false.
I have roles in my mongo as follows,
{ "_id" : "9B3D757wQA9Mz4RGt", "name" : "BUYER" }
{ "_id" : "PDCJH8D6JDo9fttFj", "name" : "ADMINKAMB" }
{ "_id" : "XFGsrfB3Xsm6F8LbQ", "name" : "SELLER" }
{ "_id" : "hDLSvdo6wMnF47BBz", "name" : "ADMIN" }
{ "_id" : "ADMINKAMB", "children" : [ ] }

if you remove the autopublish from yours packages, try to add this code
For my case, I create a file /imports/startup/server/publications/index.js
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.roleAssignment.find({ 'user._id': this.userId });
}
return this.ready();
});
Then in server/main.js
import '/imports/startup/server/publications'

Related

firebase realtime database to update an entry after filter using angularfire 2

The data in the realtime db is structure like below:
"orders" : {
"-LM5p4tl7Og_PMJOspZ-" : {
"customer" : {
"_name" : "Vik Kumar",
"_uid" : "oSEYj0zrkhPCk9r7uwyOOkHcqe53"
},
"order" : {
"_orderNumber" : "VikKumar-26954",
"_orderStatus" : "Pending",
"_orderTotal" : 500,
}
},
"-LM5s1wRCvqWA1vsZONy" : {
"customer" : {
"_name" : "Vik Kumar",
"_uid" : "oSEYj0zrkhPCk9r7uwyOOkHcqe53"
},
"order" : {
"_orderNumber" : "VikKumar-11423",
"_orderStatus" : "Pending",
"_orderTotal" : 500,
}
},
"-LM5sOHzjLeqFGFleMxq" : {
"customer" : {
"_name" : "Vik Kumar",
"_uid" : "oSEYj0zrkhPCk9r7uwyOOkHcqe53"
},
"order" : {
"_orderNumber" : "VikKumar-63772",
"_orderStatus" : "Pending",
"_orderTotal" : 500,
}
}
}
I am using angularfire2 in my ionic app and filtering few orders as below:
getPendingOrders(dateStr:string){
return new Promise((resolve, reject) =>
{
this.db.list('orders',
ref => ref.orderByChild("order/_date").equalTo(dateStr)
).valueChanges().subscribe(
res => {
resolve(res)
},
err => {
console.log(err)
reject(err)
}
)
})
}
The above query gives me the response as below
[{"customer": {}, "order": {}}, {"customer": {}, "order": {}}]
I can render it in UI just fine and i want the end user to be able to update the value of property "_orderStatus". The trouble is the way i queried the data i have lost the keys to identify a particular object to update it. Please advise
ok, not sure if this helps,I think you have migrated to use AngularFire 5.0. Calling .valueChanges() will return an Observable without any metadata (item key for example), you need to use .snapshotChanges() call instead:
this.db.list(...)
.snapshotChanges()
.map(changes => {
return changes.map(change => ({key: change.payload.key, ...change.payload.val()}));
})
.subscribe(...)

How to do filter by keyword in Firebase?

I have a Firebase database structure like this
{
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : {
"Company" : {
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : {
"authTime" : 1532061957,
"companyName" : "Scopic Software",
"contactName" : "Hoang Scopic",
"email" : "hoang.trinh#scopicsoftware.com",
"firebaseID" : "5ZhJG1NACDdG9WoNZWrBoYGkIpD3",
"isFirstLogin" : false,
"phoneNumber" : "1234567890",
"schoolName" : "MIT",
"teachers" : {
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : "0"
}
}
}
},
"AhZc9B02goOtZ6qBNhz9W0K6Esg2" : {
"Subscription" : {
"-LHlQ4OhijzzFY5HZOT4" : {
"firebaseID" : "-LHlQ4OhijzzFY5HZOT4",
"period" : {
"endAt" : "1533194625",
"startAt" : "1531985025"
},
"status" : "trial"
}
},
"Teacher" : {
"AhZc9B02goOtZ6qBNhz9W0K6Esg2" : {
"authTime" : 1532061932,
"email" : "hoang.trinhj#gmail.com",
"firebaseID" : "AhZc9B02goOtZ6qBNhz9W0K6Esg2",
"isFirstLogin" : false,
"name" : "Hoang Trinh",
"schoolName" : "HUST",
"subscriptions" : {
"-LHlQ4OhijzzFY5HZOT4" : "0"
}
}
}
},
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : {
"Subscription" : {
"-LHlWnpNZazBC5lpXLi0" : {
"firebaseID" : "-LHlWnpNZazBC5lpXLi0",
"period" : {
"endAt" : "1533196388",
"startAt" : "1531986788"
},
"status" : "trial"
}
},
"Teacher" : {
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : {
"Company" : {
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : "0"
},
"authTime" : 1532060884,
"email" : "piavghoang#gmail.com",
"firebaseID" : "aOpjnzHpDiZ7uwQQqJoinGvM9ZD3",
"isFirstLogin" : false,
"subscriptions" : {
"-LHlWnpNZazBC5lpXLi0" : "0"
}
}
}
},
"ooR32SjABdOYEkWX6dzy4fE5Kym1" : {
"Admin" : {
"email" : "admin#test.com",
"firstName" : "Hoang",
"lastName" : "Trinh",
"password" : "123456xx"
},
"isAdmin" : true
}
}
This is data in an existing system, so I can't change its structure.
Now I need to write an API to list these records filtered by "email" attribute there (it's nested inside a key).
How can I do a search for this email?
There is one solution that I thought about. It's just getting the whole json back and process data in code (not using Firebase database query functions).
But I can't do that, because AFTER filtering, I need to do paging also.
In order to make the pagination, I need to use query functions like "sortByChild" or "limitToLast", so I have to use these query functions with filtering.
Thank you.
EDIT:
My current implementation for pagination:
getUsers: async (page, perPage, searchTerm) => {
const db = fbAdmin.db();
let dbRef = await db.ref();
if (searchTerm) {
// TODO: Add filter logic here
}
let totalItems = await dbRef.once('value');
let totalItemsNumber = await Object.keys(totalItems.toJSON()).length;
// Calculate for pagination
let lastItemId;
if ((page - 1) * perPage + 1 > totalItemsNumber) {
lastItemId = null;
} else {
let lastItems = await dbRef.orderByKey().limitToLast((page - 1) * perPage + 1).once('value');
lastItemId = Object.keys(lastItems.toJSON())[0];
}
// Do the pagination
let snap;
let data;
if (lastItemId) {
snap = await dbRef.orderByKey().endAt(lastItemId).limitToLast(perPage).once('value');
data = snap.toJSON();
} else {
data = {};
}
let users = Object.keys(data).map(key => {
if (data[key][KEY]) { // Check if it's an admin
return {
role: TYPE_ADMIN,
email: data[key][KEY].email,
name: data[key][KEY].firstName + " " + data[key][KEY].lastName
}
} else if (data[key][Company.KEY]) { // Check if it's a company member
return {
role: TYPE_COMPANY_MEMBER,
email: data[key][Company.KEY][key].email,
name: data[key][Company.KEY][key].name,
schoolName: data[key][Company.KEY][key].schoolName
}
} else if (data[key][Teacher.KEY]) { // Check if it's a teacher
if (data[key][Teacher.KEY][key][Company.KEY]) { // Check if it's a company teacher
return {
role: TYPE_COMPANY_TEACHER,
email: data[key][Teacher.KEY][key].email,
name: data[key][Teacher.KEY][key].name,
schoolName: data[key][Teacher.KEY][key].schoolName,
subscription: data[key][Subscription.KEY]
}
} else { // Check if it's an individual teacher
return {
role: TYPE_INDIVIDUAL_TEACHER,
email: data[key][Teacher.KEY][key].email,
name: data[key][Teacher.KEY][key].name,
schoolName: data[key][Teacher.KEY][key].schoolName,
subscription: data[key][Subscription.KEY]
}
}
} else {
return null;
}
});
return users || null;
},

how to make Meteor.user field reactive

I am trying to block user who open more than one browser being logged In.
I have a Meteor.user() object populated as follows when a user signs up:
{
"_id" : "uSS2RqZnnFwui67wk",
"createdAt" : ISODate("2017-05-15T07:28:10.546Z"),
"services" : {
"password" : {
"bcrypt" : "$2a$10$DPgA59Gmob4ajzjYZyh5auoHRUyQuF1/7M0KaWz.nzW0mIEqzlDK6"
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2017-05-15T13:42:29.322Z"),
"hashedToken" : "tkoQnweSQhgRKGzaJTAkUU3/Ljd3p4wrBJfrRvRRlcY="
}
]
}
},
"username" : "johndoe",
"emails" : [
{
"address" : "lkj#gmail.com",
"verified" : false
}
],
"profile" : {
"name" : "John Doe",
"mobile" : "9637637941",
"email" : "lkj#gmail.com",
"address" : "kfasd, asdas,d as dsad",
"gender" : "M",
"state" : "Uttar Pradesh",
"customerType" : "CLIENT",
"isBlocked" : true
},
"status" : {
"online" : true,
"lastLogin" : {
"date" : ISODate("2017-05-15T14:12:02.094Z"),
"ipAddr" : "127.0.0.1",
"userAgent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0"
},
"idle" : false
}
}
Referring to the above code, I am trying to update a UI based on the user.profile.isBlocked* status.
My UI.html is as below:
<template name="App_watch">
{{#if isBlocked}}
User Has been Blocked.
{{else}}
User has Access.
{{/if}}
</template>
My UI.js is as below:
import { Meteor } from 'meteor/meteor';
import './UI.html';
Template.App_watch.helpers({
isBlocked() {
user = Meteor.users.find({_id: Meteor.userId});
return user.profile.isBlocked;
}
});
In the code below I am simply monitoring whether there are more than 1 browsers open with same log in. If YES then block the user, else Unblock the user.
import './fixtures.js';
import './register-api.js';
UserStatus.events.on("connectionLogin", function(fields) {
var count = UserStatus.connections.find({userId : fields.userId}).count();
if(count > 1) { //Block
Meteor.users.update({_id: Meteor.userId()}, {$set: {"profile.isBlocked": true}});
} else { // Unblock
Meteor.users.update({_id: Meteor.userId()}, {$set: {"profile.isBlocked": false}});
}
});
Problem Statement:
I want to make the isBlocked variable reactive as an when the isBlocked flag changes for the user. Currently it is static and needs refresh.
Try:
Template.App_watch.helpers({
isBlocked() {
return Meteor.user() && Meteor.user().profile && Meteor.user().profile.isBlocked;
}
});
If you're looking for a single object you need to use .findOne() instead of .find() as the latter returns a cursor. It's also Meteor.userId() not Meteor.userId

How to orderByChild in nested Child in angularfire?

My firebase database structure is as below. I would like to search with a particular "Info/Email", let's say "abc#abc.com".
{
"-KhWrBcYyMluJbK7QpnK" : {
"Info" : {
"Email" : "xyz#gmail.com"
},
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX0tgQvDtDYqt4XRoL" : {
"Info" : {
"Email" : "abc#abc.com"
},
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX1eo7uFnOxqncDXQ5" : {
"Info" : {
"Email" : "abc#abc.com"
},
"Settings" : {
"Status" : "Pending"
}
}
}
I added a rule too
"Invitation" : {
".indexOn": ["Info/Email","Settings/Status"]
}
My AngularFire code is as follows:
var rootRef = firebase.database().ref().child('Invitation');
var userInvitations = rootRef.child("Info").orderByChild("Email").equalTo("abc#abc.com");
var allInvitations = $firebaseArray(userInvitations);
But I am getting a FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "Email" at /Invitation/Info to your security rules for better performance. and of course I am not receiving any data.
What are the mistakes I made here? Also can I add multiple orderByChild, for example: if I want to find details of the record, which has "Info/Email" equal to "abc#abc.com" and "Settings/Status" equal to "Pending" ?
The Firebase API only allows you to filter children one level deep
So with reference to your data structure:
if it were to be this way,
{
"-KhWrBcYyMluJbK7QpnK" : {
"Email" : "xyz#gmail.com",
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX0tgQvDtDYqt4XRoL" : {
"Email" : "abc#abc.com",
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX1eo7uFnOxqncDXQ5" : {
"Email" : "abc#abc.com",
"Settings" : {
"Status" : "Pending"
}
}
}
You should write your rules this way instead.
"Invitation" : {
"Info" : {
".indexOn": "Email",
},
"Settings" : {
".indexOn": "Status",
}
}
Then you will be able to query the data
var allInvitations = [];
var rootRef = firebase.database().ref().child('Invitation');
var userInvitations = rootRef.orderByChild("Email").equalTo("abc#abc.com");
userInvitations.on('value', snap => {
var invitations = snap.val()
for (prop in invitations ) {
allInvitations.push(invitations[prop ]);
}
console.log(allInvitations);
})

Meteor.users.find().fetch() returns single user

I am using accounts-google package to register users
I have multiple users stored in mongo
db.users.find()
{ "_id" : "av8Dxwkf5BC59fzQN", "profile" : { "avatar" : "https://lh3.googleusercontent.com/-rREuhQEDLDY/AAAAAAAAAAI/AAAAAAAADNs/x764bovDfQo/photo.jpg", "email" : "lfender6445#gmail.com", "name" : "Luke Fender", "room" : "2" }, "services" : { "resume" : { "loginTokens" : [ { "when" : ISODate("2014-04-26T19:34:52.195Z"), "hashedToken" : "8na48dlKQdTnmPEvvxBrWOm3FQcWFnDE0VnGfL4hlhM=" } ] } } }
{ "_id" : "6YJKb7umMs2ycHCPx", "profile" : { "avatar" : "https://lh3.googleusercontent.com/-rREuhQEDLDY/AAAAAAAAAAI/AAAAAAAADNs/x764bovDfQo/photo.jpg", "email" : "lfender6445#gmail.com", "name" : "Luke Fender", "room" : "2" }, "services" : { "resume" : { "loginTokens" : [ { "when" : ISODate("2014-04-26T19:35:00.185Z"), "hashedToken" : "d/vnEQMRlc4VI8pXcYmBvB+MqQLAFfAKsKksjCXapfM=" } ] } } }
But Meteor.users.find().fetch() returns document for logged in user only - shouldn't this return entire collection? Are the other users somehow private by default?
This is the default behaviour. You can only see who you're logged in as.
You can make a custom publish function to publish a custom subset/what you want. In the example below I publish all the users (only the profile field)
Server side code
Meteor.publish('users', function() {
return Meteor.users.find({}, {fields:{profile: true}});
});
Client side code
Meteor.subscribe("users");
You might want to alter these to only publish what is relevant to the user. If you have over 100 users this begins to get wasteful to publish all of them to the client.

Resources