using smart publications and smart methods

This commit is contained in:
Sacha Greif 2016-02-28 13:12:36 +09:00
parent 3f8c5a81af
commit 14b5af4b41
30 changed files with 200 additions and 170 deletions

View file

@ -112,11 +112,6 @@ oauth2@1.1.6-beta.11
observe-sequence@1.0.8-beta.11 observe-sequence@1.0.8-beta.11
ongoworks:speakingurl@9.0.0 ongoworks:speakingurl@9.0.0
ordered-dict@1.0.4 ordered-dict@1.0.4
peerlibrary:assert@0.2.5
peerlibrary:fiber-utils@0.6.0
peerlibrary:reactive-mongo@0.1.1
peerlibrary:reactive-publish@0.2.0
peerlibrary:server-autorun@0.5.2
percolatestudio:synced-cron@1.1.0 percolatestudio:synced-cron@1.1.0
promise@0.5.2-beta.11 promise@0.5.2-beta.11
raix:eventemitter@0.1.3 raix:eventemitter@0.1.3
@ -150,7 +145,7 @@ underscore@1.0.5-beta.11
url@1.0.6-beta.11 url@1.0.6-beta.11
utilities:react-list-container@0.1.0 utilities:react-list-container@0.1.0
utilities:smart-methods@0.0.2 utilities:smart-methods@0.0.2
utilities:smart-publications@0.1.0 utilities:smart-publications@0.1.1
webapp@1.2.5-beta.11 webapp@1.2.5-beta.11
webapp-hashing@1.0.6-beta.11 webapp-hashing@1.0.6-beta.11
zimme:active-route@2.3.2 zimme:active-route@2.3.2

View file

