Accounts.onCreateUser not adding field to Meteor's user collection - javascript

I want to add a new field to Meteor's user collection:
server/fixtures.js:
Accounts.onCreateUser(function(options, user) {
user.role = 'Student'
// We still want the default hook's 'profile' behavior.
if (options.profile)
user.profile = options.profile;
return user
})
But when I do Meteor.users.find().fetch();:
Object
_id: "7zLDKQE4ACJCfeEhr"
username: "alex"
__proto__: Object
I don't see the field.
Isn't working in the template, either:
documents/document_page.js:
users: function() {
var users = _.map(Meteor.presences.find().fetch(), function(user) {
return Meteor.users.findOne({_id: user.userId})
})
return users
},
documents/user.html
<template name="user">
<li class="clearfix">
<img src="/avatar.png"/>
<div class="user-info">
<p>{{userId}}</p>
<p>{{username}}</p>
<p>{{role}}</p>
</div>
</li>
</template>
Only username is showing. What could be the problem?

You need to publish the custom fields. From the docs:
By default the server publishes username, emails, and profile (writable by user). See Meteor.users for more on the fields used in user documents.
The easiest way to do this is just to publish with a name of null which will automatically publish the documents without the need for a corresponding Meteor.subscribe:
Meteor.publish(null, function() {
return Meteor.users.find(this.userId, {fields: {role: 1}});
});
In this case we are publishing the role field which will be merged with the default fields already published for the current user.

Related

Graphql schema code to view user profiles

Am new to Graphql and actually following a tutorial. I am building a project in React Native and using AWS Amplify and Graphql for my backend. I needed a little change from the tutorial am following, I want users to be able to view user profile of other users in a their contact list just Instagram or Facebook.
In my schema.graphql I have the following code:
type User #model {
id: ID!
name: String!
imageUri: String
username: String!
email: String!
}
But I don't know the next code to write for user profile and the relationships for users to view other user user profiles.
I have been able to list contacts with the following code:
useEffect(() => {
const fetchUsers = async () => {
try {
const usersData = await API.graphql(
graphqlOperation(
listUsers
)
)
setUsers(usersData.data.listUsers.items);
} catch (e) {
console.log(e);
}
}
fetchUsers();
}, [])
Please I need guide on how to achieve viewing user profile when user is clicked on the contact list.
you have to add "auth" rule to your model
type User #model
#auth(
rules: [
#this is for logged-in user. cognito user is default for provider
# In order to prevent private users from creating, another rule must be set for creating
{ allow: private, operations: [read] }
# default provider is cognito
{ allow: private, provider: iam, operations: [read, create, update, delete] }
# Only Owner can update its own data
{ allow: owner, ownerField: "username", operations: [update] }
]
) {
id: ID!
name: String!
imageUri: String
username: String!
email: String!
}
In the above code, I defined two auth rules. One is for Cognito user, he can only read, another one for the "iam" user who has more privileges.

How to hold data without change in vue js

I have a user info object like this
data: function(){
return {
userinfo: {
name:'',
username:'',
imagePath:''
},
previousUserInfo:{}
}
}
and somewhere else i display this user infos:
<template>
<div> user name: {{userinfo.name}}</div>
<div> username: {{userinfo.username}}</div>
....
in some situation current user changes and i should save previous user data in previousUserInfo object:
this.$set(this, 'previousUserInfo', this.userinfo);
but when user fills new data in userinfo, previousUserInfo data also changes.
i also tried to user another variable to hold data but reuslts is the same :
var previousUserInfo = this.userinfo;
this.$set(this, 'previousUserInfo', previousUserInfo);
what's the problem?
this.userinfo and this.previousUserInfo are pointing to same object.
You can try doing deep copy value of this.userinfo
this.$set(this, 'previousUserInfo', JSON.parse(JSON.stringify(this.userinfo));

Bookshelf.js virtual field

I'm creating a rest service with knex and bookshelf. I want to return all the record with a user specific field which is not in the database.
A good example would be a IsFavorite boolean field on a Book list request. I would then show something else to the user for a favorite book.
Now let's say I have 3 tables: User, Book and Favorite. How would I code the "get" IsFavorite field from the book record?
I saw that bookshelf support virtuals by doing something like this :
var User = Bookshelf.Model.extend({
tableName: 'users',
outputVirtuals: true,
virtuals: {
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}
},
});
but I can't figure out how to fetch from my Favorite table within the virtuals.
Thank you

How to add additional fields to user documents (not in profile)?

I know that the classic way to add data to user collection is in profile array, but according to this document, it is not the best way to store data.
Is there an alternative to that, for example to create a field in the root of user collection at the same level with default fields (_id, username, etc.)?
There is nothing wrong per-se with the profile field, other than the fact that a users can (currently) directly update their own profile by default.
I don't find this behavior desired, as a user could store arbitrary data in the profile.
This may become a real security risk if the developer uses that field as a source of authority; for example, stores the user's groups or roles in it.
In this case, users could set their own permissions and roles.
This is caused by this code:
users.allow({
// clients can modify the profile field of their own document, and
// nothing else.
update: function (userId, user, fields, modifier) {
// make sure it is our record
if (user._id !== userId)
return false;
// user can only modify the 'profile' field. sets to multiple
// sub-keys (eg profile.foo and profile.bar) are merged into entry
// in the fields list.
if (fields.length !== 1 || fields[0] !== 'profile')
return false;
return true;
}
});
The first thing to do is to restrict writes to it:
Meteor.users.deny({
update() {
return true;
}
});
It could then be updated using methods and other authorized code.
If you add your own fields and want to publish them to the currently logged-in user, you can do so by using an automatic publication:
Meteor.publish(null, function () {
if (this.userId) {
return Meteor.users.find({
_id: this.userId
}, {
fields: {
yourCustomField1: 1,
yourCustomField2: 1
}
});
} else {
return this.ready();
}
});
Meteor.users is just a normal Mongo.Collection, so modifying it is done just like any other Collection. There is also the creation hook, Accounts.onCreateUser which allows you to add custom data to the user object when it is first created, as mentioned in #MatthiasEckhart's answer.
You could add extra fields to user documents via the accountsServer.onCreateUser(func) function.
For example:
if (Meteor.isServer) {
Accounts.onCreateUser(function(options, user) {
_.extend(user, {
myValue: "value",
myArray: [],
myObject: {
key: "value"
}
});
});
}
Please note: By default, the following Meteor.users fields are published to the client username, emails and profile. As a consequence, you need to publish any additional fields.
For instance:
if (Meteor.isServer) {
Meteor.publish("user", function() {
if (this.userId) return Meteor.users.find({
_id: this.userId
}, {
fields: {
'myValue': 1,
'myArray': 1,
'myObject': 1
}
});
else this.ready();
});
}
if (Meteor.isClient) {
Meteor.subscribe("user");
}

MongoDB _id as a String (MEAN Stack)

TL;DR - I am trying to use a collected value from a form input as a document _id but am getting a 404.
I've got a modal that opens and collects form data. My first input in the form is:
<input type="text" id="name" name="name" data-ng-model="name" />
When I try to modify the Mongo (Mongoose) model, to use name as the _id, the form wont post. I get a 404 from http://sitegoeshere/#!/somethings/whatever_i_type_in_for_name
Example model:
var SomethingSchema = new Schema({
_id: {
type: String,
default: 'default',
trim: true
}
}
mongoose.model('Something', SomethingSchema);
And in my Angular controller:
$scope.create = function() {
// Create new Something object
var something = new Somethings ({
_id: this.name
});
// Redirect after save
something.$save(function(response) {
$location.path('somethings/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
I've been told that MongoDB allows Strings as the _id type so what gives? Any ideas?
UPDATE: Here's something strange, too. I wanted to see if maybe this was a limitation or bug of Mongoose so I got into the database and created two documents:
> db.subnets.find().pretty()
{ "_id" : ObjectId("546bef63395b0694d51b5cbe"), "description" : "description!" }
{ "_id" : "mystring", "description" : "more description!" }
When I go to my app and try to pull their individual views up, I can see the data for my custom _id document but get a 500 Internal Server Error when I try to access the other.
GET http://localhost:3000/somethings/546bef63395b0694d51b5cbe 500 (Internal Server Error)
GET http://localhost:3000/somethings/mystring 200 OK
The problem is most likely with this.name - looks like it's undefined.

Categories