I have an app in which I'm using a template helper. I have the following code:
UI.registerHelper('ProfileNameByUserId', function(userid) {
console.log('Userid: ' + userid);
var user = Meteor.users.findOne({'_id': userid});
console.log.log('User:' + user);
return user.username
});
I'm calling this in my template as follows:
{{#each getDocuments}}
{{ProfileNameByUserId userid}}
{{/each}}
and in the template helper:
Template.documentsIndex.helpers({
getDocuments: function () {
return Documents.find({}, { sort: { createdAt: -1 }});
}
});
The publish and subscribe are as follows:
Routes.route('/documents', {
name: 'documents',
subscriptions: function (params, queryParams) {
this.register('documentsIndex', Meteor.subscribe('documents'));
},
action: function (params, queryParams) {
.....
});
}
});
Meteor.publish('documents', function () {
return Documents.find({})
});
I'm sure the userId is passed on, as a console.log statement shows the correct id. The issue is that the user is 'undefined' so it can't find the username.
I'm using SimpleSchema to define a users schema which looks as follows:
Users = Meteor.users;
Schema = {};
Schema.UserProfile = new SimpleSchema({
firstName: {
type: String,
optional: true
},
lastName: {
type: String,
optional: true
},
gender: {
type: String,
allowedValues: ['Male', 'Female'],
optional: true
},
});
Schema.User = new SimpleSchema({
username: {
type: String,
optional: true
},
emails: {
type: Array,
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date,
optional: true,
denyUpdate: true,
autoValue: function() {
if (this.isInsert) {
return new Date();
}
}
},
profile: {
type: Schema.UserProfile,
optional: true
},
services: {
type: Object,
optional: true,
blackbox: true
},
roles: {
type: [String],
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
});
Replacing Meteor.users.findOne() in the template helper with Users.findOne() does not work either.
Any idea why user remains undefined?
You need to add a publication and subscription for the users that you want to show.
In the most general case in which all users are published:
Meteor.publish('allUsers', function () {
return Meteor.users.find();
});
Subscribe to this in your route and you will not have the user undefined in your helper.
Note that you should only publish the users that you need, but since I do not know you application structure I cannot give you a query for that.
Related
I'm trying to create an array of objects using simple-schema. In this example, a person has a careerHistory object that is filled with individual positions. I can't figure out how to insert and update the array of objects. It just errors. The only way I can get it to work is to be explicit, eg. 'careerHistory.position.1.company'.
I'm using:
meteor
simple-schema
reactjs
collection2-core
Path: mongodb
const ProfileCandidateSchema = new SimpleSchema({
userId: {
type: String,
regEx: SimpleSchema.RegEx.Id
},
careerHistory: { type: Array, optional: true },
'careerHistory.position': { type: Object, optional: true },
'careerHistory.position.$': { type: Object, optional: true },
'careerHistory.position.$.company': { type: String, optional: true },
'careerHistory.position.$.title': { type: String, optional: true }
});
Path: updateForm.js
ProfileCandidate.update(id, { $set: {
'careerHistory.position.company': this.state['position.company'],
'careerHistory.position.title': this.state['position.title'],
}
});
If you want to push object to array do
ProfileCandidate.update(id,
{ $push: { careerHistory: { position: {
'company': this.state['position.company'],
'title': this.state['position.title'],
}}}
});
if you want to update particular object
ProfileCandidate.update({ _id: id, 'careerHistory.position.company': this.state['position.company'] }, { $set: {
'careerHistory.position.$.title': this.state['position.title'],
}
});
see $ in set
I'm struggling to figure out how to make password validation with my user Schema, that's how I've being doing so far:
This is the schema:
Schema = {};
Schema.UserProfile = new SimpleSchema({
//LOTS OF FIELDS WORKING FINE
});
Schema.User = new SimpleSchema({
username: {
type: String,
optional: true
},
emails: {
type: Array,
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
label: "Perfil",
optional: false
},
services: {
type: Object,
blackbox: true
},
"services.$": {
type: Object,
blackbox: true
},
"services.$.password": { // IS IT RIGHT?
type: String,
label: "Senha",
min: 8
},
roles: {
type: String,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
And this is how I'm saving:
let company = {};
company = {
email: $('#email').val(),
password: $('#password').val(),
roles: 'company',
profile: companyProfile
}
Meteor.call('saveUser', company, function(error, result) {
if ( error ) {
console.log(error);
}
}
Meteor.methods({
saveUser: function(data) {
return Accounts.createUser(data);
}
});
I'm still a beginner, so I'm probably messing something up here. When I try to create the user, if there is an issue with any of the fields, the validation throws an error as expected. However no error is thrown in case I miss the password, any ideas of what I'm doing wrong here?
------------------------------- UPDATE ----------------------------------
Thanks #aedm for your answer. I really wish I could have something like this to verify the password and password confirmation:
password: {
type: String,
label: "Senha",
min: 8
},
password_confirmation: {
type: String,
label: "Confirmação de Senha",
min: 8,
custom: function () {
if (this.value !== this.field('password').value) {
return "passwordMismatch";
}
}
},
I guess it's not possible then, is it?
Meteor only stores a bcrypt hash for the password, it's always longer than 8 characters.
Instead, your saveUser method should throw an error when the password criteria isn't met.
Meteor.methods({
saveUser: function(data) {
if (data.password.length < 8) throw new Meteor.Error("Password too short");
return Accounts.createUser(data);
}
});
I'd try to avoid defining a schema for users, Meteor handles it pretty well without one, and it's not trivial how to do it properly.
I'm new to Meteor and programming, if this doesn't make sense or you need more info please let me know.
I'm loading a profile page of another user. So I have 2 userIds; this.userId and the other users Id. I want to use autoValue to save both userIds when an action is taken. I can't figure out how to set the other users id even though I can display it on the html page.
Path: schema.js
Schemas.class = new SimpleSchema({
Title: {
type: String,
optional: true
},
teacherProfile: {
type: String,
optional: true,
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
studentProfileId: {
type: String,
optional: true,
type: String,
autoform: {
defaultValue: "studentProfileId",
type: "hidden"
}
}
});
Path: profile.js
Template.teacherProfile.helpers({
studentProfile: ()=> {
var id = FlowRouter.getParam('id');
return Meteor.users.findOne({_id: id});
}
});
This is my solution it seems to work. Thanks to everyone that helped.
Path: schema.js
Schemas.class = new SimpleSchema({
Title: {
type: String,
optional: true
},
teacherProfile: {
type: String,
optional: true,
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
studentProfileId: {
type: String,
optional: true,
autoform: {
type: "hidden"
}
}
});
Path: profile.js
Template.profile.helpers({
studentProfile: ()=> {
var id = FlowRouter.getParam('id');
return Meteor.users.findOne({_id: id});
},
studentProfileId: () => {
return FlowRouter.getParam('id');
}
)};
Path: profile.html
<template name="profile">
{{#autoForm collection="Jobs" id="Offer" type="insert"}}
{{> afQuickField name='Title'}}
{{> afQuickField name='studentUserId' value=studentProfileId}}
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
</template>
Here is my method:
removeRole: function(role) {
check(role, String);
var user = Meteor.user();
if (!user || ! AccountsAdmin.checkForAdminAuthentication(user))
throw new Meteor.Error(401, "You need to be an authenticated admin");
// handle non-existing role
if (Meteor.roles.find({name: role}).count() < 1 )
throw new Meteor.Error(422, 'Role ' + role + ' does not exist.');
if (role === 'admin')
throw new Meteor.Error(422, 'Cannot delete role admin');
// remove the role from all users who currently have the role
// if successfull remove the role
Meteor.users.update(
{roles: role },
{$pull: {roles: role }},
{multi: true},
function(error) {
if (error) {
throw new Meteor.Error(422, error);
} else {
Roles.deleteRole(role);
}
}
);
},
Here is the error I receive when looking at the call in Kadira:
message: After filtering out keys not in the schema, your modifier is now empty
stack:
Error: After filtering out keys not in the schema, your modifier is now empty
at [object Object].doValidate (packages/aldeed_collection2-core/lib/collection2.js:282:1)
at [object Object]._.each.Mongo.Collection.(anonymous function) [as update] (packages/aldeed_collection2-core/lib/collection2.js:83:1)
at [object Object].Meteor.methods.removeRole (packages/accounts-admin-ui-bootstrap-3/server/methods.js:86:1)
Line 86 of that methods.js is "Meteor.users.update" in the code above. When trying to debug this using breakpoints it appears this is where the error is happening as well.
I am using this package to help with the user management UI that I am creating, although I have did some customizing to it. I have also tested this on a different version of my project for troubleshooting and I have found that it works when I don't use the Collection2 package.
Here is my custom schema setup:
Schema = {};
Schema.UserProfile = new SimpleSchema({
userProfile: {
type: Object
},
'userProfile.firstName': {
type: String,
optional: true,
label: "First Name"
},
'userProfile.lastName': {
type: String,
optional: true,
label: "Last Name"
},
'userProfile.birthday': {
type: Date,
optional: true,
label: "Date of Birth"
},
'userProfile.contactEmail': {
type: String,
optional: true,
label: "Email"
},
'userProfile.gender': {
type: String,
allowedValues: ['Male', 'Female'],
optional: true,
label: "Gender"
},
'userProfile.address': {
type: String,
optional: true,
label: "Address"
},
'userProfile.city': {
type: String,
optional: true,
label: "City"
},
'userProfile.stateProvince': {
type: String,
optional: true,
label: "State/Province"
},
'userProfile.postalCode': {
type: String,
optional: true,
label: "Postal Code"
},
'userProfile.phoneNumber': {
type: String,
optional: true,
label: "Phone Number"
},
userProfilePayment: {
type: Object
},
'userProfilePayment.paymentEmail': {
type: String,
optional: true,
label: "Payment Email"
},
'userProfilePayment.address': {
type: String,
optional: true,
label: "Address"
},
'userProfilePayment.city': {
type: String,
optional: true,
label: "City"
},
'userProfilePayment.stateProvince': {
type: String,
optional: true,
label: "State/Province"
},
'userProfilePayment.postalCode': {
type: String,
optional: true,
label: "Postal Code"
},
'userProfilePayment.phoneNumber': {
type: String,
optional: true,
label: "Phone Number"
},
});
Schema.User = new SimpleSchema({
username: {
type: String,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
emails: {
type: Array,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
type: Object,
optional: true,
blackbox: true
},
// Add `roles` to your schema if you use the meteor-roles package.
// Option 1: Object type
// If you specify that type as Object, you must also specify the
// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
// Example:
// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
// You can't mix and match adding with and without a group since
// you will fail validation in some cases.
roles: {
type: Object,
optional: true,
blackbox: true
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
type: Date,
optional: true
},
// Added to work with mizzao:user-status
status: {
type: Object,
optional: true,
blackbox: true
}
});
Meteor.users.attachSchema(Schema.User);
Meteor.users.allow({
// NOTE: The client should not be allowed to add users directly!
insert: function(userId, doc) {
// only allow posting if you are logged in
console.log("doc: " + doc + " userId: " + userId);
return !! userId;
},
update: function(userId, doc, fieldNames) {
// only allow updating if you are logged in
console.log("doc: " + doc + " userId: " + userId);
// NOTE: a user can only update his own user doc and only the 'userProfile' and 'userProfilePayment' field
return !! userId && userId === doc._id && _.isEmpty(_.difference(fieldNames, ['userProfile, userProfilePayment']));
},
/* NOTE: The client should not generally be able to remove users
remove: function(userID, doc) {
//only allow deleting if you are owner
return doc.submittedById === Meteor.userId();
}
*/
});
To remove a key in a mongodb update you want to use the $unset operator:
Meteor.users.update({ roles: role },{ $unset: { roles: 1 }}, { multi: true })
It's just a bit unusual that in your model a user can only have a single role.
I'm having some trouble with updating a user account. I use the following schema (collection2):
lib/collections/users.js
Users = Meteor.users;
var Schemas = {};
Schemas.User = new SimpleSchema({
gender: {
type: Number,
min: 1
},
s_gender: {
type: Number,
min: 1,
optional:false
},
picture: {
type: String,
custom: function() {
var base64Matcher = new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$");
var value = this.value.replace("data:image/png;base64,","");
if(!base64Matcher.test(value))
{
return 'no picture';
}
else
{
return true;
}
}
}
});
Users.attachSchema(Schemas.User);
Now I do the update with the following code:
client/templates/start.js
Users.update({_id: Meteor.userId()}, {
$set: {picture: picture, gender: gender, s_gender: s_gender}
}, {validationContext: "updateUser"}, function (error, result) {
if (error) {
errorObjs = Users.simpleSchema().namedContext("updateUser").invalidKeys();
console.log(errorObjs);
}
console.log(result);
});
The validation passes, but I only get a "0" in results (errors are null) - the update isn't working. Errors are shown if I have an empty field, so the validation is working well. If I detach the schema, the update works fine.
Did I forget something here or why isn't he updating when validation passes?
// Edit: Also I see, that Meteor doesn't create users anymore.
I believe you need to use Users.profile.foo instead of Users.foo, because Users is a special meteor collection and you can only save new fields inside the profile field. Try using Simple Schema/Collection 2 suggested User schema as a starting point (I'll copy it bellow). Notice the "profile schema" is loaded before the user schema:
Schema = {};
Schema.UserProfile = new SimpleSchema({
firstName: {
type: String,
regEx: /^[a-zA-Z-]{2,25}$/,
optional: true
},
lastName: {
type: String,
regEx: /^[a-zA-Z]{2,25}$/,
optional: true
},
birthday: {
type: Date,
optional: true
},
gender: {
type: String,
allowedValues: ['Male', 'Female'],
optional: true
},
organization : {
type: String,
regEx: /^[a-z0-9A-z .]{3,30}$/,
optional: true
},
website: {
type: String,
regEx: SimpleSchema.RegEx.Url,
optional: true
},
bio: {
type: String,
optional: true
}
});
Schema.User = new SimpleSchema({
username: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/
},
emails: {
type: [Object],
optional: true
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
services: {
type: Object,
optional: true,
blackbox: true
}
});
Meteor.users.attachSchema(Schema.User);
source: https://github.com/aldeed/meteor-collection2