prettier commit

This commit is contained in:
eric-burel 2019-01-29 17:32:08 +01:00
parent c7aeaea949
commit f51f558cb1
10 changed files with 244 additions and 195 deletions

View file

@ -6,42 +6,42 @@ export * from 'meteor/vulcan:lib';
export * from './default_mutations.js';
export * from './default_resolvers.js';
export { default as Layout } from './components/Layout.jsx';
export { default as App } from './components/App.jsx';
export { default as Icon } from './components/Icon.jsx';
export { default as Loading } from './components/Loading.jsx';
export { default as ShowIf } from './components/ShowIf.jsx';
export { default as NewButton } from './components/NewButton.jsx';
export { default as EditButton } from './components/EditButton.jsx';
export { default as MutationButton } from './components/MutationButton.jsx';
export { default as Error404 } from './components/Error404.jsx';
export { default as DynamicLoading } from './components/DynamicLoading.jsx';
export { default as HeadTags } from './components/HeadTags.jsx';
export { default as Avatar } from './components/Avatar.jsx';
export { default as Card } from './components/Card.jsx';
export { default as Datatable } from './components/Datatable.jsx';
export { default as Flash } from './components/Flash.jsx';
export { default as HelloWorld } from './components/HelloWorld.jsx';
export { default as Welcome } from './components/Welcome.jsx';
export { default as RouterHook } from './components/RouterHook.jsx';
export { default as ScrollToTop } from './components/ScrollToTop.jsx';
export {default as Layout} from './components/Layout.jsx';
export {default as App} from './components/App.jsx';
export {default as Icon} from './components/Icon.jsx';
export {default as Loading} from './components/Loading.jsx';
export {default as ShowIf} from './components/ShowIf.jsx';
export {default as NewButton} from './components/NewButton.jsx';
export {default as EditButton} from './components/EditButton.jsx';
export {default as MutationButton} from './components/MutationButton.jsx';
export {default as Error404} from './components/Error404.jsx';
export {default as DynamicLoading} from './components/DynamicLoading.jsx';
export {default as HeadTags} from './components/HeadTags.jsx';
export {default as Avatar} from './components/Avatar.jsx';
export {default as Card} from './components/Card.jsx';
export {default as Datatable} from './components/Datatable.jsx';
export {default as Flash} from './components/Flash.jsx';
export {default as HelloWorld} from './components/HelloWorld.jsx';
export {default as Welcome} from './components/Welcome.jsx';
export {default as RouterHook} from './components/RouterHook.jsx';
export {default as ScrollToTop} from './components/ScrollToTop.jsx';
export { default as withAccess } from './containers/withAccess.js';
export { default as withMessages } from './containers/withMessages.js';
export { default as withMulti } from './containers/withMulti.js';
export { default as withSingle } from './containers/withSingle.js';
export { default as withCreate } from './containers/withCreate.js';
export { default as withUpdate } from './containers/withUpdate.js';
export { default as withDelete } from './containers/withDelete.js';
export { default as withCurrentUser } from './containers/withCurrentUser.js';
export { default as withMutation } from './containers/withMutation.js';
export { default as withUpsert } from './containers/withUpsert.js';
export {default as withAccess} from './containers/withAccess.js';
export {default as withMessages} from './containers/withMessages.js';
export {default as withMulti} from './containers/withMulti.js';
export {default as withSingle} from './containers/withSingle.js';
export {default as withCreate} from './containers/withCreate.js';
export {default as withUpdate} from './containers/withUpdate.js';
export {default as withDelete} from './containers/withDelete.js';
export {default as withCurrentUser} from './containers/withCurrentUser.js';
export {default as withMutation} from './containers/withMutation.js';
export {default as withUpsert} from './containers/withUpsert.js';
export { default as withComponents } from './containers/withComponents';
export {default as withComponents} from './containers/withComponents';
// OpenCRUD backwards compatibility
export { default as withNew } from './containers/withCreate.js';
export { default as withEdit } from './containers/withUpdate.js';
export { default as withRemove } from './containers/withDelete.js';
export { default as withList } from './containers/withMulti.js';
export { default as withDocument } from './containers/withSingle.js';
export {default as withNew} from './containers/withCreate.js';
export {default as withEdit} from './containers/withUpdate.js';
export {default as withRemove} from './containers/withDelete.js';
export {default as withList} from './containers/withMulti.js';
export {default as withDocument} from './containers/withSingle.js';

View file

@ -1,5 +1,9 @@
import { addTrackFunction } from 'meteor/vulcan:events';
import { getApolloClient, getFragment, createClientTemplate } from 'meteor/vulcan:lib';
import {addTrackFunction} from 'meteor/vulcan:events';
import {
getApolloClient,
getFragment,
createClientTemplate,
} from 'meteor/vulcan:lib';
import gql from 'graphql-tag';
function trackInternal(eventName, eventProperties) {
@ -8,7 +12,10 @@ function trackInternal(eventName, eventProperties) {
const fragmentName = 'AnalyticsEventFragment';
const fragment = getFragment(fragmentName);
const mutation = gql`${createClientTemplate({ typeName: 'AnalyticsEvent', fragmentName })}${fragment}`;
const mutation = gql`
${createClientTemplate({typeName: 'AnalyticsEvent', fragmentName})}
${fragment}
`;
const variables = {
data: {
@ -16,7 +23,7 @@ function trackInternal(eventName, eventProperties) {
properties: eventProperties,
},
};
apolloClient.mutate({ mutation, variables });
apolloClient.mutate({mutation, variables});
}
addTrackFunction(trackInternal);

View file

@ -6,28 +6,28 @@
// Meteor WebApp use a Connect server, so we need to
// use apollo-server-express integration
//import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import {ApolloServer} from 'apollo-server-express';
import { Meteor } from 'meteor/meteor';
import {Meteor} from 'meteor/meteor';
import { WebApp } from 'meteor/webapp';
import {WebApp} from 'meteor/webapp';
import bodyParser from 'body-parser';
// import cookiesMiddleware from 'universal-cookie-express';
// import Cookies from 'universal-cookie';
import voyagerMiddleware from 'graphql-voyager/middleware/express';
import getVoyagerConfig from './voyager';
import { graphiqlMiddleware, getGraphiqlConfig } from './graphiql';
import {graphiqlMiddleware, getGraphiqlConfig} from './graphiql';
import getPlaygroundConfig from './playground';
import initGraphQL from './initGraphQL';
import './settings';
import { engineConfig } from './engine';
import { initContext, computeContextFromReq } from './context.js';
import {engineConfig} from './engine';
import {initContext, computeContextFromReq} from './context.js';
import { GraphQLSchema } from '../../modules/graphql.js';
import {GraphQLSchema} from '../../modules/graphql.js';
import { enableSSR } from '../apollo-ssr';
import {enableSSR} from '../apollo-ssr';
import universalCookiesMiddleware from 'universal-cookie-express';
@ -36,10 +36,14 @@ import {
getApolloServerOptions,
} from './settings';
import { getSetting } from '../../modules/settings.js';
import { formatError } from 'apollo-errors';
import {getSetting} from '../../modules/settings.js';
import {formatError} from 'apollo-errors';
export const setupGraphQLMiddlewares = (apolloServer, config, apolloApplyMiddlewareOptions) => {
export const setupGraphQLMiddlewares = (
apolloServer,
config,
apolloApplyMiddlewareOptions
) => {
// DEBUG LOG
const logReqMiddleware = (req, res, next) => {
console.log('REQ', req.url, req.headers), next();
@ -59,11 +63,11 @@ export const setupGraphQLMiddlewares = (apolloServer, config, apolloApplyMiddlew
// parse request (order matters)
WebApp.connectHandlers.use(
config.path,
bodyParser.json({ limit: getSetting('apolloServer.jsonParserOptions.limit') })
bodyParser.json({limit: getSetting('apolloServer.jsonParserOptions.limit')})
);
WebApp.connectHandlers.use(
config.path,
bodyParser.text({ type: 'application/graphql' })
bodyParser.text({type: 'application/graphql'})
);
// Provide the Meteor WebApp Connect server instance to Apollo
@ -75,10 +79,9 @@ export const setupGraphQLMiddlewares = (apolloServer, config, apolloApplyMiddlew
...apolloApplyMiddlewareOptions,
});
// setup the end point otherwise the request hangs
// TODO: undestand why this is necessary
// @see
// @see
WebApp.connectHandlers.use(config.path, (req, res) => {
if (req.method === 'GET') {
res.end();
@ -108,7 +111,6 @@ export const createApolloServer = ({
apolloServerOptions = {}, // apollo options
config = {}, // Vulcan options
}) => {
// given options contains the schema
const apolloServer = new ApolloServer({
// graphql playground (replacement to graphiql), available on the app path
@ -129,7 +131,7 @@ export const onStart = () => {
const config = {
path: '/graphql',
maxAccountsCacheSizeInMB: 1,
configServer: apolloServer => { },
configServer: apolloServer => {},
voyagerPath: '/graphql-voyager',
graphiqlPath: '/graphiql',
// customConfigFromReq
@ -160,7 +162,7 @@ export const onStart = () => {
formatError,
tracing: getSetting('apolloTracing', Meteor.isDevelopment),
cacheControl: true,
context: ({ req }) => context(req),
context: ({req}) => context(req),
...getApolloServerOptions(),
},
});
@ -172,7 +174,7 @@ export const onStart = () => {
setupToolsMiddlewares(config);
}
// ssr
enableSSR({ computeContext: context });
enableSSR({computeContext: context});
};
// createApolloServer when server startup
Meteor.startup(onStart);

View file

@ -124,7 +124,10 @@ export const computeContextFromReq = (currentContext, customContextFromReq) => {
// console.log('// apollo_server.js user-agent:', req.headers['user-agent']);
// console.log('// apollo_server.js locale:', req.headers.locale);
context.locale = getHeaderLocale(req.headers, context.currentUser && context.currentUser.locale);
context.locale = getHeaderLocale(
req.headers,
context.currentUser && context.currentUser.locale
);
return context;
};

View file

@ -1,4 +1,4 @@
export * from './apollo_server2';
export * from './settings';
export { default as initGraphQL } from './initGraphQL';
export {default as initGraphQL} from './initGraphQL';

View file

@ -3,33 +3,48 @@
Run a GraphQL request from the server with the proper context
*/
import { graphql } from 'graphql';
import { Collections } from '../modules/collections.js';
import {graphql} from 'graphql';
import {Collections} from '../modules/collections.js';
import DataLoader from 'dataloader';
import findByIds from '../modules/findbyids.js';
import { getDefaultFragmentText, extractFragmentName, getFragmentText } from '../modules/fragments.js';
import { getSetting } from '../modules/settings';
import {
getDefaultFragmentText,
extractFragmentName,
getFragmentText,
} from '../modules/fragments.js';
import {getSetting} from '../modules/settings';
import merge from 'lodash/merge';
import { singleClientTemplate } from '../modules/graphql_templates';
import { Utils } from './utils';
import { GraphQLSchema } from '../modules/graphql';
import {singleClientTemplate} from '../modules/graphql_templates';
import {Utils} from './utils';
import {GraphQLSchema} from '../modules/graphql';
// note: if no context is passed, default to running requests with full admin privileges
export const runGraphQL = async (query, variables = {}, context ) => {
const defaultContext = { currentUser: {isAdmin: true}, locale: getSetting('locale') };
export const runGraphQL = async (query, variables = {}, context) => {
const defaultContext = {
currentUser: {isAdmin: true},
locale: getSetting('locale'),
};
const queryContext = merge(defaultContext, context);
const executableSchema = GraphQLSchema.getExecutableSchema();
// within the scope of this specific request,
// within the scope of this specific request,
// decorate each collection with a new Dataloader object and add it to context
Collections.forEach(collection => {
collection.loader = new DataLoader(ids => findByIds(collection, ids, queryContext), { cache: true });
collection.loader = new DataLoader(
ids => findByIds(collection, ids, queryContext),
{cache: true}
);
queryContext[collection.options.collectionName] = collection;
});
// see http://graphql.org/graphql-js/graphql/#graphql
const result = await graphql(executableSchema, query, {}, queryContext, variables);
const result = await graphql(
executableSchema,
query,
{},
queryContext,
variables
);
if (result.errors) {
// eslint-disable-next-line no-console
@ -51,42 +66,51 @@ If no fragment is passed, default to default fragment
*/
export const buildQuery = (collection, {fragmentName, fragmentText}) => {
const collectionName = collection.options.collectionName;
const typeName = collection.options.typeName;
const defaultFragmentName = `${collectionName}DefaultFragment`;
const defaultFragmentText = getDefaultFragmentText(collection, { onlyViewable: false });
const defaultFragmentText = getDefaultFragmentText(collection, {
onlyViewable: false,
});
// default to default name and text
let name = defaultFragmentName;
let text = defaultFragmentText;
if (fragmentName) { // if fragmentName is passed, use that to get name and text
if (fragmentName) {
// if fragmentName is passed, use that to get name and text
name = fragmentName;
text = getFragmentText(fragmentName);
} else if (fragmentText) { // if fragmentText is passed, use that to get name and text
} else if (fragmentText) {
// if fragmentText is passed, use that to get name and text
name = extractFragmentName(fragmentText);
text = fragmentText;
}
const query = `${singleClientTemplate({ typeName, fragmentName: name })}${text}`;
const query = `${singleClientTemplate({
typeName,
fragmentName: name,
})}${text}`;
return query;
};
Meteor.startup(() => {
Collections.forEach(collection => {
const typeName = collection.options.typeName;
collection.queryOne = async (documentId, { fragmentName, fragmentText, context }) => {
const query = buildQuery(collection, { fragmentName, fragmentText });
const result = await runQuery(query, { input: { selector: { documentId } } }, context);
collection.queryOne = async (
documentId,
{fragmentName, fragmentText, context}
) => {
const query = buildQuery(collection, {fragmentName, fragmentText});
const result = await runQuery(
query,
{input: {selector: {documentId}}},
context
);
return result.data[Utils.camelCaseify(typeName)].result;
};
});
});

View file

@ -4,55 +4,54 @@ import {
defaultConfig,
initGraphQL,
initContext,
computeContextFromReq
computeContextFromReq,
} from '../../lib/server/apollo-server';
import {GraphQLSchema} from '../../lib/modules/graphql';
import expect from 'expect';
import { executableSchema } from './fixtures/minimalSchema';
import {executableSchema} from './fixtures/minimalSchema';
const test = it; // TODO: just before we switch to jest
// @see https://www.apollographql.com/docs/apollo-server/features/testing.html
describe('apollo-server', function() {
let options;
before(function () {
initGraphQL();
let options;
before(function() {
initGraphQL();
options = {
config: defaultConfig,
// Apollo options
apolloServerOptions: {
// TODO: check why this fails. One of the schema defined
// in one of the test file (when running createCollection in a test)
// is not working as expected
//schema: GraphQLSchema.getExecutableSchema(),
schema: executableSchema,
//formatError,
//tracing: getSetting('apolloTracing', Meteor.isDevelopment),
cacheControl: true,
//context
},
// Apollo applyMiddleware Option
apolloApplyMiddlewareOptions: {},
};
options = {
config: defaultConfig,
// Apollo options
apolloServerOptions: {
// TODO: check why this fails. One of the schema defined
// in one of the test file (when running createCollection in a test)
// is not working as expected
//schema: GraphQLSchema.getExecutableSchema(),
schema: executableSchema,
//formatError,
//tracing: getSetting('apolloTracing', Meteor.isDevelopment),
cacheControl: true,
//context
},
// Apollo applyMiddleware Option
apolloApplyMiddlewareOptions: {},
};
});
describe('createServer', function() {
test('init server', function() {
const server = createApolloServer(options);
expect(server).toBeDefined();
});
describe('createServer', function () {
test('init server', function () {
const server = createApolloServer(options);
expect(server).toBeDefined();
});
});
describe('setupWebApp', function() {});
describe('compute context', function() {
test.skip('inital context contains data loaders', function() {
// TODO
});
describe('setupWebApp', function () { });
describe('compute context', function(){
test.skip('inital context contains data loaders', function(){
// TODO
});
test.skip('initial context contains graphQLSchema context', function(){
// TODO
});
test.skip('initial context is merged with provided context', function(){
// TODO
});
test.skip('initial context contains graphQLSchema context', function() {
// TODO
});
});
test.skip('initial context is merged with provided context', function() {
// TODO
});
});
});

View file

@ -1,7 +1,7 @@
// blatantly stolen from https://www.apollographql.com/docs/graphql-tools/generate-schema.html
import find from 'lodash/find';
import filter from 'lodash/filter';
import { makeExecutableSchema } from 'graphql-tools';
import {makeExecutableSchema} from 'graphql-tools';
const typeDefs = `
type Author {
@ -34,27 +34,27 @@ const typeDefs = `
// example data
const authors = [
{ id: 1, firstName: 'Tom', lastName: 'Coleman' },
{ id: 2, firstName: 'Sashko', lastName: 'Stubailo' },
{ id: 3, firstName: 'Mikhail', lastName: 'Novikov' },
{id: 1, firstName: 'Tom', lastName: 'Coleman'},
{id: 2, firstName: 'Sashko', lastName: 'Stubailo'},
{id: 3, firstName: 'Mikhail', lastName: 'Novikov'},
];
const posts = [
{ id: 1, authorId: 1, title: 'Introduction to GraphQL', votes: 2 },
{ id: 2, authorId: 2, title: 'Welcome to Meteor', votes: 3 },
{ id: 3, authorId: 2, title: 'Advanced GraphQL', votes: 1 },
{ id: 4, authorId: 3, title: 'Launchpad is Cool', votes: 7 },
{id: 1, authorId: 1, title: 'Introduction to GraphQL', votes: 2},
{id: 2, authorId: 2, title: 'Welcome to Meteor', votes: 3},
{id: 3, authorId: 2, title: 'Advanced GraphQL', votes: 1},
{id: 4, authorId: 3, title: 'Launchpad is Cool', votes: 7},
];
const resolvers = {
Query: {
posts: () => posts,
author: (_, { id }) => find(authors, { id }),
author: (_, {id}) => find(authors, {id}),
},
Mutation: {
upvotePost: (_, { postId }) => {
const post = find(posts, { id: postId });
upvotePost: (_, {postId}) => {
const post = find(posts, {id: postId});
if (!post) {
throw new Error(`Couldn't find post with id ${postId}`);
}
@ -64,15 +64,15 @@ const resolvers = {
},
Author: {
posts: author => filter(posts, { authorId: author.id }),
posts: author => filter(posts, {authorId: author.id}),
},
Post: {
author: post => find(authors, { id: post.authorId }),
author: post => find(authors, {id: post.authorId}),
},
};
export const executableSchema = makeExecutableSchema({
typeDefs,
resolvers
});
typeDefs,
resolvers,
});

View file

@ -1,2 +1,2 @@
import './graphql.test';
import './apollo-server.test';
import './apollo-server.test';

View file

@ -1,4 +1,4 @@
import { Utils } from 'meteor/vulcan:lib';
import {Utils} from 'meteor/vulcan:lib';
import Users from './collection.js';
import moment from 'moment';
import _ from 'underscore';
@ -11,7 +11,7 @@ import _ from 'underscore';
* @summary Get a user
* @param {String} userOrUserId
*/
Users.getUser = function (userOrUserId) {
Users.getUser = function(userOrUserId) {
if (typeof userOrUserId === 'undefined') {
if (!Meteor.user()) {
throw new Error();
@ -29,44 +29,51 @@ Users.getUser = function (userOrUserId) {
* @summary Get a user's username (unique, no special characters or spaces)
* @param {Object} user
*/
Users.getUserName = function (user) {
try{
if (user.username)
return user.username;
if (user && user.services && user.services.twitter && user.services.twitter.screenName)
Users.getUserName = function(user) {
try {
if (user.username) return user.username;
if (
user &&
user.services &&
user.services.twitter &&
user.services.twitter.screenName
)
return user.services.twitter.screenName;
}
catch (error){
} catch (error) {
console.log(error); // eslint-disable-line
return null;
}
};
Users.getUserNameById = function (userId) {return Users.getUserName(Users.findOne(userId));};
Users.getUserNameById = function(userId) {
return Users.getUserName(Users.findOne(userId));
};
/**
* @summary Get a user's display name (not unique, can take special characters and spaces)
* @param {Object} user
*/
Users.getDisplayName = function (user) {
Users.getDisplayName = function(user) {
if (!user) {
return '';
} else {
return (user.displayName) ? user.displayName : Users.getUserName(user);
return user.displayName ? user.displayName : Users.getUserName(user);
}
};
Users.getDisplayNameById = function (userId) {return Users.getDisplayName(Users.findOne(userId));};
Users.getDisplayNameById = function(userId) {
return Users.getDisplayName(Users.findOne(userId));
};
/**
* @summary Get a user's profile URL
* @param {Object} user (note: we only actually need either the _id or slug properties)
* @param {Boolean} isAbsolute
*/
Users.getProfileUrl = function (user, isAbsolute) {
Users.getProfileUrl = function(user, isAbsolute) {
if (typeof user === 'undefined') {
return '';
}
isAbsolute = typeof isAbsolute === 'undefined' ? false : isAbsolute; // default to false
var prefix = isAbsolute ? Utils.getSiteUrl().slice(0,-1) : '';
var prefix = isAbsolute ? Utils.getSiteUrl().slice(0, -1) : '';
if (user.slug) {
return `${prefix}/users/${user.slug}`;
} else {
@ -79,7 +86,7 @@ Users.getProfileUrl = function (user, isAbsolute) {
* @param {Object} user (note: we only actually need either the _id or slug properties)
* @param {Boolean} isAbsolute
*/
Users.getEditUrl = function (user, isAbsolute) {
Users.getEditUrl = function(user, isAbsolute) {
return `${Users.getProfileUrl(user, isAbsolute)}/edit`;
};
@ -87,55 +94,64 @@ Users.getEditUrl = function (user, isAbsolute) {
* @summary Get a user's Twitter name
* @param {Object} user
*/
Users.getTwitterName = function (user) {
Users.getTwitterName = function(user) {
// return twitter name provided by user, or else the one used for twitter login
if (typeof user !== 'undefined') {
if (user.twitterUsername) {
return user.twitterUsername;
} else if(Utils.checkNested(user, 'services', 'twitter', 'screenName')) {
} else if (Utils.checkNested(user, 'services', 'twitter', 'screenName')) {
return user.services.twitter.screenName;
}
}
return null;
};
Users.getTwitterNameById = function (userId) {return Users.getTwitterName(Users.findOne(userId));};
Users.getTwitterNameById = function(userId) {
return Users.getTwitterName(Users.findOne(userId));
};
/**
* @summary Get a user's GitHub name
* @param {Object} user
*/
Users.getGitHubName = function (user) {
Users.getGitHubName = function(user) {
// return twitter name provided by user, or else the one used for twitter login
if(Utils.checkNested(user, 'profile', 'github')){
if (Utils.checkNested(user, 'profile', 'github')) {
return user.profile.github;
}else if(Utils.checkNested(user, 'services', 'github', 'screenName')){ // TODO: double-check this with GitHub login
} else if (Utils.checkNested(user, 'services', 'github', 'screenName')) {
// TODO: double-check this with GitHub login
return user.services.github.screenName;
}
return null;
};
Users.getGitHubNameById = function (userId) {return Users.getGitHubName(Users.findOne(userId));};
Users.getGitHubNameById = function(userId) {
return Users.getGitHubName(Users.findOne(userId));
};
/**
* @summary Get a user's email
* @param {Object} user
*/
Users.getEmail = function (user) {
if(user.email){
Users.getEmail = function(user) {
if (user.email) {
return user.email;
}else{
} else {
return null;
}
};
Users.getEmailById = function (userId) {return Users.getEmail(Users.findOne(userId));};
Users.getEmailById = function(userId) {
return Users.getEmail(Users.findOne(userId));
};
/**
* @summary Get a user's email hash
* @param {Object} user
*/
Users.getEmailHash = function (user) {
Users.getEmailHash = function(user) {
return user.emailHash;
};
Users.getEmailHashById = function (userId) {return Users.getEmailHash(Users.findOne(userId));};
Users.getEmailHashById = function(userId) {
return Users.getEmailHash(Users.findOne(userId));
};
/**
* @summary Get a user setting
@ -143,7 +159,7 @@ Users.getEmailHashById = function (userId) {return Users.getEmailHash(Users.find
* @param {String} settingName
* @param {Object} defaultValue
*/
Users.getSetting = function (user = null, settingName, defaultValue = null) {
Users.getSetting = function(user = null, settingName, defaultValue = null) {
if (user) {
const settingValue = Users.getProperty(user, settingName);
return typeof settingValue === 'undefined' ? defaultValue : settingValue;
@ -160,51 +176,50 @@ Users.getSetting = function (user = null, settingName, defaultValue = null) {
* @summary Check if the user has completed their profile.
* @param {Object} user
*/
Users.hasCompletedProfile = function (user) {
Users.hasCompletedProfile = function(user) {
if (!user) return false;
return _.every(Users.getRequiredFields(), function (fieldName) {
return _.every(Users.getRequiredFields(), function(fieldName) {
return !!Utils.getNestedProperty(user, fieldName);
});
};
///////////////////
// Other Helpers //
///////////////////
Users.findLast = function (user, collection) {
Users.findLast = function(user, collection) {
return collection.findOne({userId: user._id}, {sort: {createdAt: -1}});
};
Users.timeSinceLast = function (user, collection){
Users.timeSinceLast = function(user, collection) {
var now = new Date().getTime();
var last = this.findLast(user, collection);
if(!last)
return 999; // if this is the user's first post or comment ever, stop here
return Math.abs(Math.floor((now-last.createdAt)/1000));
if (!last) return 999; // if this is the user's first post or comment ever, stop here
return Math.abs(Math.floor((now - last.createdAt) / 1000));
};
Users.numberOfItemsInPast24Hours = function (user, collection) {
Users.numberOfItemsInPast24Hours = function(user, collection) {
var mNow = moment();
var items = collection.find({
userId: user._id,
createdAt: {
$gte: mNow.subtract(24, 'hours').toDate()
}
$gte: mNow.subtract(24, 'hours').toDate(),
},
});
return items.count();
};
Users.getProperty = function (object, property) {
Users.getProperty = function(object, property) {
// recursive function to get nested properties
var array = property.split('.');
if(array.length > 1){
if (array.length > 1) {
var parent = array.shift();
// if our property is not at this level, call function again one level deeper if we can go deeper, else return undefined
return (typeof object[parent] === 'undefined') ? undefined : this.getProperty(object[parent], array.join('.'));
}else{
return typeof object[parent] === 'undefined'
? undefined
: this.getProperty(object[parent], array.join('.'));
} else {
// else return property
return object[array[0]];
}
@ -220,7 +235,6 @@ Users.getProperty = function (object, property) {
// Users.update(user._id, modifier);
// }
////////////////////
// More Helpers //
////////////////////
@ -231,9 +245,9 @@ Users.getProperty = function (object, property) {
* @summary @method Users.getRequiredFields
* Get a list of all fields required for a profile to be complete.
*/
Users.getRequiredFields = function () {
Users.getRequiredFields = function() {
var schema = Users.simpleSchema()._schema;
var fields = _.filter(_.keys(schema), function (fieldName) {
var fields = _.filter(_.keys(schema), function(fieldName) {
var field = schema[fieldName];
return !!field.mustComplete;
});
@ -248,6 +262,6 @@ Users.getRequiredFields = function () {
// return Meteor.user() ? Users.getEmail(Meteor.user()) : '';
// };
Users.findByEmail = function (email) {
return Users.findOne({'email': email});
Users.findByEmail = function(email) {
return Users.findOne({email: email});
};