@ -4,7 +4,8 @@ Posts.addField([
fieldSchema: { fieldSchema: {
type: String, type: String,
optional: true, optional: true,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
type: 'bootstrap-postthumbnail', type: 'bootstrap-postthumbnail',
order: 40 order: 40

View file

@ -48,9 +48,10 @@ Users.addField([
fieldName: "telescope.isInvited", fieldName: "telescope.isInvited",
fieldSchema: { fieldSchema: {
type: Boolean, type: Boolean,
public: true, publish: true,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
autoform: { autoform: {
omit: true omit: true
} }

View file

@ -4,12 +4,14 @@ Feeds.schema = new SimpleSchema({
url: { url: {
type: String, type: String,
regEx: SimpleSchema.RegEx.Url, regEx: SimpleSchema.RegEx.Url,
editableBy: ["admin"] insertableIf: Users.is.admin,
editableIf: Users.is.admin
}, },
userId: { userId: {
type: String, type: String,
label: 'feedUser', label: 'feedUser',
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
autoform: { autoform: {
instructions: 'Posts will be assigned to this user.', instructions: 'Posts will be assigned to this user.',
options: function () { options: function () {
@ -27,7 +29,8 @@ Feeds.schema = new SimpleSchema({
type: [String], type: [String],
label: 'categories', label: 'categories',
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
autoform: { autoform: {
instructions: 'Posts will be assigned to this category.', instructions: 'Posts will be assigned to this category.',
noselect: true, noselect: true,

View file

@ -50,7 +50,7 @@ Posts.addField([
type: Number, type: Number,
decimal: true, decimal: true,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -62,7 +62,7 @@ Posts.addField([
type: Number, type: Number,
decimal: true, decimal: true,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
]); ]);
@ -81,7 +81,7 @@ Comments.addField([
fieldSchema: { fieldSchema: {
type: Number, type: Number,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -92,7 +92,7 @@ Comments.addField([
fieldSchema: { fieldSchema: {
type: [String], type: [String],
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -103,7 +103,7 @@ Comments.addField([
fieldSchema: { fieldSchema: {
type: Number, type: Number,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -114,7 +114,7 @@ Comments.addField([
fieldSchema: { fieldSchema: {
type: [String], type: [String],
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -126,7 +126,7 @@ Comments.addField([
type: Number, type: Number,
decimal: true, decimal: true,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
/** /**
@ -138,7 +138,7 @@ Comments.addField([
type: Number, type: Number,
decimal: true, decimal: true,
optional: true, optional: true,
public: true, publish: true,
} }
}, },
]); ]);

View file

@ -46,7 +46,7 @@ const UsersEdit = React.createClass({
({CanEditUser} = Telescope.components); ({CanEditUser} = Telescope.components);
const fields = Meteor.users.simpleSchema().getEditableFields(this.props.currentUser); const fields = Users.getInsertableFields(this.props.currentUser);
return ( return (
<CanEditUser user={this.props.currentUser} userToEdit={user}> <CanEditUser user={this.props.currentUser} userToEdit={user}>

View file

@ -4,14 +4,16 @@ Categories = new Mongo.Collection("categories");
Categories.schema = new SimpleSchema({ Categories.schema = new SimpleSchema({
name: { name: {
type: String, type: String,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true editableIf: Users.is.admin,
publish: true
}, },
description: { description: {
type: String, type: String,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true, editableIf: Users.is.admin,
publish: true,
autoform: { autoform: {
rows: 3 rows: 3
} }
@ -19,26 +21,30 @@ Categories.schema = new SimpleSchema({
order: { order: {
type: Number, type: Number,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true editableIf: Users.is.admin,
publish: true
}, },
slug: { slug: {
type: String, type: String,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true editableIf: Users.is.admin,
publish: true
}, },
image: { image: {
type: String, type: String,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true editableIf: Users.is.admin,
publish: true
}, },
parentId: { parentId: {
type: String, type: String,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true, editableIf: Users.is.admin,
publish: true,
autoform: { autoform: {
options: function () { options: function () {
var categories = Categories.find().map(function (category) { var categories = Categories.find().map(function (category) {

View file

@ -7,7 +7,8 @@ Posts.addField(
type: [String], type: [String],
control: "checkboxgroup", control: "checkboxgroup",
optional: true, optional: true,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
noselect: true, noselect: true,
type: "bootstrap-category", type: "bootstrap-category",

View file

@ -11,7 +11,8 @@ Package.onUse(function (api) {
api.use([ api.use([
'nova:core@0.25.7', 'nova:core@0.25.7',
'nova:posts@0.25.7' 'nova:posts@0.25.7',
'nova:users@0.25.7'
]); ]);
api.addFiles([ api.addFiles([

View file

@ -1,6 +1,6 @@
Template.comment_edit.helpers({ Template.comment_edit.helpers({
commentFields: function () { commentFields: function () {
return Comments.simpleSchema().getEditableFields(Meteor.user()); return Comments.getInsertableFields(Meteor.user());
} }
}); });

View file

@ -1,6 +1,6 @@
Template.comment_submit.helpers({ Template.comment_submit.helpers({
commentFields: function () { commentFields: function () {
return Comments.simpleSchema().getEditableFields(Meteor.user()); return Comments.getInsertableFields(Meteor.user());
}, },
isLoggedIn: function () { isLoggedIn: function () {
return !!Meteor.user(); return !!Meteor.user();

View file

@ -15,7 +15,7 @@ Comments.schema = new SimpleSchema({
_id: { _id: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The `_id` of the parent comment, if there is one The `_id` of the parent comment, if there is one
@ -24,9 +24,10 @@ Comments.schema = new SimpleSchema({
type: String, type: String,
// regEx: SimpleSchema.RegEx.Id, // regEx: SimpleSchema.RegEx.Id,
max: 500, max: 500,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
optional: true, optional: true,
public: true, publish: true,
autoform: { autoform: {
omit: true // never show this omit: true // never show this
} }
@ -38,9 +39,10 @@ Comments.schema = new SimpleSchema({
type: String, type: String,
// regEx: SimpleSchema.RegEx.Id, // regEx: SimpleSchema.RegEx.Id,
max: 500, max: 500,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
optional: true, optional: true,
public: true, publish: true,
autoform: { autoform: {
omit: true // never show this omit: true // never show this
} }
@ -51,7 +53,7 @@ Comments.schema = new SimpleSchema({
createdAt: { createdAt: {
type: Date, type: Date,
optional: true, optional: true,
public: false, publish: false
}, },
/** /**
The timestamp of the comment being posted. For now, comments are always created and posted at the same time The timestamp of the comment being posted. For now, comments are always created and posted at the same time
@ -59,7 +61,7 @@ Comments.schema = new SimpleSchema({
postedAt: { postedAt: {
type: Date, type: Date,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The comment body (Markdown) The comment body (Markdown)
@ -67,8 +69,9 @@ Comments.schema = new SimpleSchema({
body: { body: {
type: String, type: String,
max: 3000, max: 3000,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
public: true, editableIf: Users.is.ownerOrAdmin,
publish: true,
autoform: { autoform: {
rows: 5, rows: 5,
afFormGroup: { afFormGroup: {
@ -82,7 +85,7 @@ Comments.schema = new SimpleSchema({
htmlBody: { htmlBody: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The comment author's name The comment author's name
@ -90,7 +93,7 @@ Comments.schema = new SimpleSchema({
author: { author: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Whether the comment is inactive. Inactive comments' scores gets recalculated less often Whether the comment is inactive. Inactive comments' scores gets recalculated less often
@ -98,7 +101,7 @@ Comments.schema = new SimpleSchema({
inactive: { inactive: {
type: Boolean, type: Boolean,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The post's `_id` The post's `_id`
@ -106,10 +109,10 @@ Comments.schema = new SimpleSchema({
postId: { postId: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
// regEx: SimpleSchema.RegEx.Id, // regEx: SimpleSchema.RegEx.Id,
max: 500, max: 500,
// editableBy: ["member", "admin"], // TODO: should users be able to set postId, but not modify it? // editableIf: Users.is.ownerOrAdmin, // TODO: should users be able to set postId, but not modify it?
autoform: { autoform: {
omit: true // never show this omit: true // never show this
} }
@ -120,7 +123,7 @@ Comments.schema = new SimpleSchema({
userId: { userId: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Whether the comment is deleted. Delete comments' content doesn't appear on the site. Whether the comment is deleted. Delete comments' content doesn't appear on the site.
@ -128,7 +131,7 @@ Comments.schema = new SimpleSchema({
isDeleted: { isDeleted: {
type: Boolean, type: Boolean,
optional: true, optional: true,
public: true, publish: true,
} }
}); });

View file

@ -9,7 +9,7 @@ Posts.addField([
fieldSchema: { fieldSchema: {
type: Number, type: Number,
optional: true, optional: true,
public: true publish: true
} }
}, },
/** /**
@ -20,7 +20,7 @@ Posts.addField([
fieldSchema: { fieldSchema: {
type: [String], type: [String],
optional: true, optional: true,
public: true, publish: true,
join: { join: {
joinAs: "commentersArray", joinAs: "commentersArray",
collection: () => Users, collection: () => Users,

View file

@ -46,7 +46,7 @@ const EditDocContainer = React.createClass({
const document = this.props.document; const document = this.props.document;
const collection = this.props.collection; const collection = this.props.collection;
const fields = collection.simpleSchema().getEditableFields(this.data.currentUser); const fields = collection.getInsertableFields(this.data.currentUser);
return ( return (
<div className="document-edit"> <div className="document-edit">

View file

@ -42,7 +42,7 @@ const NewDocContainer = React.createClass({
render() { render() {
const collection = this.props.collection; const collection = this.props.collection;
const fields = collection.simpleSchema().getEditableFields(this.data.currentUser); const fields = collection.getInsertableFields(this.data.currentUser);
return ( return (
<div className="new-document"> <div className="new-document">

View file

@ -17,17 +17,16 @@ FlowRouter.route('/demo', {
Movies = new Mongo.Collection("movies"); Movies = new Mongo.Collection("movies");
const hasUserId = userId => !!userId; const isLoggedIn = user => !!user;
const isOwner = (userId, document) => userId === document.userId; const isOwner = (user, document) => {user._id === document.userId};
const schema = new SimpleSchema({ const schema = new SimpleSchema({
name: { name: {
type: String, type: String,
publish: true, publish: true,
control: "text", control: "text",
createIf: hasUserId, insertableIf: isLoggedIn,
editIf: isOwner, editableIf: isOwner
editableBy: ["member", "admin"]
}, },
createdAt: { createdAt: {
type: Date, type: Date,
@ -38,21 +37,19 @@ const schema = new SimpleSchema({
publish: true, publish: true,
optional: true, optional: true,
control: "text", control: "text",
createIf: hasUserId, insertableIf: isLoggedIn,
editIf: isOwner, editableIf: isOwner
editableBy: ["member", "admin"]
}, },
review: { review: {
type: String, type: String,
publish: true, publish: true,
control: "textarea", control: "textarea",
createIf: hasUserId, insertableIf: isLoggedIn,
editIf: isOwner, editableIf: isOwner
editableBy: ["member", "admin"]
}, },
userId: { userId: {
type: String, type: String,
publish: true, publish: user => Users.is.admin(user),
join: { join: {
collection: () => Meteor.users, collection: () => Meteor.users,
joinAs: "user", joinAs: "user",
@ -67,15 +64,15 @@ Movies.attachSchema(schema);
// Methods // // Methods //
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
Movies.initMethods({ Movies.smartMethods({
deleteIf: isOwner,
createCallback: function (document) { createCallback: function (document) {
document = _.extend(document, { document = _.extend(document, {
createdAt: new Date(), createdAt: new Date(),
userId: Meteor.userId() userId: Meteor.userId()
}); });
return document; return document;
} },
deleteCallback: isOwner
}); });
////////////////////////////////////////////////////// //////////////////////////////////////////////////////

View file

@ -48,7 +48,7 @@ Telescope.allowCheck = function (collection, userId, document, fieldNames, modif
var schema = collection.simpleSchema(); var schema = collection.simpleSchema();
var user = Meteor.users.findOne(userId); var user = Meteor.users.findOne(userId);
var allowedFields = schema.getEditableFields(user); var allowedFields = collection.getInsertableFields(user);
var fields = []; var fields = [];
// fieldNames only contains top-level fields, so loop over modifier to get real list of fields // fieldNames only contains top-level fields, so loop over modifier to get real list of fields
@ -75,23 +75,6 @@ Meteor.Collection.prototype.allowCheck = function (userId, document, fieldNames,
*/ */
Telescope.schemas = {}; Telescope.schemas = {};
/**
* @method SimpleSchema.getEditableFields
* 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 = _.sortBy(_.filter(_.keys(schema), function (fieldName) {
var field = schema[fieldName];
return Users.can.editField(user, field);
}), function (fieldName) {
var field = schema[fieldName];
return field.autoform && field.autoform.order;
});
return fields;
};
SimpleSchema.prototype.getProfileFields = function () { SimpleSchema.prototype.getProfileFields = function () {
var schema = this._schema; var schema = this._schema;
var fields = _.filter(_.keys(schema), function (fieldName) { var fields = _.filter(_.keys(schema), function (fieldName) {

View file

@ -21,15 +21,11 @@ SimpleSchema.extendOptions({
private: Match.Optional(Boolean), private: Match.Optional(Boolean),
editable: Match.Optional(Boolean), // editable: true means the field can be edited by the document's owner editable: Match.Optional(Boolean), // editable: true means the field can be edited by the document's owner
hidden: Match.Optional(Boolean), // hidden: true means the field is never shown in a form no matter what hidden: Match.Optional(Boolean), // hidden: true means the field is never shown in a form no matter what
editableBy: Match.Optional([String]),
publishedTo: Match.Optional([String]),
required: Match.Optional(Boolean), // required: true means the field is required to have a complete profile required: Match.Optional(Boolean), // required: true means the field is required to have a complete profile
public: Match.Optional(Boolean), // public: true means the field is published freely
profile: Match.Optional(Boolean), // profile: true means the field is shown on user profiles profile: Match.Optional(Boolean), // profile: true means the field is shown on user profiles
template: Match.Optional(String), // template used to display the field template: Match.Optional(String), // template used to display the field
autoform: Match.Optional(Object), // autoform placeholder autoform: Match.Optional(Object), // autoform placeholder
control: Match.Optional(String), // autoform placeholder control: Match.Optional(String), // autoform placeholder
join: Match.Optional(Object) // autoform placeholder
// editableBy: Match.Optional(String) // editableBy: Match.Optional(String)
}); });

View file

@ -72,6 +72,7 @@ Package.onUse(function (api) {
// 'peerlibrary:reactive-publish@0.2.0', // 'peerlibrary:reactive-publish@0.2.0',
'utilities:smart-publications', 'utilities:smart-publications',
'utilities:smart-methods',
'ecmascript', 'ecmascript',
'react', 'react',

View file

@ -17,7 +17,8 @@ Users.addField([
label: 'Show banner', label: 'Show banner',
type: Boolean, type: Boolean,
optional: true, optional: true,
editableBy: ['admin', 'member'], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
omit: true omit: true
} }
@ -29,7 +30,8 @@ Users.addField([
label: 'Subscribe to newsletter', label: 'Subscribe to newsletter',
type: Boolean, type: Boolean,
optional: true, optional: true,
editableBy: ['admin', 'member'], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
omit: true omit: true
} }

View file

@ -28,7 +28,7 @@ Template.post_edit.helpers({
return Posts.findOne(FlowRouter.getParam("_id")); return Posts.findOne(FlowRouter.getParam("_id"));
}, },
postFields: function () { postFields: function () {
return Posts.simpleSchema().getEditableFields(Meteor.user()); return Posts.getInsertableFields(Meteor.user());
} }
}); });

View file

@ -4,7 +4,7 @@ Template.post_submit.onCreated(function () {
Template.post_submit.helpers({ Template.post_submit.helpers({
postFields: function () { postFields: function () {
return Posts.simpleSchema().getEditableFields(Meteor.user()); return Posts.getInsertableFields(Meteor.user());
} }
}); });

View file

@ -9,7 +9,7 @@ Posts.schema = new SimpleSchema({
_id: { _id: {
type: String, type: String,
optional: true, optional: true,
public: true publish: true
}, },
/** /**
Timetstamp of post creation Timetstamp of post creation
@ -17,7 +17,7 @@ Posts.schema = new SimpleSchema({
createdAt: { createdAt: {
type: Date, type: Date,
optional: true, optional: true,
public: false publish: false
}, },
/** /**
Timestamp of post first appearing on the site (i.e. being approved) Timestamp of post first appearing on the site (i.e. being approved)
@ -25,8 +25,9 @@ Posts.schema = new SimpleSchema({
postedAt: { postedAt: {
type: Date, type: Date,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
public: true, editableIf: Users.is.admin,
publish: true,
control: "datepicker", control: "datepicker",
autoform: { autoform: {
group: 'admin', group: 'admin',
@ -40,9 +41,10 @@ Posts.schema = new SimpleSchema({
type: String, type: String,
optional: true, optional: true,
max: 500, max: 500,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
control: "text", control: "text",
public: true, publish: true,
autoform: { autoform: {
type: "bootstrap-url", type: "bootstrap-url",
order: 10 order: 10
@ -55,9 +57,10 @@ Posts.schema = new SimpleSchema({
type: String, type: String,
optional: false, optional: false,
max: 500, max: 500,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
control: "text", control: "text",
public: true, publish: true,
autoform: { autoform: {
order: 20 order: 20
} }
@ -68,7 +71,7 @@ Posts.schema = new SimpleSchema({
slug: { slug: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Post body (markdown) Post body (markdown)
@ -77,9 +80,10 @@ Posts.schema = new SimpleSchema({
type: String, type: String,
optional: true, optional: true,
max: 3000, max: 3000,
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
control: "textarea", control: "textarea",
public: true, publish: true,
autoform: { autoform: {
rows: 5, rows: 5,
order: 30 order: 30
@ -91,7 +95,7 @@ Posts.schema = new SimpleSchema({
htmlBody: { htmlBody: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Count of how many times the post's page was viewed Count of how many times the post's page was viewed
@ -99,7 +103,7 @@ Posts.schema = new SimpleSchema({
viewCount: { viewCount: {
type: Number, type: Number,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Timestamp of the last comment Timestamp of the last comment
@ -107,7 +111,7 @@ Posts.schema = new SimpleSchema({
lastCommentedAt: { lastCommentedAt: {
type: Date, type: Date,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
Count of how many times the post's link was clicked Count of how many times the post's link was clicked
@ -115,7 +119,7 @@ Posts.schema = new SimpleSchema({
clickCount: { clickCount: {
type: Number, type: Number,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The post's status. One of pending (`1`), approved (`2`), or deleted (`3`) The post's status. One of pending (`1`), approved (`2`), or deleted (`3`)
@ -123,9 +127,10 @@ Posts.schema = new SimpleSchema({
status: { status: {
type: Number, type: Number,
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
control: "select", control: "select",
public: true, publish: true,
autoValue: function () { autoValue: function () {
// only provide a default value // only provide a default value
// 1) this is an insert operation // 1) this is an insert operation
@ -147,9 +152,10 @@ Posts.schema = new SimpleSchema({
type: Boolean, type: Boolean,
optional: true, optional: true,
defaultValue: false, defaultValue: false,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
control: "checkbox", control: "checkbox",
public: true, publish: true,
autoform: { autoform: {
group: 'admin', group: 'admin',
leftLabel: "Sticky" leftLabel: "Sticky"
@ -161,7 +167,7 @@ Posts.schema = new SimpleSchema({
inactive: { inactive: {
type: Boolean, type: Boolean,
optional: true, optional: true,
public: false, publish: false
}, },
/** /**
Save info for later spam checking on a post. We will use this for the akismet package Save info for later spam checking on a post. We will use this for the akismet package
@ -169,17 +175,17 @@ Posts.schema = new SimpleSchema({
userIP: { userIP: {
type: String, type: String,
optional: true, optional: true,
public: false, publish: false
}, },
userAgent: { userAgent: {
type: String, type: String,
optional: true, optional: true,
public: false, publish: false
}, },
referrer: { referrer: {
type: String, type: String,
optional: true, optional: true,
public: false, publish: false
}, },
/** /**
The post author's name The post author's name
@ -187,7 +193,7 @@ Posts.schema = new SimpleSchema({
author: { author: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
}, },
/** /**
The post author's `_id`. The post author's `_id`.
@ -196,9 +202,10 @@ Posts.schema = new SimpleSchema({
type: String, type: String,
optional: true, optional: true,
// regEx: SimpleSchema.RegEx.Id, // regEx: SimpleSchema.RegEx.Id,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
control: "select", control: "select",
public: true, publish: true,
autoform: { autoform: {
group: 'admin', group: 'admin',
options: function () { options: function () {

View file

@ -17,7 +17,7 @@ Package.onUse(function (api) {
'nova:core@0.25.7', 'nova:core@0.25.7',
// 'nova:i18n@0.25.7', // 'nova:i18n@0.25.7',
// 'nova:settings@0.25.7', // 'nova:settings@0.25.7',
// 'nova:users@0.25.7', 'nova:users@0.25.7',
// 'nova:comments@0.25.7' // 'nova:comments@0.25.7'
]); ]);

View file

@ -3,7 +3,7 @@ Template.user_account.helpers({
return this; return this;
}, },
userFields: function () { userFields: function () {
var fields = Meteor.users.simpleSchema().getEditableFields(Meteor.user()); var fields = Meteor.users.getInsertableFields(Meteor.user());
return fields; return fields;
}, },
isUsingPassword: function () { isUsingPassword: function () {

View file

@ -1,8 +1,3 @@
/**
* Telescope Users namespace
* @namespace Users
*/
Users = Meteor.users;
/** /**
* Vote schema * Vote schema
@ -34,7 +29,8 @@ Telescope.schemas.userData = new SimpleSchema({
type: String, type: String,
optional: true, optional: true,
control: "textarea", control: "textarea",
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
// autoform: { // autoform: {
// rows: 5 // rows: 5
// } // }
@ -44,7 +40,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
commentCount: { commentCount: {
type: Number, type: Number,
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -53,17 +49,18 @@ Telescope.schemas.userData = new SimpleSchema({
displayName: { displayName: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
profile: true, profile: true,
control: "text", control: "text",
editableBy: ["member", "admin"] insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin
}, },
/** /**
An array containing comment downvotes An array containing comment downvotes
*/ */
downvotedComments: { downvotedComments: {
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -71,7 +68,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
downvotedPosts: { downvotedPosts: {
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -83,7 +80,8 @@ Telescope.schemas.userData = new SimpleSchema({
regEx: SimpleSchema.RegEx.Email, regEx: SimpleSchema.RegEx.Email,
required: true, required: true,
control: "text", control: "text",
editableBy: ["member", "admin"] insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin
// unique: true // note: find a way to fix duplicate accounts before enabling this // unique: true // note: find a way to fix duplicate accounts before enabling this
}, },
/** /**
@ -91,7 +89,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
emailHash: { emailHash: {
type: String, type: String,
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -99,7 +97,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
htmlBio: { htmlBio: {
type: String, type: String,
public: true, publish: true,
profile: true, profile: true,
optional: true, optional: true,
// autoform: { // autoform: {
@ -113,7 +111,7 @@ Telescope.schemas.userData = new SimpleSchema({
karma: { karma: {
type: Number, type: Number,
decimal: true, decimal: true,
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -121,7 +119,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
postCount: { postCount: {
type: Number, type: Number,
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -130,7 +128,7 @@ Telescope.schemas.userData = new SimpleSchema({
// settings: { // settings: {
// type: Object, // type: Object,
// optional: true, // optional: true,
// editableBy: ["member", "admin"], // editableIf: Users.is.ownerOrAdmin,
// blackbox: true, // blackbox: true,
// autoform: { // autoform: {
// omit: true // omit: true
@ -141,7 +139,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
slug: { slug: {
type: String, type: String,
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -150,10 +148,11 @@ Telescope.schemas.userData = new SimpleSchema({
twitterUsername: { twitterUsername: {
type: String, type: String,
optional: true, optional: true,
public: true, publish: true,
profile: true, profile: true,
control: "text", control: "text",
editableBy: ["member", "admin"], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
template: "user_profile_twitter" template: "user_profile_twitter"
}, },
/** /**
@ -161,7 +160,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
upvotedComments: { upvotedComments: {
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -169,7 +168,7 @@ Telescope.schemas.userData = new SimpleSchema({
*/ */
upvotedPosts: { upvotedPosts: {
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
public: true, publish: true,
optional: true optional: true
}, },
/** /**
@ -178,11 +177,12 @@ Telescope.schemas.userData = new SimpleSchema({
website: { website: {
type: String, type: String,
regEx: SimpleSchema.RegEx.Url, regEx: SimpleSchema.RegEx.Url,
public: true, publish: true,
profile: true, profile: true,
optional: true, optional: true,
control: "text", control: "text",
editableBy: ["member", "admin"] insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin
} }
}); });
@ -193,13 +193,13 @@ Telescope.schemas.userData = new SimpleSchema({
Users.schema = new SimpleSchema({ Users.schema = new SimpleSchema({
_id: { _id: {
type: String, type: String,
public: true, publish: true,
optional: true optional: true
}, },
username: { username: {
type: String, type: String,
// regEx: /^[a-z0-9A-Z_]{3,15}$/, // regEx: /^[a-z0-9A-Z_]{3,15}$/,
public: true, publish: true,
optional: true optional: true
}, },
emails: { emails: {
@ -217,14 +217,15 @@ Users.schema = new SimpleSchema({
}, },
createdAt: { createdAt: {
type: Date, type: Date,
public: true, publish: true,
optional: true optional: true
}, },
isAdmin: { isAdmin: {
type: Boolean, type: Boolean,
control: "checkbox", control: "checkbox",
optional: true, optional: true,
editableBy: ["admin"], insertableIf: Users.is.admin,
editableIf: Users.is.admin,
// autoform: { // autoform: {
// omit: true // omit: true
// } // }
@ -268,7 +269,8 @@ if (typeof Herald !== "undefined") {
optional: true, optional: true,
defaultValue: false, defaultValue: false,
control: "checkbox", control: "checkbox",
editableBy: ['admin'], insertableIf: Users.is.admin,
editableBy: Users.is.admin,
autoform: { autoform: {
group: 'Email Notifications' group: 'Email Notifications'
} }
@ -282,7 +284,8 @@ if (typeof Herald !== "undefined") {
optional: true, optional: true,
defaultValue: false, defaultValue: false,
control: "checkbox", control: "checkbox",
editableBy: ['admin', 'member'], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
group: 'Email Notifications' group: 'Email Notifications'
} }
@ -296,7 +299,8 @@ if (typeof Herald !== "undefined") {
optional: true, optional: true,
defaultValue: true, defaultValue: true,
control: "checkbox", control: "checkbox",
editableBy: ['admin', 'member'], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
group: 'Email Notifications' group: 'Email Notifications'
} }
@ -310,7 +314,8 @@ if (typeof Herald !== "undefined") {
optional: true, optional: true,
defaultValue: true, defaultValue: true,
control: "checkbox", control: "checkbox",
editableBy: ['admin', 'member'], insertableIf: Users.is.memberOrAdmin,
editableIf: Users.is.ownerOrAdmin,
autoform: { autoform: {
group: 'Email Notifications' group: 'Email Notifications'
} }

View file

@ -0,0 +1,5 @@
/**
* Telescope Users namespace
* @namespace Users
*/
Users = Meteor.users;

View file

@ -144,16 +144,7 @@ Users.helpers({canEditById: function (document) {return Users.can.editById(this,
* @param {Object} field - The field being edited or inserted * @param {Object} field - The field being edited or inserted
*/ */
Users.can.submitField = function (user, field) { Users.can.submitField = function (user, field) {
return user && field.insertableIf && field.insertableIf(user);
if (!field.editableBy || !user) {
return false;
}
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 || memberCheck;
}; };
Users.helpers({canSubmitField: function (field) {return Users.can.submitField(this, field);}}); Users.helpers({canSubmitField: function (field) {return Users.can.submitField(this, field);}});
@ -162,7 +153,9 @@ Users.helpers({canSubmitField: function (field) {return Users.can.submitField(th
* @param {Object} user - The user performing the action * @param {Object} user - The user performing the action
* @param {Object} field - The field being edited or inserted * @param {Object} field - The field being edited or inserted
*/ */
Users.can.editField = Users.can.submitField; Users.can.editField = function (user, field, document) {
return user && field.editableIf && field.editableIf(user, document);
};
Users.can.invite = function (user) { Users.can.invite = function (user) {
return Users.is.invited(user) || Users.is.admin(user); return Users.is.invited(user) || Users.is.admin(user);

View file

@ -42,6 +42,35 @@ Users.is.owner = function (userOrUserId, document) {
Users.is.ownerById = Users.is.owner; Users.is.ownerById = Users.is.owner;
Users.helpers({isOwner: function () {return Users.is.owner(this, document);}}); Users.helpers({isOwner: function () {return Users.is.owner(this, document);}});
/**
* Check if a user is a member or an admin
* @param {Object} user - The user
* @param {Object} document - The document to check (post, comment, user object, etc.)
*/
Users.is.memberOrAdmin = function (user) {
if (typeof user === "undefined") {
return false;
} else {
return !!user || Users.is.admin(user);
}
};
/**
* Check if a user owns a document or is an admin
* @param {Object} user - The user
* @param {Object} document - The document to check (post, comment, user object, etc.)
*/
Users.is.ownerOrAdmin = function (user, document) {
if (typeof user === "undefined") {
return false;
} else if (typeof document === "undefined") {
return true;
} else {
return Users.is.owner(user, document) || Users.is.admin(user);
}
};
Users.is.invited = function (userOrUserId) { Users.is.invited = function (userOrUserId) {
try { try {
var user = Users.getUser(userOrUserId); var user = Users.getUser(userOrUserId);

View file

@ -19,10 +19,11 @@ Package.onUse(function (api) {
api.addFiles([ api.addFiles([
// 'package-tap.i18n', // 'package-tap.i18n',
'lib/collection.js', 'lib/namespace.js',
'lib/roles.js', 'lib/roles.js',
'lib/config.js', 'lib/config.js',
'lib/permissions.js', 'lib/permissions.js',
'lib/collection.js',
'lib/callbacks.js', 'lib/callbacks.js',
'lib/helpers.js', 'lib/helpers.js',
'lib/published_fields.js', 'lib/published_fields.js',