MeteorJS useraccounts:core and meteor-roles - javascript

I am using MeteorJS to develop simple web app. I am new at MeteorJs. I use useraccounts:core package and meteor-roles by alanning. Is it posible to assign role to user while registering a new user ?
EDIT 1
I have tried using onCreateUser hook but something is not working.
Accounts.onCreateUser(function(options, user){
var role = ['unselected'];
Roles.addUsersToRoles(user, role);
return user;
});

The below method must run on the server side only. The clue is that you need to create first the user, get the id from creation and then attach a role to it.
Meteor.methods({
rolesCreateUser: function (user) {
if (_.isObject(user)) {
if (user.username) {
var id = Accounts.createUser({
username: user.username,
email: user.email,
password: user.password
});
//We add roles to the user
if (user.roles.length > 0) {
Roles.addUsersToRoles(id, user.roles);
}
_.extend(user, {id: id});
return user;
}
}
}
});
And then on the client side call the method with user's data:
Meteor.call('rolesCreateUser', newUserData, function (error, newCreatedUser) {
if (error) {
//The error code
} else {
//Do something with newCreatedUser
}
});

I have this way to create users (if i understond you example you alredy have some users, just need some roles, so with the current user just create this), also use some Login buttons customized or something like that
Server.js
Meteor.methods({
createUsers: function(email,password,roles,name){
var users = [{name:name,email:email,roles:[roles]},
];
.each(users, function (user) {
var id;
id = Accounts.createUser({
email: user.email,
password: password,
profile: { name: user.name }
});
if (user.roles.length > 0) {
Roles.addUsersToRoles(id, user.roles);
}
});
},
deleteUser : function(id){ ///Some Delete Method (ignore if dont needed)
return Meteor.users.remove(id);
},
});
Publish Methods
//publish roles
Meteor.publish(null, function (){
return Meteor.roles.find({})
})
Meteor.publish("Super-Admin", function () {
var user = Meteor.users.findOne({_id:this.userId});
if (Roles.userIsInRole(user, ["Super-Admin"])) {
return Meteor.users.find({}, {fields: {emails: 1, profile: 1, roles: 1}});
}
this.stop();
return;
});
Meteor.publish("Admin", function () {
var user = Meteor.users.findOne({_id:this.userId});
if (Roles.userIsInRole(user, ["Admin"])) {
return Meteor.users.find({}, {fields: {emails: 1, profile: 1, roles: 1}});
}
this.stop();
return;
});
Meteor.publish(null, function (){
return Meteor.roles.find({})
})
So on the Client side client/register.html
<template name="register">
<form id="register-form" action="action" >
<input type="email" id="register-email" placeholder="Nombre Nuevo Usuario">
<input type="password" id="register-password" placeholder="Password">
<select id="register-rol" class="form-control">
<option value="Admin" selected>Admin</option>
<option value="Super-Admin" selected>Super Admin</option>
<option value="Normal" selected>Normal</option>
</select>
<input type="submit" value="Register">
</form>
</tempalate>
and on register.js call the server methods
Template.registrar.events({
'submit #register-form' : function(e, t) {
e.preventDefault();
var email = t.find('#register-email').value,
password = t.find('#register-password').value,
roles = $( "#register-rol" ).val();
Meteor.call("createUsers", email, password,roles);
return false;
},
'click #deleteUser' : function(event,template){
var idUsuario= this._id;
Meteor.call('deleteUser',{_id:idUsuario})
}
});
Delete Part(html) this is optional just too look if accounts are creating correctly
{{#each users}}
<li id="user"><h6>{{email}}</h6><h6>{{roles}}</h6></li>
<button id="deleteUser" class="btn btn-danger btn-xs" > Borrar Usuario {{email}} </button>
{{/each}}
client/registerList.js
Template.registrar.helpers({
users: function () {
return Meteor.users.find();
},
email: function () {
return this.emails[0].address;
},
roles: function () {
if (!this.roles) return '<none>';
return this.roles.join(',');
}
});
Remember Subscribe
Meteor.subscribe('Admin');
Meteor.subscribe('Super-Admin');
Hope this help sorry for the messy code

You may want to use OnCreateUser hook: http://docs.meteor.com/#/full/accounts_oncreateuser

Related

Angular5 reactive forms with mailcheck.js

below is HTML code for form
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control"
(blur)="suggestEmail(signupForm.controls['userData'].controls.email.value)"
id="email" formControlName="email">
<span class="help-block" *ngIf="!signupForm.get('userData.email').valid && signupForm.get('userData.email').touched">
please enter a valid email id
</span>
</div>
Below is ts code
constructor(private fb: FormBuilder) {
this.signupForm = this.fb.group({
userData: this.fb.group({
email: [null, [Validators.required, Validators.email]]
})
});
}
ngOnInit() {
}
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: function (suggestion) {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Right now, value of suggestions.full comes in alert if its being called. But I am trying to show suggestions.full in html side, like as a error warning.
Below is link to my stackblitz
stackblitz
To avoid potential problems with access to this within the Mailcheck.run suggested callback, you could save the results of Mailcheck.run, check them and, if appropriate, set an error on your form field.
let check = Mailcheck.run({
email: email,
... other stuff ...
suggested: (suggestion) => {
return suggestion;
},
empty: () => {
return false; // or however you want to handle it...
}
if (check && check.full) {
this.suggestedEmail = check.full;
this.signupForm.get('userData.email').setErrors({ 'has_suggestion': true })
}
// then in your template (using a getter)
<span class="help-block"
*ngIf="f.invalid && f.touched && f.errors?.has_suggestion">
Suggestion: {{suggestedEmail}}
</span>
Please find this stackblitz -- hope it helps!
Instead of using a regular function which will be lost this scope whereas arrow function keeps track of this. Read more about the difference here https://stackoverflow.com/a/34361380/5836034
do something like this
....
suggestion: any;
....
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: (suggestion) => {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
this.suggestion = suggestion;
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Observe the use of arrow function, to keep track of this scope and also, assigning the value of suggestion to your class variable via
this.suggestion = suggestion
in your template, you can now have access to suggestion like so
<div *ngIf="suggestion">{{suggestion.full}} </div>
Source: https://stackblitz.com/edit/angular-email-checker-bjcrcc

How to Get Params from Http Post and Insert

I am trying to capture user entered credentials and use them as a parameter to query a database. Unfortunately, I am a little lost on how to code that process. I am using angular,express, node, jQuery, and html. I am not very experienced with angular, node, and jQuery, so forgive me if this is something very simple; I am here to learn.
Here is the html where the forms live:
<!DOCTYPE html >
<html ng-app="token">
<%include header%>
<%include navbar%>
<div ng-controller="TokenCtrl">
<form ng-submit="submitLogin(loginForm)" role="form" ng-init="loginForm = {}">
<div class="form-group">
<label>email</label>
<input type="email" name="email" ng-model="loginForm.email" required="required" class="form-control"/>
</div>
<div class="form-group">
<label>password</label>
<input type="password" name="password" ng-model="loginForm.password" required="required" class="form-control"/>
</div>
<button class="btn btn-primary btn-lg" ng-click="handleLoginBtnClick()">Sign in</button>
</form>
</div>
</body>
Here is the JS for the TokenCtrl and token module, which is a derivative of ng-token-auth:
var a = angular.module('token', ['ng-token-auth']);
a.config(function($authProvider) {
// the following shows the default values. values passed to this method
// will extend the defaults using angular.extend
$authProvider.configure({
apiUrl: '/users',
tokenValidationPath: '/auth/validate_token',
signOutUrl: '/auth/sign_out',
emailRegistrationPath: '/auth',
accountUpdatePath: '/auth',
accountDeletePath: '/auth',
confirmationSuccessUrl: window.location.href,
passwordResetPath: '/auth/password',
passwordUpdatePath: '/auth/password',
passwordResetSuccessUrl: window.location.href,
emailSignInPath: '/auth/sign_in/:email/:password',
storage: 'cookies',
forceValidateToken: false,
validateOnPageLoad: true,
proxyIf: function() { return false; },
proxyUrl: '/proxy',
omniauthWindowType: 'sameWindow',
tokenFormat: {
"access-token": "{{ token }}",
"token-type": "Bearer",
"client": "{{ clientId }}",
"expiry": "{{ expiry }}",
"uid": "{{ uid }}"
},
cookieOps: {
path: "/",
expires: 9999,
expirationUnit: 'days',
secure: false,
domain: 'domain.com'
},
createPopup: function(url) {
return window.open(url, '_blank', 'closebuttoncaption=Cancel');
},
parseExpiry: function(headers) {
// convert from UTC ruby (seconds) to UTC js (milliseconds)
return (parseInt(headers['expiry']) * 1000) || null;
},
handleLoginResponse: function(response) {
return response.data;
},
handleAccountUpdateResponse: function(response) {
return response.data;
},
handleTokenValidationResponse: function(response) {
return response.data;
}
});
});
a.controller('TokenCtrl', function($scope, $auth) {
$scope.handleRegBtnClick = function() {
$auth.submitRegistration($scope.registrationForm)
.then(function(resp) {
// handle success response
})
.catch(function(resp) {
// handle error response
});
};
$scope.handlePwdResetBtnClick = function() {
$auth.requestPasswordReset($scope.pwdResetForm)
.then(function(resp) {
// handle success response
})
.catch(function(resp) {
// handle error response
});
};
$scope.handleLoginBtnClick = function() {
$auth.submitLogin($scope.loginForm)
.then(function(resp) {
// handle success response
})
.catch(function(resp) {
// handle error response
});
};
$scope.handleSignOutBtnClick = function() {
$auth.signOut()
.then(function(resp) {
// handle success response
})
.catch(function(resp) {
// handle error response
});
};
});
On the run of this function, it leads to this url:
'/auth/sign_in/:email/:password'
Using Express, I route this url to another function. Here is the route code:
app.post('/users/auth/sign_in/:email/:password', routes.verifyusers);
Which leads to,
exports.verifyusers= function(req, res) {
models.user.find({
where: {
email: req.params.email,
password: req.params.password
}
}).then(function(user) {
if(user) {
console.log("alright !")
};
});
};
When the code runs, this is what I get in the console:
Executing (default): SELECT "id", "username", "email", "password", "createdAt", "updatedAt" FROM "users" AS "user" WHERE "user"."email" = ':email' AND "user"."password" = ':password' LIMIT 1;
:email
:password
This is result is irrespective to the form data.
I think the problem is coming from emailSignInPath: '/auth/sign_in/:email/:password',
You should try with
// config
emailSignInPath: '/auth/sign_in'
// route declaration
app.post('/users/auth/sign_in', routes.verifyusers);
// route action
exports.verifyusers = function(req, res) {
models.user.find({
where: {
email: req.body.email,
password: req.body.password
}
}).then(function(user) {
if(user) {
console.log("alright !")
};
});
};
ps: don't forget to declare a body parser in your app app.use(express.bodyParser())

How to show data from postgres in meteor

I am using meteor-postgres and want to display results from SQL query.
Html:
...
<template name="myForm">
<form class="search" method="GET">
<input required="Required" type="text" name="width" placeholder="cm"/>
<input type="submit"/>
</form>
Results:
<ul>
<!--How do I render results here-->
</ul>
...
JS
Services = new SQL.Collection('services');
// in client
Template.myForm.events({
"submit form": function (event) {
var width = event.target.width.value;
// TypeError: table is undefined,
// Maybe because I am on client side?
console.log(services.first().fetch());
// How can I get data here and render it to html?
}
});
I dont know what else should I say but StackOverflows want me to add more text!
I decided to use https://github.com/numtel/meteor-pg because it has nice examples.
Update
It is better and simpler to use PgSubscription.change:
Template:
<template name="hello">
<label>id</label>
<input type="number" id="myid" />
{{#each services}}
{{id}}
{{/each}}
</template>
JS
myServices = new PgSubscription('services');
if (Meteor.isClient) {
Template.hello.helpers({
services: function () {
return myServices.reactive();
}
});
function handleInput(event, template) {
var idVal = template.find("#myid").value;
console.log("client change detected, new value:");
console.log(idVal);
myServices.change(idVal);
}
Template.hello.events({
"keyup #myid": function(event,template) {
handleInput(event,template);
},
"change #myid": function(event,template) {
handleInput(event,template);
}
});
}
if (Meteor.isServer) {
var PG_CONNECTION_STRING = "postgres://root:root#localhost:5433/parcelService";
var liveDb = new LivePg(PG_CONNECTION_STRING, "myApp");
var closeAndExit = function () {
liveDb.cleanup(process.exit);
};
// Close connections on hot code push
process.on('SIGTERM', closeAndExit);
// Close connections on exit (ctrl + c)
process.on('SIGINT', closeAndExit);
Meteor.publish('services', function (id) {
console.log("server services, id:");
console.log(id);
return liveDb.select(
'SELECT * FROM services WHERE id = $1', [ id ]
);
});
}
Old Method:
On client side I defined ReactiveVar for template
Template.myForm.created = function () {
this.asyncServices = new ReactiveVar(["Waiting for response from server..."]);
}
and helper for data
Template.myForm.helpers({
myData: function () {
return Template.instance().asyncServices.get();
}
});
now trigggering action with
Template.myForm.events({
'keyup input': function (evt, template) {
var asyncServicesX = Template.instance().asyncServices;
Meteor.call('services', params, function(error, response){
if (error) throw error;
asyncServicesX.set(response);
});
}
And finally method on server side, where sql is executed:
Meteor.methods({
'services': function (params) {
Future = Npm.require('fibers/future');
var future = new Future();
// Obtain a client from the pool
pg.connect(PG_CONNECTION_STRING, function (error, client, done) {
if (error) throw error;
// Perform query
client.query(
'select * from services where col1=$1 and col2=$2',
params,
function (error, result) {
// Release client back into pool
done();
if (error) throw error;
future["return"](result.rows);
}
)
});
return future.wait();
}
});

Comparing value from input with backbone collection data

I'm trying to create very simple login with backbonejs. Collection stores usernames and passwords. Login view has two inputs and on click it should perform check function and compare input value with data from collection.
Html part looks like this:
<div class="login-block">
<script type="text/template" id="start">
<form id="login">
<div class="input-wrapper"><input type="text" placeholder="Username" id="username" required></div>
<div class="input-wrapper"><input type="password" placeholder="Password" id="password" required></div>
<div class="input-wrapper"><button class="btn">Sign in!</button></div>
</form>
</script>
<div class="error" class="block">
Error
</div>
<div class="success">
Success
</div>
</div>
Here is my Js code:
var User = Backbone.Model.extend({
defaults: {
login: 'root',
mail: 'root#mail.com',
password: ''
}
});
var user = new User();
//variable to store username
var loginData = {
username: "",
password: ""
}
// userbase
var UserCollection = Backbone.Collection.extend({
model: User
});
var userCollection = new UserCollection([
{
username: 'Ivan',
mail: 'ivan#mail.com',
password: '1234'
},
{
username: 'test',
mail: 'test#mail.com',
password: 'test'
}
]);
// login page
var LoginView = Backbone.View.extend({
el: $(".login-block"),
events: {
"click .btn": "check"
},
check: function(){
loginData.username = this.$el.find("#username").val(); // store username
loginData.password = this.$el.find("#password").val();// store password
if (loginData.username === userCollection.each.get("username") && loginData.password === userCollection.each.get("password"))
{appRouter.navigate("success", {trigger: true});
}else{
appRouter.navigate("error", {trigger: true});
}
},
render: function () {
//$(this.el).html(this.template());
var template = _.template($('#start').html())
$(this.el).html(template());
//template: template('start');
return this;
}
});
var loginView = new LoginView({collection: userCollection});
var AppRouter = Backbone.Router.extend({
routes: {
'': 'index', // start page
'/error': 'error',
'/success': 'success'
},
index: function() {
loginView.render();
console.log("index loaded");
},
error: function(){
alert ('error');
},
success: function(){
console.log('success');
}
});
var appRouter = new AppRouter();
Backbone.history.start();
It works fine to the check function, and it stores username and password, but something is clearly wrong either with router or check function when it starts comparison. Instead of routing to success or error page, it rerenders index page.
P.S I didn't use namespacing and code in general is not of a greatest quality, but it was made for educational purpose only.
You have to add the attribute type="button" to your button, otherwise it will submit the form when clicked (See this question):
<script type="text/template" id="start">
<form id="login">
<div class="input-wrapper"><input type="text" placeholder="Username" id="username" required></div>
<div class="input-wrapper"><input type="password" placeholder="Password" id="password" required></div>
<div class="input-wrapper"><button class="btn" type="button">Sign in!</button></div>
</form>
</script>
You can also return false in the click event handler, which would cancel the default action. (submitting the form, if you don't add type="button").
For comparing the values with the hardcoded collection, you can't call each as you where doing (which is an iteration function provided by Underscore) because you would receive an error. You could use Underscore's findWhere method which is also available in Backbone collections. So the click event handler (Your check function) could look like this:
check: function(){
loginData.username = this.$el.find("#username").val(); // store username
loginData.password = this.$el.find("#password").val();// store password
if(userCollection.findWhere({username: loginData.username, password: loginData.password})){
appRouter.navigate("success", {trigger: true});
}else{
appRouter.navigate("error", {trigger: true});
}
return false;
},
You can try it on this fiddle
The logic check you're doing doesn't look like it would work to me. I would expect the following to generate an error:
userCollection.each.get('username')
the function you're calling on your collection, each, is a wrapped underscore method which takes a function callback as a parameter. If you want to check your username and password, I'd do something like this:
var user = userCollection.findWhere({ username: loginData.userName });
This will return you the model where the username matches. Then you can check the password of that model:
if (user.get('password') === loginData.password) {
// do something
} else {
// do something else
}
EDIT Heck, you can do both checks at once:
var user = userCollection.findWhere({ username: loginData.userName, password: loginData.password });
I'll leave the previous code up just to demonstrate.

How to create inputs that you can keep adding to a collection in meteor

I am trying to figure out how to create a form that has a input field, as well as a "+" button to add another input field. I than want to take those inputs and insert them into a collection. Than output them as a list. Basically I want to give the option to add as many list items as possible. If there is a better way to do this instead of a "+" button to add input fields,I' open to any suggestions.
code so far
HTML
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
<template name="postItem">
<h2>{{service}}</h2>
<ul><li>{{task}}</li></ul>
</template>
<template name="postSubmit">
<form>
<label for="service">Add a Service</label>
<input name="service" type="text" value="" placeholder="Service Type"/>
<label for="task">Add a task (spaces between each kind)</label>
<input name="task" type="text" value="" placeholder="type or task for service"/>
<input type="submit" value="Submit" />
</form>
</template>
JS
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
service: $(e.target).find('[name=service]').val(),
task: $(e.target).find('[name=task]').val()
};
Meteor.call('post', post, function(error, id) {
if (error)
return alert(error.reason);
Router.go('postPage', {_id: id});
});
}
});
Posts = new Meteor.Collection('posts');
Posts.allow({
update: ownsDocument,
remove: ownsDocument
});
Posts.deny({
update: function(userId, post, fieldNames) {
// may only edit the following two fields:
return (_.without(fieldNames, 'service', 'task').length > 0);
}
});
Meteor.methods({
post: function(postAttributes) {
var user = Meteor.user(),
postWithSameLink = Posts.findOne({url: postAttributes.url});
// ensure the user is logged in
if (!user)
throw new Meteor.Error(401, "You need to login to post new stories");
// ensure the post has a service
if (!postAttributes.service)
throw new Meteor.Error(422, 'Please fill in a service');
// ensure the post has a task
if (!postAttributes.task)
throw new Meteor.Error(422, 'Please fill in a task');
// check that there are no previous posts with the same link
if (postAttributes.url && postWithSameLink) {
throw new Meteor.Error(302,
'This link has already been posted',
postWithSameLink._id);
}
// pick out the whitelisted keys
var post = _.extend(_.pick(postAttributes, 'service', 'task'), {
userId: user._id,
author: user.username,
submitted: new Date().getTime()
});
var postId = Posts.insert(post);
return postId;
}
});
Template.postsList.helpers({
posts: function() {
return Posts.find({}, {fields: {service: 1, task: 1}}).map(function(post, index) {
return post;
});
}
});

Categories

Resources