Meteor multiple dependent collections and their permissions - what's the best practice?


#1

Hello meteor community!

I’m starting my first meteor project and have stuck in how to organize collections and publish permissions.
To simplify things - let’s say I have users (built-in), teams, projects and tasks.
The rules:

  • A user can be in multiple teams
  • Each team has access only to their projects
  • Each project can have multiple tasks (which can be accessed only by the team members)

Right now:

  • I have three separate collections - Teams, Projects and Tasks
  • Teams collection stores the team name and members array with ID’s
  • Projects store project data and the teamID to which it belongs
  • Tasks store task data and the project to which it belongs

For projects my current setup is something like this:

// Permissions check
hasTeamAccess = function(teamId,userId) {
  return Teams.findOne({_id:teamId,members:userId}) === undefined ? false : true;
}

// Projects publications
Meteor.publish('projects', function(teamId) {
   check(teamId,String);
   if(this.userId && hasTeamAccess(teamId,this.userId)){
      return Projects.find({team:teamId});
   } else {
      this.ready();
   }
});

// Projects route
Router.route('/routetoteamprojects/:id', {
   template: 'projects',
   waitOn: function() {
      return [
         Meteor.subscribe('projects', this.params.id)
      ];
   },
   data: function() {
      return {
         projects: Projects.find({team:this.params.id}),
         team: Teams.findOne(this.params.id)
      }
   }
});

And that’s basically where I’m stuck :confused: What is the most elegant way to go further? Do I need to go in deeper permissions check all the way up all like:

hasProjectAccess = function(projectId,userId) {
   var project = Projects.findOne({_id:projectId);
   return hasTeamAccess(project.teamId,userId));
}

hasTaskAccess = function(taskId,userId) {
   var task = Projects.findOne({_id:taskId);

   if(hasProjectAccess(task.projectId,userId)){
      var project = Projects.findOne({_id:task.projectId);
      return hasTeamAccess(project.teamId,userId));
   }   
}

hasTaskCommentAccess = function(taskId,userId) {
   var comment = Comments.findOne({_id:taskId);
   if(hasTaskAccess(comment.TaskId,userId)){
      var task = Comments.findOne({_id:comment.taskId);
         
      if(hasProjectAccess(task.projectId,userId)){
         var project = Projects.findOne({_id:task.projectId);
         return hasTeamAccess(project.teamId,userId));
      } 
   }   
}

And so on. Or are there more elegant ways to do that? What are your suggestions?