mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 10:01:40 -05:00
owner -> member; set allow/deny for posts, comments, users
This commit is contained in:
parent
40d38d1364
commit
fc8af1c9da
15 changed files with 190 additions and 312 deletions
|
@ -1,12 +1,6 @@
|
|||
Template.comment_edit.helpers({
|
||||
commentFields: function () {
|
||||
var schema = Comments.simpleSchema()._schema;
|
||||
var comment = this.comment;
|
||||
var fields = _.filter(_.keys(schema), function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
return Users.can.editField(Meteor.user(), field, comment);
|
||||
});
|
||||
return fields;
|
||||
return Comments.simpleSchema().getEditableFields(Meteor.user());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
Template.comment_submit.helpers({
|
||||
commentFields: function () {
|
||||
var schema = Comments.simpleSchema()._schema;
|
||||
var fields = _.filter(_.keys(schema), function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
return Users.can.submitField(Meteor.user(), field);
|
||||
});
|
||||
return fields;
|
||||
return Comments.simpleSchema().getEditableFields(Meteor.user());
|
||||
},
|
||||
reason: function () {
|
||||
return !!Meteor.user() ? i18n.t('sorry_you_do_not_have_the_rights_to_comments'): i18n.t('please_log_in_to_comment');
|
||||
|
|
|
@ -27,7 +27,7 @@ Telescope.schemas.comments = new SimpleSchema({
|
|||
},
|
||||
body: {
|
||||
type: String,
|
||||
editableBy: ["owner", "admin"],
|
||||
editableBy: ["member", "admin"],
|
||||
autoform: {
|
||||
rows: 5
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ Telescope.schemas.comments = new SimpleSchema({
|
|||
postId: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"], // TODO: should users be able to set postId, but not modify it?
|
||||
editableBy: ["member", "admin"], // TODO: should users be able to set postId, but not modify it?
|
||||
autoform: {
|
||||
omit: true // never show this
|
||||
}
|
||||
|
@ -91,23 +91,7 @@ Telescope.schemas.comments = new SimpleSchema({
|
|||
Telescope.schemas.comments.internationalize();
|
||||
Comments.attachSchema(Telescope.schemas.comments);
|
||||
|
||||
/**
|
||||
* Attach schema to Posts collection
|
||||
*/
|
||||
|
||||
|
||||
// Note: is the allow/deny code still needed?
|
||||
|
||||
Comments.deny({
|
||||
update: function(userId, post, fieldNames) {
|
||||
if(Users.is.adminById(userId))
|
||||
return false;
|
||||
// deny the update if it contains something other than the following fields
|
||||
return (_.without(fieldNames, 'body').length > 0);
|
||||
}
|
||||
});
|
||||
|
||||
Comments.allow({
|
||||
update: Users.can.editById,
|
||||
remove: Users.can.editById
|
||||
});
|
||||
update: _.partial(Telescope.allowCheck, Comments),
|
||||
remove: _.partial(Telescope.allowCheck, Comments)
|
||||
});
|
|
@ -3,7 +3,7 @@ var thumbnailProperty = {
|
|||
propertySchema: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"],
|
||||
editableBy: ["member", "admin"],
|
||||
autoform: {
|
||||
type: 'bootstrap-postthumbnail'
|
||||
}
|
||||
|
|
|
@ -26,8 +26,47 @@ Meteor.Collection.prototype.removeField = function (fieldName) {
|
|||
collection.attachSchema(schema, {replace: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an operation is allowed
|
||||
* @param {Object} collection – the collection to which the document belongs
|
||||
* @param {String} userId – the userId of the user performing the operation
|
||||
* @param {Object} document – the document being modified
|
||||
* @param {[String]} fieldNames – the names of the fields being modified
|
||||
* @param {Object} modifier – the modifier
|
||||
*/
|
||||
Telescope.allowCheck = function (collection, userId, document, fieldNames, modifier) {
|
||||
|
||||
var schema = collection.simpleSchema();
|
||||
var user = Meteor.users.findOne(userId);
|
||||
var allowedFields = schema.getEditableFields(user);
|
||||
|
||||
// allow update only if:
|
||||
// 1. user has rights to edit the document
|
||||
// 2. there is no fields in fieldNames that are not also in allowedFields
|
||||
return Users.can.edit(userId, document) && _.difference(fieldNames, allowedFields).length == 0;
|
||||
|
||||
}
|
||||
|
||||
// Note: using the prototype doesn't work in allow/deny for some reason
|
||||
Meteor.Collection.prototype.allowCheck = function (userId, document, fieldNames, modifier) {
|
||||
Telescope.allowCheck(this, userId, document, fieldNames, modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global schemas object. Note: not reactive, won't be updated after initialization
|
||||
* @namespace Telescope.schemas
|
||||
*/
|
||||
Telescope.schemas = {};
|
||||
Telescope.schemas = {};
|
||||
|
||||
/**
|
||||
* Get a list of all fields editable by a specific user for a given schema
|
||||
* @param {Object} user – the user for which to check field permissions
|
||||
*/
|
||||
SimpleSchema.prototype.getEditableFields = function (user) {
|
||||
var schema = this._schema;
|
||||
var fields = _.filter(_.keys(schema), function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
return Users.can.editField(user, field);
|
||||
});
|
||||
return fields;
|
||||
}
|
|
@ -1,12 +1,6 @@
|
|||
Template.post_edit.helpers({
|
||||
postFields: function () {
|
||||
var schema = Posts.simpleSchema()._schema;
|
||||
var post = this.post;
|
||||
var fields = _.filter(_.keys(schema), function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
return Users.can.editField(Meteor.user(), field, post);
|
||||
});
|
||||
return fields;
|
||||
return Posts.simpleSchema().getEditableFields(Meteor.user());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
Template.post_submit.helpers({
|
||||
postFields: function () {
|
||||
var schema = Posts.simpleSchema()._schema;
|
||||
var fields = _.filter(_.keys(schema), function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
return Users.can.submitField(Meteor.user(), field);
|
||||
});
|
||||
return fields;
|
||||
return Posts.simpleSchema().getEditableFields(Meteor.user());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Telescope.schemas.posts = new SimpleSchema({
|
|||
url: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"],
|
||||
editableBy: ["member", "admin"],
|
||||
autoform: {
|
||||
type: "bootstrap-url"
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ Telescope.schemas.posts = new SimpleSchema({
|
|||
title: {
|
||||
type: String,
|
||||
optional: false,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
},
|
||||
body: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"],
|
||||
editableBy: ["member", "admin"],
|
||||
autoform: {
|
||||
rows: 5
|
||||
}
|
||||
|
@ -160,7 +160,10 @@ Telescope.schemas.posts.internationalize();
|
|||
*/
|
||||
Posts.attachSchema(Telescope.schemas.posts);
|
||||
|
||||
|
||||
Posts.allow({
|
||||
update: _.partial(Telescope.allowCheck, Posts),
|
||||
remove: _.partial(Telescope.allowCheck, Posts)
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Collection Hooks //
|
||||
|
|
|
@ -4,7 +4,7 @@ Posts.registerField(
|
|||
propertySchema: {
|
||||
type: [String],
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"],
|
||||
editableBy: ["member", "admin"],
|
||||
autoform: {
|
||||
noselect: true,
|
||||
options: function () {
|
||||
|
|
|
@ -1,104 +1,11 @@
|
|||
<template name="userAccount">
|
||||
<div class="grid-small grid-module dialog user-edit">
|
||||
|
||||
{{#if profileIncomplete}}
|
||||
<div>{{_ "please_complete_your_profile_below_before_continuing"}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{> quickForm collection="Meteor.users" doc=user id="editUserForm" template="bootstrap3-horizontal" input-col-class="controls" type="update" fields=userFields}}
|
||||
|
||||
<!-- {{#if profileIncomplete}}
|
||||
<div>
|
||||
{{_ "please_complete_your_profile_below_before_continuing"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<form id="account-form">
|
||||
<h2>{{_ "account"}}</h2>
|
||||
<div class="control-group">
|
||||
<label>{{_ "username"}}</label>
|
||||
<div class="controls">
|
||||
<input id="username" name="username" disabled="disabled" type="text" value="{{userName}}" />
|
||||
</div>
|
||||
<p class="note">Profile URL: {{profileUrl}}</p>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "display_name"}}</label>
|
||||
<div class="controls">
|
||||
<input name="name" type="text" value="{{profile.username}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "email"}}</label>
|
||||
<div class="controls">
|
||||
<input name="email" type="text" value="{{userEmail}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "bio"}}</label>
|
||||
<div class="controls"><textarea name="bio" type="text">{{profile.bio}}</textarea></div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "city"}}</label>
|
||||
<div class="controls">
|
||||
<input name="city" type="text" value="{{profile.city}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "twitter_username"}}</label>
|
||||
<div class="controls">
|
||||
<input name="twitter" type="text" value="{{getTwitter}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "github_username"}}</label>
|
||||
<div class="controls">
|
||||
<input name="github" type="text" value="{{getGitHub}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "site_url"}}</label>
|
||||
<div class="controls">
|
||||
<input name="site" type="text" value="{{profile.site}}" />
|
||||
</div>
|
||||
</div>
|
||||
{{#if hasPassword}}
|
||||
<h3>{{_ "change_password"}}</h3>
|
||||
<div class="control-group">
|
||||
<label>{{_ "old_password"}}</label>
|
||||
<div class="controls"><input name="old_password" type="password" value="" /></div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{_ "new_password"}}</label>
|
||||
<div class="controls"><input name="new_password" type="password" value="" /></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{_ "email_notifications"}}</label>
|
||||
<div class="controls">
|
||||
{{#if isAdmin}}
|
||||
<label class="checkbox">
|
||||
<input id="notifications_users" type="checkbox" name="notifications_users" {{hasNotificationsUsers}} /> {{_ "new_users"}}
|
||||
</label>
|
||||
{{/if}}
|
||||
<label class="checkbox">
|
||||
<input id="notifications_posts" type="checkbox" name="notifications_posts" {{hasNotificationsPosts}} /> {{_ "new_posts"}}
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input id="notifications_comments" type="checkbox" name="notifications_comments" {{hasNotificationsComments}} /> {{_ "comments_on_my_posts"}}
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input id="notifications_replies" type="checkbox" name="notifications_replies" {{hasNotificationsReplies}} /> {{_ "replies_to_my_comments"}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{#if isAdmin}}
|
||||
<div class="control-group">
|
||||
<h3>Invites</h3>
|
||||
<label>Invites</label>
|
||||
<div class="controls">
|
||||
<input name="inviteCount" type="text" value="{{inviteCount}}" />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="form-actions">
|
||||
<a href="/forgot-password">{{_ "forgot_password"}}</a>
|
||||
<input type="submit" class="button btn btn-primary" value="{{_ "submit"}}" />
|
||||
</div>
|
||||
</form> -->
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -15,104 +15,74 @@ Template.userAccount.helpers({
|
|||
|
||||
// filter out uneditable fields and only keep "fieldName"
|
||||
var fields = _.pluck(_.filter(userDataSchema, function(field){
|
||||
return Users.can.editField(user, user, field);
|
||||
return Users.can.editField(user, field, user);
|
||||
}), "fieldName");
|
||||
|
||||
return fields;
|
||||
},
|
||||
profileIncomplete : function() {
|
||||
return this && !this.loading && !Users.userProfileComplete(this);
|
||||
},
|
||||
userName: function(){
|
||||
return Users.getUserName(this);
|
||||
},
|
||||
userEmail : function(){
|
||||
return Users.getEmail(this);
|
||||
},
|
||||
getTwitter: function(){
|
||||
return Users.getTwitterName(this) || "";
|
||||
},
|
||||
getGitHub: function(){
|
||||
return Users.getGitHubName(this) || "";
|
||||
},
|
||||
profileUrl: function(){
|
||||
return Users.getProfileUrlBySlugOrId(this.slug);
|
||||
},
|
||||
hasNotificationsUsers : function(){
|
||||
return Users.getUserSetting('notifications.users', '', this) ? 'checked' : '';
|
||||
},
|
||||
hasNotificationsPosts : function(){
|
||||
return Users.getUserSetting('notifications.posts', '', this) ? 'checked' : '';
|
||||
},
|
||||
hasNotificationsComments : function(){
|
||||
return Users.getUserSetting('notifications.comments', '', this) ? 'checked' : '';
|
||||
},
|
||||
hasNotificationsReplies : function(){
|
||||
return Users.getUserSetting('notifications.replies', '', this) ? 'checked' : '';
|
||||
},
|
||||
hasPassword: function () {
|
||||
return Users.hasPassword(Meteor.user());
|
||||
}
|
||||
});
|
||||
|
||||
Template.userAccount.events({
|
||||
'submit #account-form': function(e){
|
||||
e.preventDefault();
|
||||
// Template.userAccount.events({
|
||||
// 'submit #account-form': function(e){
|
||||
// e.preventDefault();
|
||||
|
||||
Messages.clearSeen();
|
||||
if(!Meteor.user())
|
||||
Messages.flash(i18n.t('you_must_be_logged_in'), 'error');
|
||||
// Messages.clearSeen();
|
||||
// if(!Meteor.user())
|
||||
// Messages.flash(i18n.t('you_must_be_logged_in'), 'error');
|
||||
|
||||
var $target=$(e.target);
|
||||
var name = $target.find('[name=name]').val();
|
||||
var email = $target.find('[name=email]').val();
|
||||
var user = this;
|
||||
var update = {
|
||||
"profile.username": name,
|
||||
"profile.slug": Telescope.utils.slugify(name),
|
||||
"profile.bio": $target.find('[name=bio]').val(),
|
||||
"profile.city": $target.find('[name=city]').val(),
|
||||
"profile.email": email,
|
||||
"profile.twitter": $target.find('[name=twitter]').val(),
|
||||
"profile.github": $target.find('[name=github]').val(),
|
||||
"profile.site": $target.find('[name=site]').val(),
|
||||
"profile.notifications.users": $('input[name=notifications_users]:checked').length, // only actually used for admins
|
||||
"profile.notifications.posts": $('input[name=notifications_posts]:checked').length,
|
||||
"profile.notifications.comments": $('input[name=notifications_comments]:checked').length,
|
||||
"profile.notifications.replies": $('input[name=notifications_replies]:checked').length
|
||||
};
|
||||
// var $target=$(e.target);
|
||||
// var name = $target.find('[name=name]').val();
|
||||
// var email = $target.find('[name=email]').val();
|
||||
// var user = this;
|
||||
// var update = {
|
||||
// "profile.username": name,
|
||||
// "profile.slug": Telescope.utils.slugify(name),
|
||||
// "profile.bio": $target.find('[name=bio]').val(),
|
||||
// "profile.city": $target.find('[name=city]').val(),
|
||||
// "profile.email": email,
|
||||
// "profile.twitter": $target.find('[name=twitter]').val(),
|
||||
// "profile.github": $target.find('[name=github]').val(),
|
||||
// "profile.site": $target.find('[name=site]').val(),
|
||||
// "profile.notifications.users": $('input[name=notifications_users]:checked').length, // only actually used for admins
|
||||
// "profile.notifications.posts": $('input[name=notifications_posts]:checked').length,
|
||||
// "profile.notifications.comments": $('input[name=notifications_comments]:checked').length,
|
||||
// "profile.notifications.replies": $('input[name=notifications_replies]:checked').length
|
||||
// };
|
||||
|
||||
var old_password = $target.find('[name=old_password]').val();
|
||||
var new_password = $target.find('[name=new_password]').val();
|
||||
// var old_password = $target.find('[name=old_password]').val();
|
||||
// var new_password = $target.find('[name=new_password]').val();
|
||||
|
||||
if(old_password && new_password){
|
||||
Accounts.changePassword(old_password, new_password, function(error){
|
||||
// TODO: interrupt update if there's an error at this point
|
||||
if(error)
|
||||
Messages.flash(error.reason, "error");
|
||||
});
|
||||
}
|
||||
// if(old_password && new_password){
|
||||
// Accounts.changePassword(old_password, new_password, function(error){
|
||||
// // TODO: interrupt update if there's an error at this point
|
||||
// if(error)
|
||||
// Messages.flash(error.reason, "error");
|
||||
// });
|
||||
// }
|
||||
|
||||
update = Users.hooks.userEditClientCallbacks.reduce(function(result, currentFunction) {
|
||||
return currentFunction(user, result);
|
||||
}, update);
|
||||
// update = Users.hooks.userEditClientCallbacks.reduce(function(result, currentFunction) {
|
||||
// return currentFunction(user, result);
|
||||
// }, update);
|
||||
|
||||
Meteor.users.update(user._id, {
|
||||
$set: update
|
||||
}, function(error){
|
||||
if(error){
|
||||
Messages.flash(error.reason, "error");
|
||||
} else {
|
||||
Messages.flash(i18n.t('profile_updated'), 'success');
|
||||
}
|
||||
Deps.afterFlush(function() {
|
||||
var element = $('.grid > .error');
|
||||
$('html, body').animate({scrollTop: element.offset().top});
|
||||
});
|
||||
});
|
||||
// Meteor.users.update(user._id, {
|
||||
// $set: update
|
||||
// }, function(error){
|
||||
// if(error){
|
||||
// Messages.flash(error.reason, "error");
|
||||
// } else {
|
||||
// Messages.flash(i18n.t('profile_updated'), 'success');
|
||||
// }
|
||||
// Deps.afterFlush(function() {
|
||||
// var element = $('.grid > .error');
|
||||
// $('html, body').animate({scrollTop: element.offset().top});
|
||||
// });
|
||||
// });
|
||||
|
||||
Meteor.call('changeEmail', user._id, email);
|
||||
// Meteor.call('changeEmail', user._id, email);
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
});
|
||||
// });
|
||||
|
|
|
@ -2,4 +2,18 @@
|
|||
* Telescope Users namespace
|
||||
* @namespace Users
|
||||
*/
|
||||
Users = Meteor.users;
|
||||
Users = Meteor.users;
|
||||
|
||||
Users.getUser = function (userOrUserId) {
|
||||
if (typeof userOrUserId === "undefined") {
|
||||
if (!Meteor.user()) {
|
||||
throw new Error();
|
||||
} else {
|
||||
return Meteor.user();
|
||||
}
|
||||
} else if (typeof userOrUserId === "string") {
|
||||
return Meteor.users.findOne(userOrUserId);
|
||||
} else {
|
||||
return userOrUserId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,14 @@ Users.can.view = function (user) {
|
|||
return true;
|
||||
};
|
||||
|
||||
Users.can.viewById = function (userId) {
|
||||
// if an invite is required to view, run permission check, else return true
|
||||
if (Settings.get('requireViewInvite', false)) {
|
||||
return !!userId ? Users.can.view(Meteor.users.findOne(userId)) : false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Users.can.viewPendingPosts = function (user) {
|
||||
user = (typeof user === 'undefined') ? Meteor.user() : user;
|
||||
return Users.is.admin(user);
|
||||
|
@ -31,13 +39,6 @@ Users.can.viewRejectedPosts = function (user) {
|
|||
return Users.is.admin(user);
|
||||
};
|
||||
|
||||
Users.can.viewById = function (userId) {
|
||||
// if an invite is required to view, run permission check, else return true
|
||||
if (Settings.get('requireViewInvite', false)) {
|
||||
return !!userId ? Users.can.view(Meteor.users.findOne(userId)) : false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Users.can.post = function (user, returnError) {
|
||||
user = (typeof user === 'undefined') ? Meteor.user() : user;
|
||||
|
@ -65,16 +66,27 @@ Users.can.vote = function (user, returnError) {
|
|||
return Users.can.post(user, returnError);
|
||||
};
|
||||
|
||||
Users.can.edit = function (user, item, returnError) {
|
||||
/**
|
||||
* Check if a user can edit a document
|
||||
* @param {Object} user - The user performing the action
|
||||
* @param {Object} document - The document being edited
|
||||
*/
|
||||
Users.can.edit = function (user, document) {
|
||||
user = (typeof user === 'undefined') ? Meteor.user() : user;
|
||||
|
||||
if (!user || !item || (user._id !== item.userId &&
|
||||
user._id !== item._id &&
|
||||
!Users.is.admin(user))) {
|
||||
return returnError ? "no_rights" : false;
|
||||
} else {
|
||||
return true;
|
||||
if (!user || !document) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var adminCheck = Users.is.admin(user);
|
||||
var ownerCheck = Users.is.owner(user, document);
|
||||
|
||||
return adminCheck || ownerCheck;
|
||||
};
|
||||
|
||||
Users.can.editById = function (userId, document) {
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return Users.can.edit(user, document);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -88,37 +100,19 @@ Users.can.submitField = function (user, field) {
|
|||
return false;
|
||||
}
|
||||
|
||||
var adminCheck = _.contains(field.editableBy, "admin") && Users.is.admin(user);
|
||||
var ownerCheck = _.contains(field.editableBy, "owner");
|
||||
var adminCheck = _.contains(field.editableBy, "admin") && Users.is.admin(user); // is the field editable by admins?
|
||||
var memberCheck = _.contains(field.editableBy, "member"); // is the field editable by regular users?
|
||||
|
||||
return adminCheck || ownerCheck;
|
||||
return adminCheck || memberCheck;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user can edit a field on a specific document
|
||||
* Check if a user can edit a field – for now, identical to Users.can.submitField
|
||||
* @param {Object} user - The user performing the action
|
||||
* @param {Object} field - The field being edited or inserted
|
||||
* @param {Object} document - The document being modified
|
||||
*/
|
||||
Users.can.editField = function (user, field, document) {
|
||||
|
||||
if (!field.editableBy || !user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var adminCheck = _.contains(field.editableBy, "admin") && Users.is.admin(user);
|
||||
var ownerCheck = _.contains(field.editableBy, "owner") && Users.is.owner(user, document);
|
||||
|
||||
return adminCheck || ownerCheck;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Users.can.editById = function (userId, item) {
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return Users.can.edit(user, item);
|
||||
};
|
||||
Users.can.editField = Users.can.submitField
|
||||
|
||||
Users.can.currentUserEdit = function (item) {
|
||||
return Users.can.edit(Meteor.user(), item);
|
||||
|
|
|
@ -4,23 +4,13 @@
|
|||
*/
|
||||
Users.is = {};
|
||||
|
||||
getUser = function (userOrUserId) {
|
||||
if (typeof userOrUserId === "undefined") {
|
||||
if (!Meteor.user()) {
|
||||
throw new Error();
|
||||
} else {
|
||||
return Meteor.user();
|
||||
}
|
||||
} else if (typeof userOrUserId === "string") {
|
||||
return Meteor.users.findOne(userOrUserId);
|
||||
} else {
|
||||
return userOrUserId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is an admin
|
||||
* @param {Object|string} userOrUserId - The user or their userId
|
||||
*/
|
||||
Users.is.admin = function (userOrUserId) {
|
||||
try {
|
||||
var user = getUser(userOrUserId);
|
||||
var user = Users.getUser(userOrUserId);
|
||||
return !!user && !!user.isAdmin;
|
||||
} catch (e) {
|
||||
return false; // user not logged in
|
||||
|
@ -28,19 +18,31 @@ Users.is.admin = function (userOrUserId) {
|
|||
};
|
||||
Users.is.adminById = Users.is.admin;
|
||||
|
||||
/**
|
||||
* Check if a user owns a document
|
||||
* @param {Object|string} userOrUserId - The user or their userId
|
||||
* @param {Object} document - The document to check (post, comment, user object, etc.)
|
||||
*/
|
||||
Users.is.owner = function (userOrUserId, document) {
|
||||
try {
|
||||
var user = getUser(userOrUserId);
|
||||
return user._id === document.userId;
|
||||
var user = Users.getUser(userOrUserId);
|
||||
if (!!document.userId) {
|
||||
// case 1: document is a post or a comment, use userId to check
|
||||
return user._id === document.userId;
|
||||
} else {
|
||||
// case 2: document is a user, use _id to check
|
||||
return user._id === document._id;
|
||||
}
|
||||
} catch (e) {
|
||||
return false; // user not logged in
|
||||
}
|
||||
};
|
||||
|
||||
Users.is.ownerById = Users.is.owner;
|
||||
|
||||
Users.is.invited = function (userOrUserId) {
|
||||
try {
|
||||
var user = getUser(userOrUserId);
|
||||
var user = Users.getUser(userOrUserId);
|
||||
return Users.is.admin(user) || Users.is.invited(user);
|
||||
} catch (e) {
|
||||
return false; // user not logged in
|
||||
|
|
|
@ -24,7 +24,7 @@ Telescope.schemas.userData = new SimpleSchema({
|
|||
bio: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
},
|
||||
commentCount: {
|
||||
type: Number,
|
||||
|
@ -34,7 +34,7 @@ Telescope.schemas.userData = new SimpleSchema({
|
|||
type: String,
|
||||
regEx: /^[a-zA-Z-]{2,25}$/,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
},
|
||||
downvotedComments: {
|
||||
type: [Telescope.schemas.votes],
|
||||
|
@ -48,7 +48,7 @@ Telescope.schemas.userData = new SimpleSchema({
|
|||
type: String,
|
||||
regEx: /^[a-zA-Z]{2,25}$/,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
},
|
||||
emailHash: {
|
||||
type: String,
|
||||
|
@ -85,7 +85,7 @@ Telescope.schemas.userData = new SimpleSchema({
|
|||
twitterUsername: {
|
||||
type: String,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
},
|
||||
upvotedComments: {
|
||||
type: [Telescope.schemas.votes],
|
||||
|
@ -99,7 +99,7 @@ Telescope.schemas.userData = new SimpleSchema({
|
|||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Url,
|
||||
optional: true,
|
||||
editableBy: ["owner", "admin"]
|
||||
editableBy: ["member", "admin"]
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -156,24 +156,11 @@ Telescope.schemas.users.internationalize();
|
|||
*/
|
||||
Meteor.users.attachSchema(Telescope.schemas.users);
|
||||
|
||||
|
||||
/**
|
||||
* Users collection permissions
|
||||
*/
|
||||
Users.deny({
|
||||
update: function(userId, post, fieldNames) {
|
||||
if(Users.is.adminById(userId))
|
||||
return false;
|
||||
// deny the update if it contains something other than the profile field
|
||||
return (_.without(fieldNames, 'profile', 'username', 'slug').length > 0);
|
||||
}
|
||||
});
|
||||
|
||||
Users.allow({
|
||||
update: function(userId, doc){
|
||||
return Users.is.adminById(userId) || userId == doc._id;
|
||||
},
|
||||
remove: function(userId, doc){
|
||||
return Users.is.adminById(userId) || userId == doc._id;
|
||||
}
|
||||
});
|
||||
update: _.partial(Telescope.allowCheck, Meteor.users),
|
||||
remove: _.partial(Telescope.allowCheck, Meteor.users)
|
||||
});
|
Loading…
Add table
Reference in a new issue