Merge remote-tracking branch 'upstream/devel' into devel

This commit is contained in:
Eric Burel 2018-10-29 08:41:20 +01:00
commit 6ab0b49a46
4 changed files with 86 additions and 40 deletions

View file

@ -1,11 +1,11 @@
Package.describe({ Package.describe({
summary: "Generates the boilerplate html from program's manifest", summary: 'Generates the boilerplate html from program\'s manifest',
version: '1.6.0', version: '1.6.0',
name: 'boilerplate-generator' name: 'boilerplate-generator'
}); });
Npm.depends({ Npm.depends({
"combined-stream2": "1.1.2" 'combined-stream2': '1.1.2'
}); });
Package.onUse(api => { Package.onUse(api => {

View file

@ -0,0 +1,5 @@
import { Accounts } from 'meteor/accounts-base';
import { getSetting } from 'meteor/vulcan:core';
Accounts.emailTemplates.siteName = getSetting('public.title', '');
Accounts.emailTemplates.from = getSetting('public.title', '')+ ' <' + getSetting('defaultEmail', 'no-reply@example.com') +'>';

View file

@ -4,6 +4,7 @@ import './imports/components.js';
import './imports/login_session.js'; import './imports/login_session.js';
import './imports/routes.js'; import './imports/routes.js';
import './imports/oauth_config.js'; import './imports/oauth_config.js';
import './imports/emailTemplates.js'
import { redirect, STATES } from './imports/helpers.js'; import { redirect, STATES } from './imports/helpers.js';
import './imports/api/server/servicesListPublication.js'; import './imports/api/server/servicesListPublication.js';

View file

@ -8,7 +8,7 @@ import { registerFragment, getDefaultFragmentText } from './fragments.js';
import escapeStringRegexp from 'escape-string-regexp'; import escapeStringRegexp from 'escape-string-regexp';
import { validateIntlField, getIntlString, isIntlField } from './intl'; import { validateIntlField, getIntlString, isIntlField } from './intl';
const wrapAsync = (Meteor.wrapAsync)? Meteor.wrapAsync : Meteor._wrapAsync; const wrapAsync = Meteor.wrapAsync ? Meteor.wrapAsync : Meteor._wrapAsync;
// import { debug } from './debug.js'; // import { debug } from './debug.js';
registerSetting('maxDocumentsPerRequest', 1000, 'Maximum documents per request'); registerSetting('maxDocumentsPerRequest', 1000, 'Maximum documents per request');
@ -18,24 +18,27 @@ export let hasIntlFields = false;
export const Collections = []; export const Collections = [];
export const getCollection = name => Collections.find(({ options: { collectionName }}) => name === collectionName || name === collectionName.toLowerCase()); export const getCollection = name =>
Collections.find(
({ options: { collectionName } }) => name === collectionName || name === collectionName.toLowerCase()
);
// TODO: find more reliable way to get collection name from type name? // TODO: find more reliable way to get collection name from type name?
export const getCollectionName = typeName => Utils.pluralize(typeName); export const getCollectionName = typeName => Utils.pluralize(typeName);
// TODO: find more reliable way to get type name from collection name? // TODO: find more reliable way to get type name from collection name?
export const getTypeName = collectionName => collectionName.slice(0,-1); export const getTypeName = collectionName => collectionName.slice(0, -1);
/** /**
* @summary replacement for Collection2's attachSchema. Pass either a schema, to * @summary replacement for Collection2's attachSchema. Pass either a schema, to
* initialize or replace the schema, or some fields, to extend the current schema * initialize or replace the schema, or some fields, to extend the current schema
* @class Mongo.Collection * @class Mongo.Collection
*/ */
Mongo.Collection.prototype.attachSchema = function (schemaOrFields) { Mongo.Collection.prototype.attachSchema = function(schemaOrFields) {
if (schemaOrFields instanceof SimpleSchema) { if (schemaOrFields instanceof SimpleSchema) {
this.simpleSchema = () => schemaOrFields; this.simpleSchema = () => schemaOrFields;
} else { } else {
this.simpleSchema().extend(schemaOrFields) this.simpleSchema().extend(schemaOrFields);
} }
}; };
@ -43,8 +46,7 @@ Mongo.Collection.prototype.attachSchema = function (schemaOrFields) {
* @summary Add an additional field (or an array of fields) to a schema. * @summary Add an additional field (or an array of fields) to a schema.
* @param {Object|Object[]} field * @param {Object|Object[]} field
*/ */
Mongo.Collection.prototype.addField = function (fieldOrFieldArray) { Mongo.Collection.prototype.addField = function(fieldOrFieldArray) {
const collection = this; const collection = this;
const schema = collection.simpleSchema()._schema; const schema = collection.simpleSchema()._schema;
const fieldSchema = {}; const fieldSchema = {};
@ -52,7 +54,7 @@ Mongo.Collection.prototype.addField = function (fieldOrFieldArray) {
const fieldArray = Array.isArray(fieldOrFieldArray) ? fieldOrFieldArray : [fieldOrFieldArray]; const fieldArray = Array.isArray(fieldOrFieldArray) ? fieldOrFieldArray : [fieldOrFieldArray];
// loop over fields and add them to schema (or extend existing fields) // loop over fields and add them to schema (or extend existing fields)
fieldArray.forEach(function (field) { fieldArray.forEach(function(field) {
fieldSchema[field.fieldName] = field.fieldSchema; fieldSchema[field.fieldName] = field.fieldSchema;
}); });
@ -64,8 +66,7 @@ Mongo.Collection.prototype.addField = function (fieldOrFieldArray) {
* @summary Remove a field from a schema. * @summary Remove a field from a schema.
* @param {String} fieldName * @param {String} fieldName
*/ */
Mongo.Collection.prototype.removeField = function (fieldName) { Mongo.Collection.prototype.removeField = function(fieldName) {
var collection = this; var collection = this;
var schema = _.omit(collection.simpleSchema()._schema, fieldName); var schema = _.omit(collection.simpleSchema()._schema, fieldName);
@ -77,7 +78,7 @@ Mongo.Collection.prototype.removeField = function (fieldName) {
* @summary Add a default view function. * @summary Add a default view function.
* @param {Function} view * @param {Function} view
*/ */
Mongo.Collection.prototype.addDefaultView = function (view) { Mongo.Collection.prototype.addDefaultView = function(view) {
this.defaultView = view; this.defaultView = view;
}; };
@ -86,16 +87,16 @@ Mongo.Collection.prototype.addDefaultView = function (view) {
* @param {String} viewName * @param {String} viewName
* @param {Function} view * @param {Function} view
*/ */
Mongo.Collection.prototype.addView = function (viewName, view) { Mongo.Collection.prototype.addView = function(viewName, view) {
this.views[viewName] = view; this.views[viewName] = view;
}; };
/** /**
* @summary Allow mongodb aggregation * @summary Allow mongodb aggregation
* @param {Array} pipelines mongodb pipeline * @param {Array} pipelines mongodb pipeline
* @param {Object} options mongodb option object * @param {Object} options mongodb option object
*/ */
Mongo.Collection.prototype.aggregate = function (pipelines, options) { Mongo.Collection.prototype.aggregate = function(pipelines, options) {
var coll = this.rawCollection(); var coll = this.rawCollection();
return wrapAsync(coll.aggregate.bind(coll))(pipelines, options); return wrapAsync(coll.aggregate.bind(coll))(pipelines, options);
}; };
@ -105,11 +106,12 @@ Mongo.Collection.prototype.helpers = function(helpers) {
var self = this; var self = this;
if (self._transform && !self._helpers) if (self._transform && !self._helpers)
throw new Meteor.Error('Can\'t apply helpers to \'' + throw new Meteor.Error('Can\'t apply helpers to \'' + self._name + '\' a transform function already exists!');
self._name + '\' a transform function already exists!');
if (!self._helpers) { if (!self._helpers) {
self._helpers = function Document(doc) { return _.extend(this, doc); }; self._helpers = function Document(doc) {
return _.extend(this, doc);
};
self._transform = function(doc) { self._transform = function(doc) {
return new self._helpers(doc); return new self._helpers(doc);
}; };
@ -121,12 +123,20 @@ Mongo.Collection.prototype.helpers = function(helpers) {
}; };
export const createCollection = options => { export const createCollection = options => {
const {
const { typeName, collectionName = getCollectionName(typeName), schema, generateGraphQLSchema = true, dbCollectionName } = options; typeName,
collectionName = getCollectionName(typeName),
schema,
generateGraphQLSchema = true,
dbCollectionName
} = options;
// initialize new Mongo collection // initialize new Mongo collection
const collection = collectionName === 'Users' && Meteor.users ? Meteor.users : new Mongo.Collection(dbCollectionName ? dbCollectionName : collectionName.toLowerCase()); const collection =
collectionName === 'Users' && Meteor.users
? Meteor.users
: new Mongo.Collection(dbCollectionName ? dbCollectionName : collectionName.toLowerCase());
// decorate collection with options // decorate collection with options
collection.options = options; collection.options = options;
@ -139,7 +149,7 @@ export const createCollection = options => {
// add collectionName if missing // add collectionName if missing
collection.collectionName = collectionName; collection.collectionName = collectionName;
collection.options.collectionName = collectionName; collection.options.collectionName = collectionName;
// add views // add views
collection.views = []; collection.views = [];
@ -147,7 +157,6 @@ export const createCollection = options => {
Object.keys(schema).forEach(fieldName => { Object.keys(schema).forEach(fieldName => {
const fieldSchema = schema[fieldName]; const fieldSchema = schema[fieldName];
if (isIntlField(fieldSchema)) { if (isIntlField(fieldSchema)) {
// we have at least one intl field // we have at least one intl field
hasIntlFields = true; hasIntlFields = true;
@ -159,13 +168,13 @@ export const createCollection = options => {
...propertiesToCopy, // copy properties from regular field ...propertiesToCopy, // copy properties from regular field
hidden: true, hidden: true,
type: Array, type: Array,
isIntlData: true, isIntlData: true
}; };
delete schema[`${fieldName}_intl`].intl; delete schema[`${fieldName}_intl`].intl;
schema[`${fieldName}_intl.$`] = { schema[`${fieldName}_intl.$`] = {
type: getIntlString(), type: getIntlString()
}; };
// if original field is required, enable custom validation function instead of `optional` property // if original field is required, enable custom validation function instead of `optional` property
@ -189,7 +198,7 @@ export const createCollection = options => {
context[collectionName] = collection; context[collectionName] = collection;
addToGraphQLContext(context); addToGraphQLContext(context);
if (generateGraphQLSchema){ if (generateGraphQLSchema) {
// add collection to list of dynamically generated GraphQL schemas // add collection to list of dynamically generated GraphQL schemas
addGraphQLCollection(collection); addGraphQLCollection(collection);
} }
@ -205,7 +214,6 @@ export const createCollection = options => {
// ------------------------------------- Parameters -------------------------------- // // ------------------------------------- Parameters -------------------------------- //
collection.getParameters = (terms = {}, apolloClient, context) => { collection.getParameters = (terms = {}, apolloClient, context) => {
// console.log(terms); // console.log(terms);
let parameters = { let parameters = {
@ -224,26 +232,53 @@ export const createCollection = options => {
} }
// iterate over posts.parameters callbacks // iterate over posts.parameters callbacks
parameters = runCallbacks(`${typeName.toLowerCase()}.parameters`, parameters, _.clone(terms), apolloClient, context); parameters = runCallbacks(
`${typeName.toLowerCase()}.parameters`,
parameters,
_.clone(terms),
apolloClient,
context
);
// OpenCRUD backwards compatibility // OpenCRUD backwards compatibility
parameters = runCallbacks(`${collectionName.toLowerCase()}.parameters`, parameters, _.clone(terms), apolloClient, context); parameters = runCallbacks(
`${collectionName.toLowerCase()}.parameters`,
parameters,
_.clone(terms),
apolloClient,
context
);
if (Meteor.isClient) { if (Meteor.isClient) {
parameters = runCallbacks(`${typeName.toLowerCase()}.parameters.client`, parameters, _.clone(terms), apolloClient); parameters = runCallbacks(
`${typeName.toLowerCase()}.parameters.client`,
parameters,
_.clone(terms),
apolloClient
);
// OpenCRUD backwards compatibility // OpenCRUD backwards compatibility
parameters = runCallbacks(`${collectionName.toLowerCase()}.parameters.client`, parameters, _.clone(terms), apolloClient); parameters = runCallbacks(
`${collectionName.toLowerCase()}.parameters.client`,
parameters,
_.clone(terms),
apolloClient
);
} }
// note: check that context exists to avoid calling this from withList during SSR // note: check that context exists to avoid calling this from withList during SSR
if (Meteor.isServer && context) { if (Meteor.isServer && context) {
parameters = runCallbacks(`${typeName.toLowerCase()}.parameters.server`, parameters, _.clone(terms), context); parameters = runCallbacks(`${typeName.toLowerCase()}.parameters.server`, parameters, _.clone(terms), context);
// OpenCRUD backwards compatibility // OpenCRUD backwards compatibility
parameters = runCallbacks(`${collectionName.toLowerCase()}.parameters.server`, parameters, _.clone(terms), context); parameters = runCallbacks(
`${collectionName.toLowerCase()}.parameters.server`,
parameters,
_.clone(terms),
context
);
} }
// sort using terms.orderBy (overwrite defaultView's sort) // sort using terms.orderBy (overwrite defaultView's sort)
if (terms.orderBy && !_.isEmpty(terms.orderBy)) { if (terms.orderBy && !_.isEmpty(terms.orderBy)) {
parameters.options.sort = terms.orderBy parameters.options.sort = terms.orderBy;
} }
// if there is no sort, default to sorting by createdAt descending // if there is no sort, default to sorting by createdAt descending
@ -254,7 +289,7 @@ export const createCollection = options => {
// extend sort to sort posts by _id to break ties, unless there's already an id sort // extend sort to sort posts by _id to break ties, unless there's already an id sort
// NOTE: always do this last to avoid overriding another sort // NOTE: always do this last to avoid overriding another sort
if (!(parameters.options.sort && parameters.options.sort._id)) { if (!(parameters.options.sort && parameters.options.sort._id)) {
parameters = Utils.deepExtend(true, parameters, {options: {sort: {_id: -1}}}); parameters = Utils.deepExtend(true, parameters, { options: { sort: { _id: -1 } } });
} }
// remove any null fields (setting a field to null means it should be deleted) // remove any null fields (setting a field to null means it should be deleted)
@ -268,23 +303,28 @@ export const createCollection = options => {
} }
if (terms.query) { if (terms.query) {
const query = escapeStringRegexp(terms.query); const query = escapeStringRegexp(terms.query);
const currentSchema = collection.simpleSchema()._schema; const currentSchema = collection.simpleSchema()._schema;
const searchableFieldNames = _.filter(_.keys(currentSchema), fieldName => currentSchema[fieldName].searchable); const searchableFieldNames = _.filter(_.keys(currentSchema), fieldName => currentSchema[fieldName].searchable);
if (searchableFieldNames.length) { if (searchableFieldNames.length) {
parameters = Utils.deepExtend(true, parameters, { parameters = Utils.deepExtend(true, parameters, {
selector: { selector: {
$or: searchableFieldNames.map(fieldName => ({[fieldName]: {$regex: query, $options: 'i'}})) $or: searchableFieldNames.map(fieldName => ({ [fieldName]: { $regex: query, $options: 'i' } }))
} }
}); });
} else {
console.warn(
`Warning: terms.query is set but schema ${
collection.options.typeName
} has no searchable field. Set "searchable: true" for at least one field to enable search.`
);
} }
} }
// limit number of items to 1000 by default // limit number of items to 1000 by default
const maxDocuments = getSetting('maxDocumentsPerRequest', 1000); const maxDocuments = getSetting('maxDocumentsPerRequest', 1000);
const limit = terms.limit || parameters.options.limit; const limit = terms.limit || parameters.options.limit;
parameters.options.limit = (!limit || limit < 1 || limit > maxDocuments) ? maxDocuments : limit; parameters.options.limit = !limit || limit < 1 || limit > maxDocuments ? maxDocuments : limit;
// console.log(parameters); // console.log(parameters);