mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
commit
6ab0b49a46
4 changed files with 86 additions and 40 deletions
|
@ -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 => {
|
||||||
|
|
5
packages/vulcan-accounts/imports/emailTemplates.js
Normal file
5
packages/vulcan-accounts/imports/emailTemplates.js
Normal 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') +'>';
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue