I’ve tried similar things. To understand my solution, you have to know, that my app consists of multiple modules. Every module can have multiple collections and methods. Modules represent a “thing”. If wanted, an entry of any collection can become a user. So when I have a “customer” collection, I could enable these customers to become users and log in.
The system I’ve built look like this:
var isOwnPatient, permission;
__Client_And_Server__();
/*
* We apply permissions to collections. In this case,
* dentists can log in and interact with patients.
*/
/*
* All methods are checked automatically.
* When using a function to check if a user, in this
* case the dentist is allowed to run it, we get the
* own document as first parameter, followed by all the
* arguments the method has been called with.
* Has to return true or false.
*/
isOwnPatient = function(dentist, data) {
return data.dentistId === dentist._id;
};
/*
* The permission can be a function, might be required
* because of Meteor's loading order. Alternatively we
* could just make it an object.
*/
permission = function() {
return {
// This is the module the dentist can interact with.
module: Confinet.CRM.Patients,
// Here we define, what data the dentist can get
// from the collections of the Patients module.
// We only have one collection in most cases.
collections: {
// Obviously, a dentist can query his patients.
patients: {
// A dentist can subscribe using *any* query, but
// it will be added to `$and`, along with the following
// "safety-query" we return. Can be a function, or just
// a mongo query (object).
query: function (dentist) {
return { dentistId: dentist._id };
},
// A dentist will get all the fields. We could also
// set it to an array of fields or a function,
// and return that array based on certain conditions.
fields: '*'
}
},
methods: {
create: isOwnPatient,
update: isOwnPatient,
delete: false
}
};
};
// share is coming from using CoffeeScript
share.Dentists.getCollection().permit(permission);
// ---
// generated by coffee-script 1.9.2
The patient subscription a dentist can query looks like this:
var Patients;
__Server__();
Patients = share.Patients.getCollection();
Meteor.publish('patients', function (query) {
// Instead of using `find` on a collection,
// we set the user and use `safeFind`, which
// will use our checks
return Patients
.setUser(this.userId)
.safeFind(query);
});
// ---
// generated by coffee-script 1.9.2
Methods are created using the normal method syntax, but using the module instead of Meteor
, like Patients.methods
. Those methods will automatically be checked.
I’ve posted this somewhere else already, but didn’t get any feedback. The system is designed to work safely for my application specifically, but the idea might work everywhere with little changes.
As you can see, I could easily create a .publish
function for collections, and it would be safe to query those. Fields would be checked, and access to documents would be checked as well. The system requires you to allow access, anything else won’t be returned.
Might look a little bit complicated first, but once you understand it, it’s so easy to use Let me know what you think