Meteor - New user created after validating login is not recognized - meteor

I have a login validation function setup to check if a new user registered outside of the app. That users info is stored in a temporary collection. If the users info validates I want to be able to use Accounts.createUser on the Client side, but I can't figure out how to do that. The documentation says that "registered validate login callbacks are called with a single argument, the attempt info object", but I can't find any examples of how to do this.
environment.js
Accounts.config({
forbidClientAccountCreation : true
});
server.js
Accounts.validateLoginAttempt(function(info){
if (!info.allowed)
{
var userEmail = info.methodArguments[0].user['email'].toLowerCase();
var userPass = info.methodArguments[0].password['digest'];
// check if this is a temp user
if (tmpUsers.find({'email': userEmail}).count() == 1)
{
var user = tmpUsers.findOne({'email': userEmail})
// check for active
if (user.active == "Yes")
{
// check password
if (userPass == user.password)
{
var accountId = Accounts.createUser({
'password': userPass,
'email': userEmail,
'profile': ({'acctType': user.type})
});
return true;
} else {
throw new Meteor.Error(403, "Incorrect password.");
return false;
}
} else {
throw new Meteor.Error(403, "Your account has yet to be activated.);
return false;
}
} else {
throw new Meteor.Error(403, "Can not find user " + userEmail);
return false;
}
} else {
return true;
}
});
Update:
I ended up putting the Account.userCreate part on the server side and now it does get the user created but when I try to login I get "Email already exists." So it appears as though it doesn't expect the login to be successful and tries to create the user again.
{ // This user works
"_id" : "hCBLo3AJJwmtR6s62",
"createdAt" : ISODate("2014-12-26T20:27:58.44Z"),
"services" : {
"password" : {
"bcrypt" : "$2a$10$pxlEy.JFomgwQwV2cpm72.TBG4.llP98BF9ssTCptC4WsekLzJO9G"
},
"resume" : {
"loginTokens" : []
}
},
"emails" : [{
"address" : "demo#demo.com",
"verified" : false
}]
}
{ // This one does not
"_id" : "w6SGuqJJPs5LoCTTj",
"createdAt" : ISODate("2015-01-10T20:54:16.032Z"),
"services" : {
"password" : {
"bcrypt" : "$2a$10$VJFj0UOrQiLs7djfGWAeMeruDactDFrl1nlEsXh/r5Z/895C5ubAW"
}
},
"emails" : [{
"address" : "demo2#demo.com",
"verified" : false
}],
"profile" : {
"acctType" : null
}
}

Would something like this work for you?
var options = {
username: "username", // you'll need to fill this in
email: userEmail,
password: userPass,
profile: {name: "name"} // you'll need to fill this in
};
Accounts.createUser(options, function (error) {
if (error) {
console.log("Cannot create user");
}
});

Related

How do I access data in GraphQL if not by the id?

I'm using GraphQL with Meteor and Pup v2, and I have a problem accessing the users data via a special ID provided to every user on signup, this ID will be used in a link (mysite.com/user/specialId) so other users can view the searched users account. Problem is, I can't get the data with the special ID, I can't get any data back if I don't pass in the users _id provided by MongoDB. Below I have a bunch of the code used:
Attempt 1
I tried to use a custom on-the-go way just to be able to at least access the data to see if it works (and then implement it correctly later)
const GET_USER_DETAILS = gql`
query user($userId: String) {
user(userId: $userId) {
userId
username
_id
}
}
`;
Here I export so I can get the data:
export default compose(
graphql(GET_USER_DETAILS, {
options: ({ match }) => ({
fetchPolicy: 'no-cache',
variables: {
// existing specialId for testing purposes, to be replaced with match.params.userId
userId: "J4xZzvvhBDSEufnBn",
},
}),
}),
)(PublicProfileView);
This returns a 400 error Network error: Response not successful: Received status code 400 error and after multiple attempts, I could not fix it, so I tried a different approach...
Attempt 2
I tried to go deep into the files and change the GraphQL. Created a new query:
query userById($userId: String) {
userById(userId: $userId) {
...UserAttributes
}
}
(Mentioned fragment)
fragment UserAttributes on User {
_id
name {
...
}
username
emailAddress
oAuthProvider
roles {
...
}
settings {
...
}
userId
}
Tried to add new item in API:
type Query {
...
userById(userId: String): User
...
}
Resolver:
resolvers: {
Query: {
...
userById: (parent, args) => {
// Assuming args equals an object like { _id: '123' };
return UserQueries.userById(args);
},
},
},
query.js, attempt 1:
userById: (parent) => queryUsers.find({ userId: parent.userId }, { sort: { createdAt: 1 } }).fetch()
Attempt 2:
userById: (parent, args, context) => {
return queryUsers({
userId: parent.userId,
});
},
And finally
Attempt 3
I tried to modify the get query
const getQueryModified = (options) => {
// console.log(options.userId)
try {
return options.userId
? { 'userId': options.userId }
: { userId: options.userId };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Here is the original query I tried to modify:
const getQuery = (options) => {
try {
return options.search
? {
_id: { $ne: options.currentUser._id },
$or: [
{ 'profile.name.first': options.search },
{ 'profile.name.last': options.search },
{ 'emails.address': options.search },
// { 'userId': options.search },
{ 'services.facebook.first_name': options.search },
{ 'services.facebook.last_name': options.search },
{ 'services.facebook.email': options.search },
],
}
: { _id: options.currentUser._id };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Unfortunately this was also unsuccessful, the best I get from these when executing the below query is null...
userById(userId: "J4xZzvvhBDSEufnBn"){
username
}
All I want is to get the user data from their userId and not their _id, but I can't seem to figure out how to do it

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;
},

Group users in Firebase RTDB

I am using Firebase in my Qt app for Authentication and Realtime Database features, when users register they need to be assigned into the selected groups then departments of that group. Each group will have admin(s), who can access the entire group database, but the users will only access their department.
Below is my code for my registration form which assigns certain user values, how would i go about grouping the users in the database with additional options on my registration form?
onUserRegistered: {
indicator.stopAnimating()
console.debug("User login " + success + " - " + message)
if(success) {
loginDialog.title = "Success!"
firebaseDb.setUserValue("Firstname", firstname.text)
firebaseDb.setUserValue("Surname", surname.text)
} else {
loginDialog.title = "An Issue occured!"
}
loginDialog.text = message
loginbutton.visible = true
registerCheckbox.visible = true
loginDialog.open()
}
I would like my database to be laid out as below, if this is appropriate for use? Multiple location groups with users within to access thier part of the database!
{
"groups" : {
"Colchester" : {
},
"Ipswich" : {
},
"CanaryWharf" : {
"Departments" : {
"Admin" : {
"members" : {
"user1" : true
}
},
"Assistant" : {
"members" : {
"user2" : true
}
},
"Reception" : {
"members" : {
"user3" : true,
"user1" : true
}
},
"Stylist" : {
"members" : {
"user4" : true
}
},
"Technician" : {
"members" : {
"user5" : true
}
}
}
}
}
Without access to the Firebase Cloud Firestore collections, detailed in the link;
Google Firebase Cloud Firestore Collections
I achieved the result of grouping of my users by the following code, if anyone still wants to add an improved version please do, but for now this works as intended for me:
App {
id: app
property var groupName
property var subGroupName
//these values are assigned when my user logs in from user values
//set in firebase on registration
firebaseDb.getUserValue("group", {
}, function(success, key, value) {
if(success){
groupName = value
console.log("GROUPNAME LOG: " + groupName)}})
}
//I then use these values across my app when storing data in the database
//an example of which is an AppButton elsewhere in my app
AppButton {
id: saveButton
onClicked: {
userData = ({"date": calendar.selectedDate, "name": userName +" "+ userSurname, "details": dayCycle.text, "status": "pending"})
var time = new Date().getTime()
firebaseDb.setValue("groups" + "/" + groupName + "/" + subGroupName + "/" + time, userData)
}
}

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

Handlebars + passport js

I'm using handlebars as a view engine.
For routes :
app.get('/', function(req, res) {
if(req.user) {res.render('user'), {name:req.user.username, id:req.user.id}}
else
if(!req.user) {res.render('index')};
});
For passport.js
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("SELECT * FROM users WHERE id = ? ",[id], function(err, rows){
done(err, rows[0]);
});
});
passport.use(
'local-signup',
new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows) {
if (err)
return done(err);
if (rows.length) {
return done(null, false, {message: 'That username is already taken'});
} else {
var newUserMysql = {
username: username,
password: bcrypt.hashSync(password, null, null) // use the generateHash function in our user model
};
var insertQuery = "INSERT INTO users ( username, password ) values (?,?)";
connection.query(insertQuery,[newUserMysql.username, newUserMysql.password],function(err, rows) {
newUserMysql.id = rows.insertId;
return done(null, newUserMysql);
});
}
});
})
);
I'm trying to find a solution, but it doesn't work. Whenever I try to use this, handlebars won't show anything up.. I know that ejs uses something like <%= user.username %> that does work, but can't convert that to handlebars..
if(req.user) {res.render('user'), {name:req.user.username, id:req.user.id}}
I figured it out till the end, my object {} was outside the (), not inside like it was supposed to be. This is the right code:
if(req.user) {res.render('user', {name:req.user.username, id:req.user.id})}

Resources