eslint & clean up code, also fixed some bugs (#1515)

* [eslint] update eslint rules & add .eslintignore to ignore non-ready nova packages

* [clean-up] nova-voting

* [clean-up] [bug] nova-users: missing user parameter

* [clean-up] nova-users

* [clean-up] nova-subscribe

* [clean-up] nova-settings

* [clean-up] nova-rss

* [clean-up] [bug] nova-posts: correct UsersRemoveDeletePosts

* [clean-up] nova-posts

* [clean-up] nova-notifications

* [clean-up] [bug] nova-newsletter: no error.message on throw error

* [clean-up] nova-newsletter

* [clean-up] nova-lib

* [clean-up] nova-kadira

* [clean-up] nova-inject-data

* [clean-up] nova-getting-started

* [clean-up] nova-forms

* [clean-up] nova-events

* [clean-up] [bug] nova-embedly: no FlowRouter

* [clean-up] nova-embedly

* [clean-up] nova-email-templates

* [clean-up] nova-email

* [clean-up] nova-debug

* [clean-up] nova-core

* [clean-up] [bug] nova-comments: correct UsersRemoveDeleteComments

* [clean-up] nova-comments

* [clean-up] [bug] nova-cloudinary: use Telescope.settings.collection instand

* [clean-up] nova-cloudinary

* [clean-up] nova-categories

* [clean-up] nova-base-components

* [clean-up] nova-api

* [eslint] extends react recommended

* [clean-up] for jsx files

* [eslint] extends meteor recommended

* i forgot this one little change
This commit is contained in:
Comus Leong 2016-11-26 02:46:55 +08:00 committed by Xavier Cazalot
parent 99c8d6ef34
commit 464e20a96c
102 changed files with 548 additions and 457 deletions

1
.eslintignore Normal file
View file

@ -0,0 +1 @@
packages/_*

View file

@ -1,6 +1,8 @@
{
"extends": [
"eslint:recommended"
"eslint:recommended",
"plugin:meteor/recommended",
"plugin:react/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
@ -10,7 +12,17 @@
},
"rules": {
"babel/generator-star-spacing": 0,
"babel/new-cap": 1,
"babel/new-cap": [1, {
"capIsNewExceptions": [
"Optional",
"OneOf",
"Maybe",
"MailChimpAPI",
"Juice",
"Run",
"AppComposer"
]
}],
"babel/array-bracket-spacing": 0,
"babel/object-curly-spacing": 0,
"babel/object-shorthand": 0,
@ -20,8 +32,14 @@
"key-spacing": 0,
"no-extra-boolean-cast": 0,
"no-undef": 1,
"no-unused-vars": 1,
"no-console": 1
"no-unused-vars": [1, {
"vars": "all",
"args": "none",
"varsIgnorePattern": "React|PropTypes|Component"
}],
"no-console": 1,
"react/prop-types": 0,
"meteor/audit-argument-checks": 0
},
"env": {
"browser": true,
@ -32,7 +50,8 @@
},
"plugins": [
"babel",
"meteor"
"meteor",
"react"
],
"settings": {
"import/resolver": "meteor"

View file

@ -1,7 +1,7 @@
/*
The original Newsletter components is defined using an
The original Newsletter components is defined using an
ES6 class, so we use the "class foo extends bar" syntax
to extend it. This way, we can simply redefine the
to extend it. This way, we can simply redefine the
render method to change it, while preserving
all of the class's other methods (other render
functions, event handlers, etc.).
@ -9,7 +9,7 @@ functions, event handlers, etc.).
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, intlShape } from 'react-intl';
import { FormattedMessage /*, intlShape */ } from 'react-intl';
class CustomNewsletter extends Telescope.components.Newsletter {
@ -27,4 +27,4 @@ class CustomNewsletter extends Telescope.components.Newsletter {
}
export default CustomNewsletter;
export default CustomNewsletter;

View file

@ -1,12 +1,12 @@
import Telescope from 'meteor/nova:lib';
import Posts from "meteor/nova:posts";
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, FormattedRelative } from 'react-intl';
import { Button } from 'react-bootstrap';
import moment from 'moment';
import { ModalTrigger } from "meteor/nova:core";
import { Link } from 'react-router';
import Posts from "meteor/nova:posts";
import Categories from "meteor/nova:categories";
// import { Button } from 'react-bootstrap';
// import moment from 'moment';
// import { ModalTrigger } from "meteor/nova:core";
// import Categories from "meteor/nova:categories";
class CustomPostsItem extends Telescope.components.PostsItem {
@ -14,7 +14,7 @@ class CustomPostsItem extends Telescope.components.PostsItem {
const post = this.props.post;
let postClass = "posts-item";
let postClass = "posts-item";
if (post.sticky) postClass += " posts-sticky";
// custom code starts here
@ -25,22 +25,22 @@ class CustomPostsItem extends Telescope.components.PostsItem {
return (
<div className={postClass}>
<div className="posts-item-vote">
<Telescope.components.Vote post={post} />
</div>
{post.thumbnailUrl ? <Telescope.components.PostsThumbnail post={post}/> : null}
<div className="posts-item-content">
<h3 className="posts-item-title">
<Link to={Posts.getLink(post)} className="posts-item-title-link" target={Posts.getLinkTarget(post)}>
{post.title}
</Link>
{this.renderCategories()}
</h3>
<div className="posts-item-meta">
{post.user? <div className="posts-item-user"><Telescope.components.UsersAvatar user={post.user} size="small"/><Telescope.components.UsersName user={post.user}/></div> : null}
<div className="posts-item-date"><FormattedRelative value={post.postedAt}/></div>
@ -56,13 +56,13 @@ class CustomPostsItem extends Telescope.components.PostsItem {
</div>
{this.renderCommenters()}
</div>
)
}
};
}
CustomPostsItem.propTypes = {
post: React.PropTypes.object.isRequired
}
@ -71,4 +71,4 @@ CustomPostsItem.contextTypes = {
currentUser: React.PropTypes.object
};
export default CustomPostsItem;
export default CustomPostsItem;

View file

@ -1,3 +1,4 @@
import { Picker } from 'meteor/meteorhacks:picker';
import { servePostsApi } from './api.js';
// for backwards compatibility's sake, accept a "limit" segment
@ -6,4 +7,4 @@ Picker.route('/api/:limit?', function(params, req, res, next) {
params.query.limit = params.limit;
}
res.end(servePostsApi(params.query));
});
});

View file

@ -1,9 +1,9 @@
import Telescope from 'meteor/nova:lib';
import NovaForm from "meteor/nova:forms";
import Categories from "meteor/nova:categories";
import React, { PropTypes, Component } from 'react';
import { FormattedMessage } from 'react-intl';
import NovaForm from "meteor/nova:forms";
import { DocumentContainer } from "meteor/utilities:react-list-container";
import Categories from "meteor/nova:categories";
// import { DocumentContainer } from "meteor/utilities:react-list-container";
class CategoriesEditForm extends Component{
@ -14,7 +14,7 @@ class CategoriesEditForm extends Component{
deleteCategory() {
const category = this.props.category;
if (window.confirm(`Delete category “${category.name}”?`)) {
if (window.confirm(`Delete category “${category.name}”?`)) {
this.context.actions.call("categories.deleteById", category._id, (error, result) => {
if (error) {
this.context.messages.flash(error.message, "error");
@ -30,7 +30,7 @@ class CategoriesEditForm extends Component{
return (
<div className="categories-edit-form">
<NovaForm
<NovaForm
document={this.props.category}
collection={Categories}
methodName="categories.edit"
@ -57,4 +57,4 @@ CategoriesEditForm.contextTypes = {
};
module.exports = CategoriesEditForm;
export default CategoriesEditForm;
export default CategoriesEditForm;

View file

@ -1,11 +1,11 @@
import Telescope from 'meteor/nova:lib';
import { /* ModalTrigger, */ ContextPasser } from "meteor/nova:core";
import React, { PropTypes, Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { Button, DropdownButton, MenuItem, Modal } from 'react-bootstrap';
import { /* ModalTrigger, */ ContextPasser } from "meteor/nova:core";
import { withRouter } from 'react-router'
import { LinkContainer } from 'react-router-bootstrap';
import Users from 'meteor/nova:users';
// import Users from 'meteor/nova:users';
// note: cannot use ModalTrigger component because of https://github.com/react-bootstrap/react-bootstrap/issues/1808
@ -36,12 +36,12 @@ class CategoriesList extends Component {
}
renderCategoryEditModal(category, index) {
return (
<Modal key={index} show={this.state.openModal === index+1} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title><FormattedMessage id="categories.edit"/></Modal.Title>
</Modal.Header>
</Modal.Header>
<Modal.Body>
<ContextPasser currentUser={this.context.currentUser} messages={this.context.messages} actions={this.context.actions} closeCallback={this.closeModal}>
<Telescope.components.CategoriesEditForm category={category}/>
@ -52,12 +52,12 @@ class CategoriesList extends Component {
}
renderCategoryNewModal() {
return (
<Modal show={this.state.openModal === 0} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title><FormattedMessage id="categories.new"/></Modal.Title>
</Modal.Header>
</Modal.Header>
<Modal.Body>
<ContextPasser currentUser={this.context.currentUser} messages={this.context.messages} closeCallback={this.closeModal}>
<Telescope.components.CategoriesNewForm/>
@ -82,18 +82,18 @@ class CategoriesList extends Component {
}
render() {
const categories = this.props.categories;
const context = this.context;
// const context = this.context;
const currentQuery = _.clone(this.props.router.location.query);
delete currentQuery.cat;
return (
<div>
<DropdownButton
bsStyle="default"
className="categories-list btn-secondary"
title={<FormattedMessage id="categories"/>}
<DropdownButton
bsStyle="default"
className="categories-list btn-secondary"
title={<FormattedMessage id="categories"/>}
id="categories-dropdown"
>
<div className="category-menu-item dropdown-item">
@ -115,7 +115,7 @@ class CategoriesList extends Component {
)
}
};
}
CategoriesList.propTypes = {
categories: React.PropTypes.array
@ -128,4 +128,4 @@ CategoriesList.contextTypes = {
};
module.exports = withRouter(CategoriesList);
export default withRouter(CategoriesList);
export default withRouter(CategoriesList);

View file

@ -1,11 +1,11 @@
import Telescope from 'meteor/nova:lib';
import Users from 'meteor/nova:users';
import React, { PropTypes, Component } from 'react';
import { Button, DropdownButton, MenuItem } from 'react-bootstrap';
import classNames from "classnames";
//import { Messages, ModalTrigger } from 'meteor/nova:core';
import { LinkContainer } from 'react-router-bootstrap';
import { withRouter } from 'react-router'
import Users from 'meteor/nova:users';
import { /* Button, DropdownButton, */ MenuItem } from 'react-bootstrap';
// import classNames from "classnames";
// import { Messages, ModalTrigger } from 'meteor/nova:core';
class Category extends Component {
@ -26,7 +26,7 @@ class Category extends Component {
const {category, index, router} = this.props;
const currentQuery = router.location.query;
// const currentQuery = router.location.query;
const currentCategorySlug = router.location.query.cat;
const newQuery = _.clone(router.location.query);
newQuery.cat = category.slug;
@ -34,9 +34,9 @@ class Category extends Component {
return (
<div className="category-menu-item dropdown-item">
<LinkContainer to={{pathname:"/", query: newQuery}}>
<MenuItem
eventKey={index+1}
key={category._id}
<MenuItem
eventKey={index+1}
key={category._id}
>
{currentCategorySlug === category.slug ? <Telescope.components.Icon name="voted"/> : null}
{category.name}
@ -60,4 +60,4 @@ Category.contextTypes = {
};
module.exports = withRouter(Category);
export default withRouter(Category);
export default withRouter(Category);

View file

@ -1,8 +1,8 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import moment from 'moment';
import { intlShape, FormattedMessage, FormattedRelative } from 'react-intl';
import Users from 'meteor/nova:users';
// import moment from 'moment';
// import Users from 'meteor/nova:users';
class CommentsItem extends Component{
@ -33,7 +33,7 @@ class CommentsItem extends Component{
event.preventDefault();
this.setState({showEdit: true});
}
editCancelCallback(event) {
event.preventDefault();
this.setState({showEdit: false});
@ -44,11 +44,11 @@ class CommentsItem extends Component{
}
deleteComment() {
const comment = this.props.comment;
const deleteConfirmMessage = this.context.intl.formatMessage({id: "comments.delete_confirm"}, {body: Telescope.utils.trimWords(comment.body, 20)});
const deleteSuccessMessage = this.context.intl.formatMessage({id: "comments.delete_success"}, {body: Telescope.utils.trimWords(comment.body, 20)});
if (window.confirm(deleteConfirmMessage)) {
this.context.actions.call('comments.deleteById', comment._id, (error, result) => {
this.context.messages.flash(deleteSuccessMessage, "success");
@ -70,7 +70,7 @@ class CommentsItem extends Component{
<a className="comments-item-reply-link" onClick={this.showReply}>
<Telescope.components.Icon name="reply"/> <FormattedMessage id="comments.reply"/>
</a> : null}
</div>
</div>
)
}
@ -78,12 +78,12 @@ class CommentsItem extends Component{
return (
<div className="comments-item-reply">
<Telescope.components.CommentsNew
postId={this.props.comment.postId}
parentComment={this.props.comment}
successCallback={this.replySuccessCallback}
cancelCallback={this.replyCancelCallback}
type="reply"
<Telescope.components.CommentsNew
postId={this.props.comment.postId}
parentComment={this.props.comment}
successCallback={this.replySuccessCallback}
cancelCallback={this.replyCancelCallback}
type="reply"
/>
</div>
)
@ -92,9 +92,9 @@ class CommentsItem extends Component{
renderEdit() {
return (
<Telescope.components.CommentsEdit
comment={this.props.comment}
successCallback={this.editSuccessCallback}
<Telescope.components.CommentsEdit
comment={this.props.comment}
successCallback={this.editSuccessCallback}
cancelCallback={this.editCancelCallback}
/>
)

View file

@ -1,6 +1,6 @@
import Telescope from 'meteor/nova:lib';
import React from 'react';
import {injectIntl, FormattedMessage} from 'react-intl';
import {/* injectIntl, */ FormattedMessage} from 'react-intl';
const CommentsList = ({results, hasMore, ready, count, totalCount, loadMore}) => {
@ -24,11 +24,11 @@ const CommentsList = ({results, hasMore, ready, count, totalCount, loadMore}) =>
<FormattedMessage id="comments.no_comments"/>
</p>
</div>
)
)
}
};
CommentsList.displayName = "CommentsList";
module.exports = CommentsList;
module.exports = CommentsList;

View file

@ -18,8 +18,8 @@ class CommentsNew extends Component {
return (
<div className="comments-new-form">
<NovaForm
collection={Comments}
<NovaForm
collection={Comments}
methodName="comments.new"
prefilledProps={prefilledProps}
successCallback={this.props.successCallback}
@ -30,7 +30,7 @@ class CommentsNew extends Component {
)
}
};
}
CommentsNew.propTypes = {
postId: React.PropTypes.string.isRequired,
@ -46,4 +46,4 @@ CommentsNew.contextTypes = {
currentUser: React.PropTypes.object
}
module.exports = CommentsNew;
module.exports = CommentsNew;

View file

@ -4,7 +4,7 @@ import React, { PropTypes, Component } from 'react';
class CommentsNode extends Component {
renderComment(comment) {
return (
<Telescope.components.CommentsItem comment={comment} key={comment._id} />
)
@ -22,7 +22,7 @@ class CommentsNode extends Component {
const comment = this.props.comment;
const children = this.props.comment.childrenResults;
return (
<div className="comments-node">
{this.renderComment(comment)}
@ -31,7 +31,7 @@ class CommentsNode extends Component {
)
}
};
}
CommentsNode.propTypes = {
comment: React.PropTypes.object.isRequired, // the current comment
@ -41,4 +41,4 @@ CommentsNode.contextTypes = {
currentUser: React.PropTypes.object, // the current user
};
module.exports = CommentsNode;
module.exports = CommentsNode;

View file

@ -10,10 +10,10 @@ class App extends Component {
}
getChildContext() {
const messages = Telescope.strings[this.getLocale()] || {};
const intlProvider = new IntlProvider({locale: this.getLocale()}, messages);
const {intl} = intlProvider.getChildContext();
return {
@ -29,8 +29,8 @@ class App extends Component {
return (
<IntlProvider locale={this.getLocale()} messages={Telescope.strings[this.getLocale()]}>
{
this.props.ready ?
<Telescope.components.Layout>{this.props.children}</Telescope.components.Layout>
this.props.ready ?
<Telescope.components.Layout>{this.props.children}</Telescope.components.Layout>
: <Telescope.components.AppLoading />
}
</IntlProvider>
@ -56,4 +56,4 @@ App.childContextTypes = {
}
module.exports = AppComposer(App);
export default AppComposer(App);
export default AppComposer(App);

View file

@ -29,7 +29,7 @@ class Newsletter extends Component {
subscribeEmail(data) {
this.context.actions.call("newsletter.addEmail", data.email, (error, result) => {
if (error) {
console.log(error);
console.log(error); // eslint-disable-line
this.context.messages.flash(error.message, "error");
} else {
this.successCallbackSubscription(result);

View file

@ -1,7 +1,7 @@
import React, { PropTypes, Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { Button } from 'react-bootstrap';
import { Messages } from 'meteor/nova:core';
// import { Messages } from 'meteor/nova:core';
import Users from 'meteor/nova:users';
class NewsletterButton extends Component {
@ -15,7 +15,7 @@ class NewsletterButton extends Component {
'newsletter.removeUser' : 'newsletter.addUser';
this.context.actions.call(action, this.props.user, (error, result) => {
if (error) {
console.log(error);
console.log(error); // eslint-disable-line
this.context.messages.flash(error.message, "error");
} else {
this.props.successCallback(result);

View file

@ -1,5 +1,6 @@
import Telescope from 'meteor/nova:lib';
import Users from 'meteor/nova:users';
import { T9n } from 'meteor/softwarerero:accounts-t9n';
// import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions';
// checkNpmVersions({
@ -16,4 +17,4 @@ Users.avatar.setOptions({
});
// https://github.com/softwarerero/meteor-accounts-t9n
T9n.setLanguage(Telescope.settings.get("locale", "en"));
T9n.setLanguage(Telescope.settings.get("locale", "en"));

View file

@ -1,6 +1,6 @@
import Telescope from "meteor/nova:lib";
import React, { PropTypes, Component } from "react";
import { Button } from "react-bootstrap";
// import { Button } from "react-bootstrap";
import moment from "moment";
import { FormattedMessage } from "react-intl";

View file

@ -1,8 +1,8 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { ListContainer } from "meteor/utilities:react-list-container";
import moment from 'moment';
import Posts from "meteor/nova:posts";
import { ListContainer } from "meteor/utilities:react-list-container";
import React, { PropTypes, Component } from 'react';
import moment from 'moment';
class PostsDay extends Component {
@ -19,19 +19,19 @@ class PostsDay extends Component {
listId: `posts.list.${moment(date).format("YYYY-MM-DD")}`
};
({selector, options} = Posts.parameters.get(terms));
const {selector, options} = Posts.parameters.get(terms);
const postsPerPage = Telescope.settings.get("postsPerPage", 10);
return (
<div className="posts-day">
<h4 className="posts-day-heading">{moment(date).format("dddd, MMMM Do YYYY")}</h4>
<ListContainer
collection={Posts}
<ListContainer
collection={Posts}
publication="posts.list"
selector={selector}
options={options}
terms={terms}
terms={terms}
joins={Posts.getJoins()}
component={Telescope.components.PostsList}
componentProps={{showHeader: false}}
@ -51,4 +51,4 @@ PostsDay.propTypes = {
}
module.exports = PostsDay;
export default PostsDay;
export default PostsDay;

View file

@ -1,12 +1,12 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, intlShape } from 'react-intl';
import NovaForm from "meteor/nova:forms";
import { DocumentContainer } from "meteor/utilities:react-list-container";
//import { Messages } from "meteor/nova:core";
//import Actions from "../actions.js";
import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, intlShape } from 'react-intl';
// import { Messages } from "meteor/nova:core";
// import Actions from "../actions.js";
// import Users from 'meteor/nova:users';
class PostsEditForm extends Component{
@ -20,7 +20,7 @@ class PostsEditForm extends Component{
const deletePostConfirm = this.context.intl.formatMessage({id: "posts.delete_confirm"}, {title: post.title});
const deletePostSuccess = this.context.intl.formatMessage({id: "posts.delete_success"}, {title: post.title});
if (window.confirm(deletePostConfirm)) {
if (window.confirm(deletePostConfirm)) {
this.context.actions.call('posts.remove', post._id, (error, result) => {
this.context.messages.flash(deletePostSuccess, "success");
this.context.events.track("post deleted", {'_id': post._id});
@ -41,13 +41,13 @@ class PostsEditForm extends Component{
render() {
return (
<div className="posts-edit-form">
{this.renderAdminArea()}
<DocumentContainer
collection={Posts}
publication="posts.single"
<DocumentContainer
collection={Posts}
publication="posts.single"
selector={{_id: this.props.post._id}}
terms={{_id: this.props.post._id}}
joins={Posts.getJoins()}
@ -57,7 +57,7 @@ class PostsEditForm extends Component{
collection: Posts,
currentUser: this.context.currentUser,
methodName: "posts.edit",
successCallback: (post) => {
successCallback: (post) => {
this.context.messages.flash(this.context.intl.formatMessage({id: "posts.edit_success"}, {title: post.title}), 'success')
}
}}
@ -82,4 +82,4 @@ PostsEditForm.contextTypes = {
}
module.exports = PostsEditForm;
export default PostsEditForm;
export default PostsEditForm;

View file

@ -1,6 +1,6 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { ListContainer, DocumentContainer } from "meteor/utilities:react-list-container";
import { ListContainer /* , DocumentContainer */ } from "meteor/utilities:react-list-container";
import Posts from "meteor/nova:posts";
class PostsHome extends Component {
@ -8,19 +8,19 @@ class PostsHome extends Component {
getDefaultView() {
return {view: 'top'}
}
render() {
const params = {...this.getDefaultView(), ...this.props.location.query, listId: "posts.list.main"};
const {selector, options} = Posts.parameters.get(params);
return (
<ListContainer
collection={Posts}
<ListContainer
collection={Posts}
publication="posts.list"
selector={selector}
options={options}
terms={params}
terms={params}
joins={Posts.getJoins()}
component={Telescope.components.PostsList}
cacheSubscription={true}
@ -29,6 +29,6 @@ class PostsHome extends Component {
/>
)
}
};
}
module.exports = PostsHome;
module.exports = PostsHome;

View file

@ -1,12 +1,12 @@
import Telescope from 'meteor/nova:lib';
import { ModalTrigger } from "meteor/nova:core";
import Posts from "meteor/nova:posts";
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, FormattedRelative } from 'react-intl';
import { Button } from 'react-bootstrap';
import moment from 'moment';
import { ModalTrigger } from "meteor/nova:core";
import { Link } from 'react-router';
import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
// import { Button } from 'react-bootstrap';
// import moment from 'moment';
// import Users from 'meteor/nova:users';
class PostsItem extends Component {
@ -32,12 +32,12 @@ class PostsItem extends Component {
</div>
)
}
render() {
const post = this.props.post;
let postClass = "posts-item";
let postClass = "posts-item";
if (post.sticky) postClass += " posts-sticky";
// console.log(post)
@ -45,22 +45,22 @@ class PostsItem extends Component {
return (
<div className={postClass}>
<div className="posts-item-vote">
<Telescope.components.Vote post={post} />
</div>
{post.thumbnailUrl ? <Telescope.components.PostsThumbnail post={post}/> : null}
<div className="posts-item-content">
<h3 className="posts-item-title">
<Link to={Posts.getLink(post)} className="posts-item-title-link" target={Posts.getLinkTarget(post)}>
{post.title}
</Link>
{this.renderCategories()}
</h3>
<div className="posts-item-meta">
{post.user? <div className="posts-item-user"><Telescope.components.UsersAvatar user={post.user} size="small"/><Telescope.components.UsersName user={post.user}/></div> : null}
<div className="posts-item-date">{post.postedAt ? <FormattedRelative value={post.postedAt}/> : <FormattedMessage id="posts.dateNotDefined"/>}</div>
@ -76,13 +76,13 @@ class PostsItem extends Component {
</div>
{this.renderCommenters()}
</div>
)
}
};
}
PostsItem.propTypes = {
post: React.PropTypes.object.isRequired
}
@ -92,4 +92,4 @@ PostsItem.contextTypes = {
};
module.exports = PostsItem;
export default PostsItem;
export default PostsItem;

View file

@ -1,6 +1,6 @@
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, intlShape } from 'react-intl';
import { Button, ButtonGroup, DropdownButton, MenuItem } from 'react-bootstrap';
import { /* Button, ButtonGroup, */ DropdownButton, MenuItem } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
import { withRouter } from 'react-router'
import Users from 'meteor/nova:users';
@ -9,7 +9,7 @@ const PostsViews = (props, context) => {
let views = ["top", "new", "best"];
const adminViews = ["pending", "rejected", "scheduled"];
if (Users.canDo(context.currentUser, "posts.edit.all")) {
views = views.concat(adminViews);
}
@ -18,13 +18,13 @@ const PostsViews = (props, context) => {
return (
<div className="posts-views">
<DropdownButton
bsStyle="default"
className="views btn-secondary"
title={context.intl.formatMessage({id: "posts.view"})}
<DropdownButton
bsStyle="default"
className="views btn-secondary"
title={context.intl.formatMessage({id: "posts.view"})}
id="views-dropdown"
>
{views.map(view =>
{views.map(view =>
<LinkContainer key={view} to={{pathname: "/", query: {...query, view: view}}} /*to={}*/ className="dropdown-item">
<MenuItem>
<FormattedMessage id={"posts."+view}/>

View file

@ -5,7 +5,7 @@ import { Accounts } from 'meteor/std:accounts-ui';
const UsersAccountForm = () => {
return (
<Accounts.ui.LoginForm />
)
)
};
module.exports = UsersAccountForm;
@ -23,12 +23,12 @@ class AccountsButton extends Accounts.ui.Button {
render () {
const {label, href, type, disabled, className, onClick} = this.props;
if (type === 'link') {
return <a href={ href } className={ className } onClick={ onClick }>{ label }</a>;
return <a href={ href } className={ className } onClick={ onClick }>{ label }</a>;
}
return <Button
return <Button
bsStyle="primary"
className={ className }
type={ type } 
type={ type }
disabled={ disabled }
onClick={ onClick }>{ label }
</Button>;
@ -44,13 +44,13 @@ class AccountsField extends Accounts.ui.Field {
onChange({ target: { value: this.input.value } })
}
}
render() {
const { id, hint, label, type = 'text', onChange, className = "field", defaultValue = "" } = this.props;
const { id, hint, /* label, */ type = 'text', onChange, className = "field", defaultValue = "" } = this.props;
const { mount = true } = this.state;
return mount ? (
<div className={ className }>
<FormControl id={ id } type={ type } onChange={ onChange } placeholder={ hint } defaultValue={ defaultValue } />
<FormControl id={ id } type={ type } onChange={ onChange } placeholder={ hint } defaultValue={ defaultValue } />
</div>
) : null;
}
@ -99,4 +99,4 @@ class AccountsField extends Accounts.ui.Field {
Accounts.ui.Button = AccountsButton;
Accounts.ui.Field = AccountsField;
// Accounts.ui.SocialButtons = AccountsSocialButtons;
// Accounts.ui.PasswordOrService = AccountsPasswordOrService;
// Accounts.ui.PasswordOrService = AccountsPasswordOrService;

View file

@ -1,7 +1,7 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { Dropdown, Button } from 'react-bootstrap';
import { Dropdown /* , Button */ } from 'react-bootstrap';
const UsersAccountMenu = () => {
@ -14,10 +14,10 @@ const UsersAccountMenu = () => {
<Telescope.components.UsersAccountForm />
</Dropdown.Menu>
</Dropdown>
)
)
};
UsersAccountMenu.displayName = "UsersAccountMenu";
module.exports = UsersAccountMenu;
export default UsersAccountMenu;
export default UsersAccountMenu;

View file

@ -1,7 +1,7 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage, intlShape } from 'react-intl';
import { Row, Col } from 'react-bootstrap';
// import { Row, Col } from 'react-bootstrap';
import NovaForm from "meteor/nova:forms";
//import { Messages } from "meteor/nova:core";
import Users from 'meteor/nova:users';
@ -9,21 +9,21 @@ import Users from 'meteor/nova:users';
const UsersEdit = (props, context) => {
const user = props.user;
const currentUser = props.currentUser;
// const currentUser = props.currentUser;
//const label = `Edit profile for ${Users.getDisplayName(user)}`;
return (
<Telescope.components.CanDo
<Telescope.components.CanDo
action="users.edit"
document={user}
displayNoPermissionMessage={true}
>
<div className="page users-edit-form">
<h2 className="page-title users-edit-form-title"><FormattedMessage id="users.edit_account"/></h2>
<NovaForm
collection={Users}
document={user}
<NovaForm
collection={Users}
document={user}
methodName="users.edit"
successCallback={(user)=>{
context.messages.flash(context.intl.formatMessage({id: "users.edit_success"}, {name: Users.getDisplayName(user)}), 'success')
@ -34,7 +34,7 @@ const UsersEdit = (props, context) => {
)
};
UsersEdit.propTypes = {
user: React.PropTypes.object.isRequired,
};
@ -48,4 +48,4 @@ UsersEdit.contextTypes = {
UsersEdit.displayName = "UsersEdit";
module.exports = UsersEdit;
export default UsersEdit;
export default UsersEdit;

View file

@ -1,5 +1,6 @@
import React, { Component } from 'react';
import { Accounts, STATES } from 'meteor/std:accounts-ui';
import { T9n } from 'meteor/softwarerero:accounts-t9n';
import React, { Component } from 'react';
import { Link } from 'react-router';
class UsersResetPassword extends Component {

View file

@ -1,16 +1,16 @@
import Telescope from 'meteor/nova:lib';
import React from 'react';
import {mount} from 'react-mounter';
import { Messages } from 'meteor/nova:core';
import { IndexRoute, Route, useRouterHistory, browserHistory, createMemoryHistory } from 'react-router';
import { ReactRouterSSR } from 'meteor/reactrouter:react-router-ssr';
import { ListContainer, DocumentContainer } from "meteor/utilities:react-list-container";
// import useNamedRoutes from 'use-named-routes';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import Events from "meteor/nova:events";
import { ReactRouterSSR } from 'meteor/reactrouter:react-router-ssr';
import React from 'react';
import Helmet from 'react-helmet';
import Cookie from 'react-cookie';
import ReactDOM from 'react-dom';
// import {mount} from 'react-mounter';
// import { IndexRoute, Route, useRouterHistory, browserHistory, createMemoryHistory } from 'react-router';
// import { ListContainer, DocumentContainer } from "meteor/utilities:react-list-container";
// import useNamedRoutes from 'use-named-routes';
// import createBrowserHistory from 'history/lib/createBrowserHistory';
Telescope.routes.indexRoute = { name: "posts.list", component: Telescope.components.PostsHome };
@ -33,13 +33,13 @@ Meteor.startup(() => {
childRoutes: Telescope.routes.routes
}
let history;
// let history;
const clientOptions = {
renderHook: ReactDOM.render,
props: {
onUpdate: () => {
Events.analyticsRequest();
Events.analyticsRequest();
Messages.clearSeen();
}
}
@ -48,15 +48,15 @@ Meteor.startup(() => {
const serverOptions = {
htmlHook: (html) => {
const head = Helmet.rewind();
return html.replace('<head>', '<head>'+ head.title + head.meta + head.link);
return html.replace('<head>', '<head>'+ head.title + head.meta + head.link);
},
preRender: (req, res) => {
Cookie.plugToRequest(req, res);
},
};
ReactRouterSSR.Run(AppRoutes, clientOptions, serverOptions);
// note: we did like this at first
// if (Meteor.isClient) {
// history = useNamedRoutes(useRouterHistory(createBrowserHistory))({ routes: AppRoutes });
@ -66,4 +66,4 @@ Meteor.startup(() => {
// }
// ReactRouterSSR.Run(AppRoutes, {historyHook: () => history}, {historyHook: () => history});
});
});

View file

@ -18,7 +18,8 @@ Categories.getParents = function (category) {
categoriesArray.push(parent);
recurse(parent);
}
}(category);
};
getParents(category);
return categoriesArray;
};
@ -37,7 +38,8 @@ Categories.getChildren = function (category) {
categoriesArray = categoriesArray.concat(children);
recurse(children);
}
}([category]);
};
getChildren([category]);
return categoriesArray;
};

View file

@ -1,6 +1,7 @@
import Telescope from 'meteor/nova:lib';
import Categories from "./collection.js";
import Users from 'meteor/nova:users';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
const canInsert = user => Users.canDo(user, "categories.new");
const canEdit = user => Users.canDo(user, "categories.edit.all");
@ -79,7 +80,7 @@ Telescope.settings.collection.addField([
optional: true,
form: {
group: 'categories',
instructions: 'Let users filter by one or multiple categories at a time.',
instructions: 'Let users filter by one or multiple categories at a time.',
options: function () {
return [
{value: "single", label: "categories_behavior_one_at_a_time"},
@ -100,4 +101,4 @@ Telescope.settings.collection.addField([
}
}
}
]);
]);

View file

@ -19,7 +19,7 @@ if (Meteor.settings && Meteor.settings.categories) {
} else {
// if not, create it
Categories.insert(category);
console.log(`// Creating category “${category.name}`);
console.log(`// Creating category “${category.name}`); // eslint-disable-line
}
});
}

View file

@ -1,14 +1,16 @@
import Posts from "meteor/nova:posts";
// import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
import Categories from "../collection.js";
Meteor.publish('categories', function() {
const currentUser = this.userId && Users.findOne(this.userId);
if(Users.canDo(currentUser, "posts.view.approved.all")){
var categories = Categories.find({}, {fields: Categories.publishedFields.list});
/*
var publication = this;
categories.forEach(function (category) {
@ -17,8 +19,9 @@ Meteor.publish('categories', function() {
var cursor = Posts.find({$and: [{categories: {$in: categoryIds}}, {status: Posts.config.STATUS_APPROVED}]});
// Counts.publish(publication, category.getCounterName(), cursor, { noReady: true });
});
*/
return categories;
}
return [];
});
});

View file

@ -1,3 +1,4 @@
import Telescope from 'meteor/nova:lib';
import Posts from "meteor/nova:posts";
import PublicationUtils from 'meteor/utilities:smart-publications';
@ -20,7 +21,7 @@ Posts.addField([
]);
if (typeof Settings !== "undefined") {
Settings.addField([
Telescope.settings.collection.addField([
{
fieldName: 'cloudinaryCloudName',
fieldSchema: {

View file

@ -14,7 +14,7 @@ Cloudinary.config({
});
const CloudinaryUtils = {
// send an image URL to Cloudinary and get a cloudinary result object in return
uploadImage(imageUrl) {
try {
@ -26,8 +26,8 @@ const CloudinaryUtils = {
};
return data;
} catch (error) {
console.log("// Cloudinary upload failed for URL: "+imageUrl);
console.log(error.stack);
console.log("// Cloudinary upload failed for URL: "+imageUrl); // eslint-disable-line
console.log(error.stack); // eslint-disable-line
}
},
@ -35,8 +35,8 @@ const CloudinaryUtils = {
getUrls(cloudinaryId) {
return Telescope.settings.get("cloudinaryFormats").map(format => {
const url = Cloudinary.url(cloudinaryId, {
width: format.width,
height: format.height,
width: format.width,
height: format.height,
crop: 'fill',
sign_url: true,
fetch_format: "auto",
@ -56,7 +56,7 @@ Meteor.methods({
if (Users.isAdmin(Meteor.user())) {
thumbnailUrl = typeof thumbnailUrl === "undefined" ? "http://www.telescopeapp.org/images/logo.png" : thumbnailUrl;
const data = CloudinaryUtils.uploadImage(thumbnailUrl);
console.log(data);
console.log(data); // eslint-disable-line
}
},
cachePostThumbnails: function (limit = 20) {
@ -71,16 +71,16 @@ Meteor.methods({
postsWithUncachedThumbnails.forEach(Meteor.bindEnvironment((post, index) => {
Meteor.setTimeout(function () {
console.log(`// ${index}. Caching thumbnail for post “${post.title}” (_id: ${post._id})`);
console.log(`// ${index}. Caching thumbnail for post “${post.title}” (_id: ${post._id})`); // eslint-disable-line
const data = CloudinaryUtils.uploadImage(post.thumbnailUrl);
Posts.update(post._id, {$set:{
cloudinaryId: data.cloudinaryId,
cloudinaryUrls: data.urls
}});
}, index * 1000);
}));
}
}
@ -106,7 +106,7 @@ Telescope.callbacks.add("posts.new.async", cachePostThumbnailOnSubmit);
function cachePostThumbnailOnEdit (newPost, oldPost) {
if (Telescope.settings.get("cloudinaryAPIKey")) {
if (newPost.thumbnailUrl && newPost.thumbnailUrl !== oldPost.thumbnailUrl) {
const data = CloudinaryUtils.uploadImage(newPost.thumbnailUrl);
Posts.update(newPost._id, {$set:{
cloudinaryId: data.cloudinaryId,
@ -118,4 +118,4 @@ function cachePostThumbnailOnEdit (newPost, oldPost) {
}
Telescope.callbacks.add("posts.edit.async", cachePostThumbnailOnEdit);
export default CloudinaryUtils;
export default CloudinaryUtils;

View file

@ -232,7 +232,7 @@ function CommentsNewNotifications (comment) {
}
}
}
}
}
@ -278,7 +278,7 @@ Telescope.callbacks.add("comments.edit.method", CommentsEditSubmittedPropertiesC
function UsersRemoveDeleteComments (user, options) {
if (options && options.deleteComments) {
Comments.remove({userId: userId});
Comments.remove({userId: user._id});
} else {
// not sure if anything should be done in that scenario yet
// Comments.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});

View file

@ -2,6 +2,6 @@
* @summary The global namespace for Comments.
* @namespace Comments
*/
Comments = new Mongo.Collection("comments");
const Comments = new Mongo.Collection("comments");
export default Comments;
export default Comments;

View file

@ -1,6 +1,6 @@
import PublicationUtils from 'meteor/utilities:smart-publications';
import Posts from "meteor/nova:posts";
import Users from "meteor/nova:users";
import Posts from 'meteor/nova:posts';
import Users from 'meteor/nova:users';
Posts.addField([
/**

View file

@ -1,4 +1,4 @@
import Telescope from 'meteor/nova:lib';
// import Telescope from 'meteor/nova:lib';
import Comments from './collection.js';
import Posts from 'meteor/nova:posts';
import Users from 'meteor/nova:users';

View file

@ -1,6 +1,6 @@
import Comments from './collection.js';
import PublicationsUtils from 'meteor/utilities:smart-publications';
import Posts from "meteor/nova:posts";
// import Posts from "meteor/nova:posts";
Comments.publishedFields = {};
@ -26,4 +26,4 @@ Comments.publishedFields.list = PublicationsUtils.arrayToFields([
* @summary Specify which fields should be published by the posts.single publication
* @array Posts.publishedFields.single
*/
Comments.publishedFields.single = PublicationsUtils.arrayToFields(Comments.getPublishedFields());
Comments.publishedFields.single = PublicationsUtils.arrayToFields(Comments.getPublishedFields());

View file

@ -1,7 +1,7 @@
import Telescope from 'meteor/nova:lib';
import Comments from './collection.js';
import Users from 'meteor/nova:users';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import Comments from './collection.js';
// check if user can create a new comment
const canInsert = user => Users.canDo(user, "comments.new");
@ -10,7 +10,7 @@ const canInsert = user => Users.canDo(user, "comments.new");
const canEdit = Users.canEdit;
// check if user can edit *all* comments
const canEditAll = user => Users.canDo(user, "comments.edit.all");
// const canEditAll = user => Users.canDo(user, "comments.edit.all");
/**
* @summary Comments schema
@ -126,7 +126,7 @@ Comments.schema = new SimpleSchema({
}
},
/**
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.
*/
isDeleted: {
type: Boolean,

View file

@ -1,5 +1,6 @@
import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
import Comments from '../collection.js';
Comments._ensureIndex({postId: 1});
Comments._ensureIndex({parentCommentId: 1});
@ -9,11 +10,11 @@ Comments._ensureIndex({parentCommentId: 1});
* @param {Object} terms
*/
Meteor.publish('comments.list', function (terms) {
const currentUser = this.userId && Users.findOne(this.userId);
terms.currentUserId = this.userId; // add currentUserId to terms
({selector, options} = Comments.parameters.get(terms));
const {selector, options} = Comments.parameters.get(terms);
// commenting this because of FR-SSR issue
// Counts.publish(this, 'comments.list', Comments.find(selector, options));
@ -41,12 +42,12 @@ Meteor.publish('comments.list', function (terms) {
// check(terms, {_id: String});
//
//
// let commentIds = [terms._id];
// const childCommentIds = _.pluck(Comments.find({parentCommentId: terms._id}, {fields: {_id: 1}}).fetch(), '_id');
// commentIds = commentIds.concat(childCommentIds);
// return Users.canView(currentUser) ? Comments.find({_id: {$in: commentIds}}, {sort: {score: -1, postedAt: -1}}) : [];
// });
@ -60,7 +61,7 @@ Meteor.publish('comments.list', function (terms) {
// check(commentId, String);
//
//
// if(Users.canViewById(this.userId)){
// var comment = Comments.findOne(commentId);
@ -75,8 +76,8 @@ Meteor.publish('comments.list', function (terms) {
// check(commentId, String);
//
//
// var userIds = [];
// if(Users.canViewById(this.userId)){
@ -92,11 +93,11 @@ Meteor.publish('comments.list', function (terms) {
// }
// return Users.find({_id: {$in: userIds}}, {fields: Users.pubsub.publicProperties});
// }
// }
// return [];
// });
// });

View file

@ -1,4 +1,4 @@
import Telescope from 'meteor/nova:lib';
// import Telescope from 'meteor/nova:lib';
/**
* @summary Update an item's (post or comment) score
@ -7,6 +7,8 @@ import Telescope from 'meteor/nova:lib';
* @param {object} collection - The collection the item belongs to
* @param {string} operation - The operation being performed
*/
/*
function updateScore (item, user, collection, operation) {
Telescope.updateScore({collection: collection, item: item, forceUpdate: true});
}
@ -14,6 +16,7 @@ Telescope.callbacks.add("upvote.async", updateScore);
Telescope.callbacks.add("downvote.async", updateScore);
Telescope.callbacks.add("cancelUpvote.async", updateScore);
Telescope.callbacks.add("cancelDownvote.async", updateScore);
*/
/**
* @summary Update the profile of the user doing the operation
@ -22,6 +25,8 @@ Telescope.callbacks.add("cancelDownvote.async", updateScore);
* @param {object} collection - The collection the item belongs to
* @param {string} operation - The operation being performed
*/
/*
function updateUser (item, user, collection, operation) {
var update = {};
@ -39,10 +44,10 @@ function updateUser (item, user, collection, operation) {
case "downvote":
update.$addToSet = {'telescope.downvotedPosts': vote};
break;
case "cancelUpvote":
case "cancelUpvote":
update.$pull = {'telescope.upvotedPosts': {itemId: item._id}};
break;
case "cancelDownvote":
case "cancelDownvote":
update.$pull = {'telescope.downvotedPosts': {itemId: item._id}};
break;
}
@ -54,6 +59,7 @@ Telescope.callbacks.add("upvote.async", updateUser);
Telescope.callbacks.add("downvote.async", updateUser);
Telescope.callbacks.add("cancelUpvote.async", updateUser);
Telescope.callbacks.add("cancelDownvote.async", updateUser);
*/
/**
* @summary Update the karma of the item's owner
@ -62,11 +68,13 @@ Telescope.callbacks.add("cancelDownvote.async", updateUser);
* @param {object} collection - The collection the item belongs to
* @param {string} operation - The operation being performed
*/
/*
function updateKarma (item, user, collection, operation) {
var votePower = Telescope.getVotePower(user);
var karmaAmount = (operation === "upvote" || operation === "cancelDownvote") ? votePower : -votePower;
// only update karma is the operation isn't done by the item's author
if (item.userId !== user._id) {
Users.update({_id: item.userId}, {$inc: {"telescope.karma": karmaAmount}});
@ -76,4 +84,5 @@ function updateKarma (item, user, collection, operation) {
Telescope.callbacks.add("upvote.async", updateKarma);
Telescope.callbacks.add("downvote.async", updateKarma);
Telescope.callbacks.add("cancelUpvote.async", updateKarma);
Telescope.callbacks.add("cancelDownvote.async", updateKarma);
Telescope.callbacks.add("cancelDownvote.async", updateKarma);
*/

View file

@ -48,7 +48,7 @@ class ModalTrigger extends Component {
<Modal bsSize={this.props.size} show={this.state.modalIsOpen} onHide={this.closeModal}>
{this.props.title ? this.renderHeader() : null}
<Modal.Body>
<ContextPasser
<ContextPasser
currentUser={this.context.currentUser}
actions={this.context.actions}
events={this.context.events}
@ -62,7 +62,7 @@ class ModalTrigger extends Component {
</div>
)
}
};
}
ModalTrigger.propTypes = {
component: React.PropTypes.object.isRequired,
@ -86,4 +86,4 @@ ModalTrigger.contextTypes = {
// }
module.exports = ModalTrigger;
export default ModalTrigger;
export default ModalTrigger;

View file

@ -1,6 +1,7 @@
import Telescope from 'meteor/nova:lib';
import {Inject} from 'meteor/meteorhacks:inject-initial';
import Events from "meteor/nova:events";
import { Inject } from 'meteor/meteorhacks:inject-initial';
import { SyncedCron } from 'meteor/percolatestudio:synced-cron';
Meteor.startup(function () {
Events.log({
@ -20,4 +21,4 @@ Meteor.startup(function() {
}
});
Inject.obj('serverTimezoneOffset', {offset: new Date().getTimezoneOffset()});
Inject.obj('serverTimezoneOffset', {offset: new Date().getTimezoneOffset()});

View file

@ -1,6 +1,6 @@
import React from 'react';
import Posts from "meteor/nova:posts";
import Comments from "meteor/nova:comments";
// import Posts from "meteor/nova:posts";
// import Comments from "meteor/nova:comments";
import Users from 'meteor/nova:users';
const Group = ({name, actions}) => {
@ -32,11 +32,11 @@ const Groups = props => {
</table>
</div>
</div>
)
}
module.exports = Groups
export default Groups
export default Groups

View file

@ -1,3 +1,5 @@
/* eslint-disable no-undef */
import TelescopeImport from 'meteor/nova:lib';
import PostsImport from "meteor/nova:posts";
import CommentsImport from "meteor/nova:comments";

View file

@ -4,14 +4,14 @@ import Users from 'meteor/nova:users';
Meteor.methods({
"email.test": function (emailName) {
const email = NovaEmail.emails[emailName];
if(Users.isAdminById(this.userId)){
console.log("// testing email ["+emailName+"]");
console.log("// testing email ["+emailName+"]"); // eslint-disable-line
let html, properties;
// if email has a custom way of generating its HTML, use it
if (typeof email.getTestHTML !== "undefined") {
@ -33,11 +33,11 @@ Meteor.methods({
const subject = "[Test] " + email.subject.bind(email)(properties);
NovaEmail.send (Telescope.settings.get('defaultEmail'), subject, html)
return subject;
} else {
throw new Meteor.Error("must_be_admin", "You must be an admin to send test emails");
}
}
});
});

View file

@ -1,10 +1,13 @@
/* global Movies:true */
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import {mount} from 'react-mounter';
import MoviesWrapper from './demo-components.jsx';
import Core from 'meteor/nova:core';
import { Route } from 'react-router';
import Users from 'meteor/nova:users';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import React, { PropTypes, Component } from 'react';
import MoviesWrapper from './demo-components.jsx';
// import {mount} from 'react-mounter';
// import Core from 'meteor/nova:core';
// import { Route } from 'react-router';
//////////////////////////////////////////////////////
// Collection & Schema //

View file

@ -1,10 +1,12 @@
/* global Movies */
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { ListContainer } from "meteor/utilities:react-list-container";
import NovaForm from "meteor/nova:forms";
import { Button } from 'react-bootstrap';
import { Accounts } from 'meteor/std:accounts-ui';
import { ModalTrigger, Messages, FlashContainer } from "meteor/nova:core";
import { ModalTrigger, /* Messages, */ FlashContainer } from "meteor/nova:core";
const FlashMessages = Telescope.components.FlashMessages;
@ -24,8 +26,8 @@ class MoviesWrapper extends Component {
<FlashContainer component={FlashMessages}/>
<div className="main">
<ListContainer
collection={Movies}
<ListContainer
collection={Movies}
publication="movies.list"
terms={{options: {sort: {createdAt: -1}}}}
options={{sort: {createdAt: -1}}}
@ -48,23 +50,23 @@ class MoviesWrapper extends Component {
class MoviesList extends Component {
renderNew() {
const component = (
<div className="add-movie">
<ModalTrigger
title="Add Movie"
<ModalTrigger
title="Add Movie"
component={<Button bsStyle="primary">Add Movie</Button>}
>
<NovaForm
collection={Movies}
methodName="movies.create"
<NovaForm
collection={Movies}
methodName="movies.create"
currentUser={this.props.currentUser}
/>
</ModalTrigger>
<hr/>
</div>
)
return !!this.props.currentUser ? component : "";
}
@ -78,7 +80,7 @@ class MoviesList extends Component {
</div>
)
}
};
}
//////////////////////////////////////////////////////
// Movie //
@ -91,14 +93,14 @@ class Movie extends Component {
const movie = this.props;
const component = (
<ModalTrigger
label="Edit Movie"
component={<Button bsStyle="primary">Edit Movie</Button>}
<ModalTrigger
label="Edit Movie"
component={<Button bsStyle="primary">Edit Movie</Button>}
>
<NovaForm
collection={Movies}
currentUser={this.props.currentUser}
document={movie}
<NovaForm
collection={Movies}
currentUser={this.props.currentUser}
document={movie}
methodName="movies.edit"
/>
</ModalTrigger>
@ -112,7 +114,7 @@ class Movie extends Component {
}
render() {
const movie = this.props;
return (
@ -124,8 +126,8 @@ class Movie extends Component {
)
}
};
}
const LoadMore = props => <a href="#" className="load-more button button--primary" onClick={props.loadMore}>Load More ({props.count}/{props.totalCount})</a>
export default MoviesWrapper
export default MoviesWrapper

View file

@ -1,3 +1,5 @@
import { Picker } from 'meteor/meteorhacks:picker';
import NovaEmail from 'meteor/nova:email';
Meteor.startup(function () {
@ -29,7 +31,7 @@ Meteor.startup(function () {
// return html
res.end(html);
});
// raw template
@ -38,5 +40,5 @@ Meteor.startup(function () {
});
});
});
});

View file

@ -77,10 +77,10 @@ NovaEmail.send = function(to, subject, html, text){
});
}
console.log('//////// sending email…');
console.log('from: '+from);
console.log('to: '+to);
console.log('subject: '+subject);
console.log('//////// sending email…'); // eslint-disable-line
console.log('from: '+from); // eslint-disable-line
console.log('to: '+to); // eslint-disable-line
console.log('subject: '+subject); // eslint-disable-line
// console.log('html: '+html);
// console.log('text: '+text);
@ -95,8 +95,8 @@ NovaEmail.send = function(to, subject, html, text){
try {
Email.send(email);
} catch (error) {
console.log("// error while sending email:")
console.log(error)
console.log("// error while sending email:"); // eslint-disable-line
console.log(error); // eslint-disable-line
}
return email;

View file

@ -24,16 +24,16 @@ class EmbedlyURL extends Component {
// the URL has changed, get a new thumbnail
this.context.actions.call("getEmbedlyData", url, (error, result) => {
console.log("querying Embedly…");
console.log("querying Embedly…"); // eslint-disable-line
this.setState({loading: false});
if (error) {
console.log(error)
console.log(error); // eslint-disable-line
this.context.throwError({content: error.message, type: "error"});
} else {
console.log(result)
console.log(result); // eslint-disable-line
this.context.addToAutofilledValues({
title: result.title,
body: result.description,
@ -46,7 +46,7 @@ class EmbedlyURL extends Component {
}
render() {
const Loading = Telescope.components.Loading;
const wrapperStyle = {
@ -61,16 +61,16 @@ class EmbedlyURL extends Component {
};
loadingStyle.display = this.state.loading ? "block" : "none";
// see https://facebook.github.io/react/warnings/unknown-prop.html
const {document, updateCurrentValue, control, ...rest} = this.props;
const {document, updateCurrentValue, control, ...rest} = this.props; // eslint-disable-line
return (
<div className="embedly-url-field" style={wrapperStyle}>
<Input
<Input
{...rest}
onBlur={this.handleBlur}
type="text"
onBlur={this.handleBlur}
type="text"
ref={ref => this.input = ref}
/>
<div className="embedly-url-field-loading" style={loadingStyle}>
@ -93,4 +93,4 @@ EmbedlyURL.contextTypes = {
actions: React.PropTypes.object,
}
export default EmbedlyURL;
export default EmbedlyURL;

View file

@ -1,7 +1,7 @@
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { FormattedMessage } from 'react-intl';
import Formsy from 'formsy-react';
// import Formsy from 'formsy-react';
import FRC from 'formsy-react-components';
const Input = FRC.Input;
@ -29,9 +29,9 @@ class ThumbnailURL extends Component {
renderThumbnail() {
return (
<div>
<img
className="embedly-thumbnail"
src={this.props.value}
<img
className="embedly-thumbnail"
src={this.props.value}
style={{
"width": 150,
"height": Telescope.settings.get('thumbnailHeight', 150) * 150 / Telescope.settings.get('thumbnailWidth', 150)
@ -44,7 +44,7 @@ class ThumbnailURL extends Component {
render() {
const {name, value, label} = this.props;
const {name, /* value, */ label} = this.props;
const inputType = this.state.showInput ? "text" : "hidden";
@ -73,4 +73,4 @@ ThumbnailURL.contextTypes = {
deleteValue: React.PropTypes.func
}
export default ThumbnailURL;
export default ThumbnailURL;

View file

@ -10,7 +10,7 @@ Telescope.callbacks.add("postClass", addThumbnailClass);
function checkIfPreviouslyPosted (data) {
Meteor.call("checkForDuplicates", data.url, function (error, result) {
if (error) {
Messages.flash(error.reason + '. <a href="'+FlowRouter.path("postPage", {_id: error.details})+'">'+"go_to_post"+'</a>');
// Messages.flash(error.reason + '. <a href="'+FlowRouter.path("postPage", {_id: error.details})+'">'+"go_to_post"+'</a>');
}
});
return data;

View file

@ -2,8 +2,8 @@ import Telescope from 'meteor/nova:lib';
import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
getEmbedlyData = function (url) {
var data = {};
var getEmbedlyData = function (url) {
// var data = {};
var extractBase = 'http://api.embed.ly/1/extract';
var embedlyKey = Telescope.settings.get('embedlyKey');
var thumbnailWidth = Telescope.settings.get('thumbnailWidth', 200);
@ -11,7 +11,7 @@ getEmbedlyData = function (url) {
if(!embedlyKey) {
// fail silently to still let the post be submitted as usual
console.log("Couldn't find an Embedly API key! Please add it to your Telescope settings or remove the Embedly module.");
console.log("Couldn't find an Embedly API key! Please add it to your Telescope settings or remove the Embedly module."); // eslint-disable-line
return null;
}
@ -42,7 +42,7 @@ getEmbedlyData = function (url) {
return embedlyData;
} catch (error) {
console.log(error)
console.log(error); // eslint-disable-line
// the first 13 characters of the Embedly errors are "failed [400] ", so remove them and parse the rest
var errorObject = JSON.parse(error.message.substring(13));
throw new Meteor.Error(errorObject.error_code, errorObject.error_message);
@ -111,7 +111,7 @@ var regenerateThumbnail = function (post) {
Meteor.methods({
testGetEmbedlyData: function (url) {
check(url, String);
console.log(getEmbedlyData(url));
console.log(getEmbedlyData(url)); // eslint-disable-line
},
getEmbedlyData: function (url) {
check(url, String);
@ -129,11 +129,11 @@ Meteor.methods({
generateThumbnails: function (limit = 20, mode = "generate") {
// mode = "generate" : generate thumbnails only for all posts that don't have one
// mode = "all" : regenerate thumbnais for all posts
if (Users.isAdmin(Meteor.user())) {
console.log("// Generating thumbnails…")
console.log("// Generating thumbnails…"); // eslint-disable-line
const selector = {url: {$exists: true}};
if (mode === "generate") {
selector.thumbnailUrl = {$exists: false};
@ -143,11 +143,11 @@ Meteor.methods({
posts.forEach((post, index) => {
Meteor.setTimeout(function () {
console.log(`// ${index}. fetching thumbnail for “${post.title}” (_id: ${post._id})`);
console.log(`// ${index}. fetching thumbnail for “${post.title}” (_id: ${post._id})`); // eslint-disable-line
try {
regenerateThumbnail(post);
} catch (error) {
console.log(error);
console.log(error); // eslint-disable-line
}
}, index * 1000);
});

View file

@ -1,3 +1,5 @@
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
const Events = new Mongo.Collection('events');
Events.schema = new SimpleSchema({
@ -63,4 +65,4 @@ Events.track = function(event, properties){
// }
};
export default Events;
export default Events;

View file

@ -31,7 +31,7 @@ class Tags extends Component {
const tags = this.state.tags;
tags.splice(i, 1);
const value = this.state.value;
value.splice(i,1);
@ -42,7 +42,7 @@ class Tags extends Component {
}
handleAddition(tag) {
// first, check if added tag is part of the possible options
const option = _.findWhere(this.props.options, {label: tag});
@ -69,14 +69,14 @@ class Tags extends Component {
render() {
const {name, value, label} = this.props;
const {name, /* value, */ label} = this.props;
return (
<div className="form-group row">
<label className="control-label col-sm-3">{label}</label>
<div className="col-sm-9">
<div className="tags-field">
<ReactTags
<ReactTags
tags={this.state.tags}
suggestions={this.state.suggestions}
handleDelete={this.handleDelete}
@ -105,4 +105,4 @@ Tags.propTypes = {
label: React.PropTypes.string
}
export default Tags;
export default Tags;

View file

@ -1,6 +1,6 @@
import React, { PropTypes, Component } from 'react';
import DateTimePicker from 'react-datetime';
import moment from 'moment';
// import moment from 'moment';
class DateTime extends Component {
// when the datetime picker mounts, NovaForm will catch the date value (no formsy mixin in this component)
@ -13,11 +13,11 @@ class DateTime extends Component {
<div className="form-group row">
<label className="control-label col-sm-3">{this.props.label}</label>
<div className="col-sm-9">
<DateTimePicker
<DateTimePicker
value={this.props.value || new Date()}
// newDate argument is a Moment object given by react-datetime
onChange={newDate => { this.context.addToAutofilledValues({[this.props.name]: newDate._d}) }}
format={"x"}
format={"x"}
inputProps={{name: this.props.name}}
/>
</div>

View file

@ -4,7 +4,7 @@ import FRC from 'formsy-react-components';
import DateTime from './DateTime.jsx';
import Utils from './utils.js';
// import Utils from './utils.js';
const Checkbox = FRC.Checkbox;
// const CheckboxGroup = FRC.CheckboxGroup;
@ -30,7 +30,7 @@ class FormComponent extends Component {
renderComponent() {
// see https://facebook.github.io/react/warnings/unknown-prop.html
const { control, group, updateCurrentValue, document, ...rest } = this.props;
const { control, group, updateCurrentValue, document, ...rest } = this.props; // eslint-disable-line
const base = this.props.control === "function" ? this.props : rest;
@ -53,7 +53,7 @@ class FormComponent extends Component {
case "textarea":
return <Textarea {...properties} />;
case "checkbox":
return <Checkbox {...properties} />;
return <Checkbox {...properties} />;
// note: checkboxgroup cause React refs error
case "checkboxgroup":
return <CheckboxGroup {...properties} />;
@ -63,7 +63,7 @@ class FormComponent extends Component {
return <Select {...properties} />;
case "datetime":
return <DateTime {...properties} />;
default:
default:
return <Input {...properties} type="text" />;
}
@ -88,7 +88,7 @@ FormComponent.propTypes = {
label: React.PropTypes.string,
value: React.PropTypes.any,
placeholder: React.PropTypes.string,
prefilledValue: React.PropTypes.any,
prefilledValue: React.PropTypes.any,
options: React.PropTypes.any,
control: React.PropTypes.any,
datatype: React.PropTypes.any,

View file

@ -85,7 +85,7 @@ class NovaForm extends Component{
// backward compatibility from 'autoform' to 'form'
if (fieldSchema.autoform) {
fieldSchema.form = fieldSchema.autoform;
console.warn(`🔭 Telescope Nova Warning: The 'autoform' field is deprecated. You should rename it to 'form' instead. It was defined on your '${fieldName}' field on the '${this.props.collection._name}' collection`);
console.warn(`🔭 Telescope Nova Warning: The 'autoform' field is deprecated. You should rename it to 'form' instead. It was defined on your '${fieldName}' field on the '${this.props.collection._name}' collection`); // eslint-disable-line
}
// replace value by prefilled value if value is empty
@ -96,7 +96,7 @@ class NovaForm extends Component{
field.value = prefilledValue;
}
}
// replace empty value, which has not been prefilled, by the default value from the schema
if (fieldSchema.defaultValue && field.value === "") {
field.value = fieldSchema.defaultValue;
@ -291,7 +291,7 @@ class NovaForm extends Component{
this.setState({disabled: false});
console.log(error);
console.log(error); // eslint-disable-line
const errorContent = this.context.intl.formatMessage({id: error.reason}, {details: error.details})
// add error to state
@ -326,7 +326,7 @@ class NovaForm extends Component{
// complete the data with values from custom components which are not being catched by Formsy mixin
// note: it follows the same logic as NovaForm's getDocument method
data = {
data = {
...this.state.autofilledValues, // ex: can be values from EmbedlyURL or NewsletterSubscribe component
...data, // original data generated thanks to Formsy
...this.state.currentValues, // ex: can be values from DateTime component

View file

@ -1,3 +1,5 @@
/* eslint-disable react/display-name */
'use strict';
var React = require('react');
@ -156,4 +158,4 @@ module.exports = {
}
return (this.isValid() === false);
}
};
};

View file

@ -1,3 +1,5 @@
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
if (typeof SimpleSchema !== "undefined") {
SimpleSchema.extendOptions({
control: Match.Optional(Match.Any), // NovaForm control (String or React component)

View file

@ -92,7 +92,7 @@ var createDummyComments = function () {
};
deleteDummyContent = function () {
var deleteDummyContent = function () {
Users.remove({'profile.isDummy': true});
Posts.remove({isDummy: true});
Comments.remove({isDummy: true});

View file

@ -1,3 +1,5 @@
/* global InjectData */
Meteor.startup(function() {
var dom = $('script[type="text/inject-data"]', document);
var injectedDataString = $.trim(dom.text());
@ -8,4 +10,4 @@ InjectData.getData = function(key, callback) {
Meteor.startup(function() {
callback(InjectData._data[key]);
});
};
};

View file

@ -1 +1,3 @@
InjectData = {};
/* eslint-disable */
InjectData = {};

View file

@ -1,4 +1,6 @@
var http = Npm.require('http');
/* global InjectData */
// var http = Npm.require('http');
var templateText = Assets.getText('lib/inject.html');
var injectDataTemplate = _.template(templateText);
@ -43,7 +45,7 @@ InjectData._hijackWriteIfNeeded = function(res) {
'warn: injecting data turned off due to CORS headers. ' +
'read more: http://goo.gl/eGwb4e';
console.warn(warnMessage);
console.warn(warnMessage); // eslint-disable-line
originalWrite.call(res, chunk, encoding);
return;
}

View file

@ -1,3 +1,5 @@
/* global InjectData */
InjectData._encode = function(ejson) {
var ejsonString = EJSON.stringify(ejson);
return encodeURIComponent(ejsonString);

View file

@ -1,9 +1,9 @@
var fs = Npm.require('fs');
var path = Npm.require('path');
// var fs = Npm.require('fs');
// var path = Npm.require('path');
// We use this patch to avoid data injection failure during server-side rendering on Meteor 1.4
// All the credits for this package goes to Arunoda, Kadira's team & @rigconfig
// see https://github.com/meteor/meteor/issues/7992
// see https://github.com/meteor/meteor/issues/7992
Package.describe({
"summary": "A way to inject data to the client with initial HTML",

View file

@ -1,4 +1,5 @@
import Telescope from 'meteor/nova:lib';
import { Kadira } from 'meteor/meteorhacks:kadira';
Meteor.startup(function() {
if(process.env.NODE_ENV === "production" && !!Telescope.settings.get('kadiraAppId') && !!Telescope.settings.get('kadiraAppSecret')){

View file

@ -1,8 +1,8 @@
import Telescope from './config.js';
import moment from 'moment';
// import moment from 'moment';
/**
* @summary Callback hooks provide an easy way to add extra steps to common operations.
* @summary Callback hooks provide an easy way to add extra steps to common operations.
* @namespace Telescope.callbacks
*/
Telescope.callbacks = {};
@ -95,7 +95,7 @@ Telescope.callbacks.runAsync = function () {
callback.apply(this, args);
});
});
}
};
};

View file

@ -1,3 +1,4 @@
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import Telescope from './config.js';
/**

View file

@ -1,9 +1,11 @@
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
/**
* @summary Kick off the global namespace for Telescope.
* @namespace Telescope
*/
Telescope = {};
const Telescope = {};
Telescope.VERSION = '0.27.4-nova';
@ -106,4 +108,4 @@ Telescope.statuses = [
}
];
export default Telescope;
export default Telescope;

View file

@ -1,3 +1,4 @@
/* eslint-disable */
// see https://gist.github.com/furf/3208381
_.mixin({

View file

@ -60,7 +60,7 @@ Telescope.utils.camelCaseify = function(str) {
* @param {Number} numWords - Number of words to trim sentence to.
*/
Telescope.utils.trimWords = function(s, numWords) {
if (!s)
return s;
@ -89,7 +89,7 @@ Telescope.utils.capitalise = function(str) {
Telescope.utils.t = function(message) {
var d = new Date();
console.log("### "+message+" rendered at "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds());
console.log("### "+message+" rendered at "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()); // eslint-disable-line
};
Telescope.utils.nl2br = function(str) {
@ -147,7 +147,7 @@ Telescope.utils.slugify = function (s) {
Telescope.utils.getUnusedSlug = function (collection, slug) {
let suffix = "";
let index = 0;
// handle edge case for Users collection
const field = collection._name === 'users' ? 'telescope.slug' : 'slug';
@ -239,7 +239,7 @@ Telescope.utils.checkNested = function(obj /*, level1, level2, ... levelN*/) {
Telescope.log = function (s) {
if(Telescope.settings.get('debug', false) || process.env.NODE_ENV === "development") {
console.log(s);
console.log(s); // eslint-disable-line
}
};
@ -313,4 +313,4 @@ Telescope.utils.getLogoUrl = () => {
// the logo may be hosted on another website
return logoUrl.indexOf('://') > -1 ? logoUrl : prefix + logoUrl;
}
};
};

View file

@ -5,10 +5,10 @@ import Users from 'meteor/nova:users';
function subscribeUserOnProfileCompletion (user) {
if (!!Telescope.settings.get('autoSubscribe') && !!Users.getEmail(user)) {
MailChimpList.add(user, false, function (error, result) {
console.log(error);
console.log(result);
console.log(error); // eslint-disable-line
console.log(result); // eslint-disable-line
});
}
return user;
}
Telescope.callbacks.add("users.profileCompleted.async", subscribeUserOnProfileCompletion);
Telescope.callbacks.add("users.profileCompleted.async", subscribeUserOnProfileCompletion);

View file

@ -1,6 +1,7 @@
import Telescope from 'meteor/nova:lib';
import Newsletter from '../namespace.js';
import { SyncedCron } from 'meteor/percolatestudio:synced-cron';
import moment from 'moment';
import Newsletter from '../namespace.js';
const defaultFrequency = [1]; // every monday
const defaultTime = '00:00'; // GMT
@ -45,7 +46,7 @@ var getSchedule = function (parser) {
Meteor.methods({
getNextJob: function () {
var nextJob = SyncedCron.nextScheduledAtDate('scheduleNewsletter');
console.log(nextJob);
console.log(nextJob); // eslint-disable-line
return nextJob;
}
});
@ -60,8 +61,8 @@ var addJob = function () {
job: function() {
// only schedule newsletter campaigns in production
if (process.env.NODE_ENV === "production" || Telescope.settings.get("enableNewsletterInDev", false)) {
console.log("// Scheduling newsletter…")
console.log(new Date());
console.log("// Scheduling newsletter…"); // eslint-disable-line
console.log(new Date()); // eslint-disable-line
Newsletter.scheduleNextWithMailChimp();
}
}

View file

@ -23,7 +23,7 @@ const MailChimp = function ( apiKey, options ) {
if ( !mailChimpOptions.apiKey || mailChimpOptions.apiKey === '' ) {
console.error( '[MailChimp] Error: No API Key defined!' );
console.error( '[MailChimp] Error: No API Key defined!' ); // eslint-disable-line
throw new Meteor.Error(
'No API Key',
@ -89,4 +89,4 @@ MailChimp.prototype.call = function ( section, method, options, callback ) {
// }
// });
export default MailChimp;
export default MailChimp;

View file

@ -30,7 +30,7 @@ MailChimpList.add = function(userOrEmail, confirm, done){
try {
console.log('// Adding "'+email+'" to MailChimp list…');
console.log('// Adding "'+email+'" to MailChimp list…'); // eslint-disable-line
var api = new MailChimp(apiKey);
var subscribeOptions = {
@ -47,7 +47,7 @@ MailChimpList.add = function(userOrEmail, confirm, done){
Users.methods.setSetting(user._id, 'newsletter.subscribed', true);
}
console.log("// User subscribed");
console.log("// User subscribed"); // eslint-disable-line
return subscribe;
@ -55,7 +55,7 @@ MailChimpList.add = function(userOrEmail, confirm, done){
throw new Meteor.Error("subscription-failed", error.message);
}
} else {
throw new Meteor.Error("Please provide your MailChimp API key and list ID", error.message);
throw new Meteor.Error("Please provide your MailChimp API key and list ID");
}
};
@ -74,7 +74,7 @@ MailChimpList.remove = (user) => {
try {
console.log('// Removing "'+email+'" from MailChimp list…');
console.log('// Removing "'+email+'" from MailChimp list…'); // eslint-disable-line
var api = new MailChimp(apiKey);
var subscribeOptions = {
@ -89,7 +89,7 @@ MailChimpList.remove = (user) => {
// mark user as unsubscribed
Users.methods.setSetting(user._id, 'newsletter.subscribed', false);
console.log("// User unsubscribed");
console.log("// User unsubscribed"); // eslint-disable-line
return subscribe;
@ -97,7 +97,7 @@ MailChimpList.remove = (user) => {
throw new Meteor.Error("unsubscription-failed", error.message);
}
} else {
throw new Meteor.Error("Please provide your MailChimp API key and list ID", error.message);
throw new Meteor.Error("Please provide your MailChimp API key and list ID");
}
};

View file

@ -1,11 +1,14 @@
/* eslint-disable no-console */
// newsletter scheduling with MailChimp
import Telescope from 'meteor/nova:lib';
import Newsletter from '../../namespace.js';
import MailChimp from './mailchimp_api.js';
import Posts from 'meteor/nova:posts';
import NovaEmail from 'meteor/nova:email';
import htmlToText from 'html-to-text';
import moment from 'moment';
import Newsletter from '../../namespace.js';
import MailChimp from './mailchimp_api.js';
const defaultPosts = 5;
@ -68,14 +71,14 @@ Newsletter.scheduleWithMailChimp = function (campaign, isTest = false) {
};
// schedule campaign
var schedule = api.call('campaigns', 'schedule', scheduleOptions);
var schedule = api.call('campaigns', 'schedule', scheduleOptions); // eslint-disable-line
console.log('// Newsletter scheduled for '+scheduledTime);
// console.log(schedule)
// if this is not a test, mark posts as sent
if (!isTest)
var updated = Posts.update({_id: {$in: campaign.postIds}}, {$set: {scheduledAt: new Date()}}, {multi: true})
var updated = Posts.update({_id: {$in: campaign.postIds}}, {$set: {scheduledAt: new Date()}}, {multi: true}) // eslint-disable-line
// send confirmation email
var confirmationHtml = NovaEmail.getTemplate('newsletterConfirmation')({
@ -90,4 +93,4 @@ Newsletter.scheduleWithMailChimp = function (campaign, isTest = false) {
}
return subject;
}
};
};

View file

@ -1,10 +1,11 @@
import Telescope from 'meteor/nova:lib';
import moment from 'moment';
import Posts from "meteor/nova:posts";
import Comments from "meteor/nova:comments";
import Users from 'meteor/nova:users';
import Categories from "meteor/nova:categories";
import NovaEmail from 'meteor/nova:email';
import { SyncedCron } from 'meteor/percolatestudio:synced-cron';
import moment from 'moment';
import Newsletter from '../namespace.js';
// create new "newsletter" view for all posts from the past X days that haven't been scheduled yet
@ -14,7 +15,7 @@ Posts.views.add("newsletter", function (terms) {
scheduledAt: {$exists: false}
},
options: {
sort: {baseScore: -1},
sort: {baseScore: -1},
limit: terms.limit
}
};
@ -32,14 +33,14 @@ Newsletter.getPosts = function (postsCount) {
// if there is a last newsletter and it was sent less than 7 days ago use its date, else default to posts from the last 7 days
var lastWeek = moment().subtract(7, 'days');
var after = (lastNewsletter && moment(lastNewsletter.finishedAt).isAfter(lastWeek)) ? lastNewsletter.finishedAt : lastWeek.format("YYYY-MM-DD");
// get parameters using "newsletter" view
var params = Posts.parameters.get({
view: "newsletter",
after: after,
limit: postsCount
});
return Posts.find(params.selector, params.options).fetch();
};
@ -91,7 +92,7 @@ Newsletter.build = function (postsArray) {
// get the two highest-scoring comments
properties.popularComments = Comments.find({postId: post._id}, {sort: {score: -1}, limit: 2, transform: function (comment) {
// get comment author
var user = Users.findOne(comment.userId);
@ -105,7 +106,7 @@ Newsletter.build = function (postsArray) {
} catch (error) {
comment.authorAvatarUrl = false;
}
return comment;
}}).fetch();
@ -151,13 +152,13 @@ Newsletter.build = function (postsArray) {
var emailHTML = NovaEmail.buildTemplate(newsletterHTML, {
date: moment().format("dddd, MMMM D YYYY")
});
// 4. build campaign object and return it
var campaign = {
postIds: _.pluck(postsArray, '_id'),
subject: Telescope.utils.trimWords(subject, 15),
html: emailHTML
};
return campaign;
};

View file

@ -21,7 +21,7 @@ Telescope.notifications.create = (userIds, notificationName, data) => {
if (!!userEmail) {
NovaEmail.buildAndSendHTML(Users.getEmail(user), subject, html);
} else {
console.log(`// Couldn't send notification: admin user ${user._id} doesn't have an email`);
console.log(`// Couldn't send notification: admin user ${user._id} doesn't have an email`); // eslint-disable-line
}
});

View file

@ -360,7 +360,7 @@ Telescope.callbacks.add("posts.edit.sync", PostsEditSetPostedAt);
// ------------------------------------- posts.edit.async -------------------------------- //
function PostsEditRunPostApprovedCallbacks (post, oldPost) {
var now = new Date();
// var now = new Date();
if (Posts.isApproved(post) && !Posts.isApproved(oldPost)) {
Telescope.callbacks.runAsync("posts.approve.async", post);
@ -388,7 +388,7 @@ Telescope.callbacks.add("posts.approve.async", PostsApprovedNotification);
function UsersRemoveDeletePosts (user, options) {
if (options && options.deletePosts) {
Posts.remove({userId: userId});
Posts.remove({userId: user._id});
} else {
// not sure if anything should be done in that scenario yet
// Posts.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});

View file

@ -4,16 +4,16 @@ const returnEmptyObject = function () {
return {};
}
console.log(Mongo)
console.log(Mongo); // eslint-disable-line
const Mongo = typeof Mongo !== "undefined" ? Mongo : {
const Mongo = typeof Mongo !== "undefined" ? Mongo : {
Collection: function () {
return {attachSchema: returnEmptyObject}
}
};
console.log("// Mongo")
console.log(Mongo)
console.log("// Mongo"); // eslint-disable-line
console.log(Mongo); // eslint-disable-line
const Meteor = typeof Meteor !== "undefined" ? Meteor : {
methods: returnEmptyObject
@ -22,4 +22,4 @@ const Meteor = typeof Meteor !== "undefined" ? Meteor : {
const SimpleSchema = typeof SimpleSchema !== "undefined" ? SimpleSchema : returnEmptyObject;
const Foo = "bar"
export { Mongo, Foo }
export { Mongo, Foo }

View file

@ -1,7 +1,8 @@
import Telescope from 'meteor/nova:lib';
import Posts from './collection.js'
import Users from 'meteor/nova:users';
import Events from "meteor/nova:events";
import Events from 'meteor/nova:events';
import { Messages } from 'meteor/nova:core';
import Posts from './collection.js'
/**
*
@ -113,7 +114,7 @@ Meteor.methods({
* @param {Object} modifier - the update modifier
*/
'posts.edit': function (postId, modifier) {
Posts.simpleSchema().namedContext("posts.edit").validate(modifier, {modifier: true});
check(postId, String);
@ -134,7 +135,7 @@ Meteor.methods({
'posts.approve': function(postId){
check(postId, String);
const post = Posts.findOne(postId);
const now = new Date();
@ -145,7 +146,7 @@ Meteor.methods({
if (!post.postedAt) {
set.postedAt = now;
}
Posts.update(post._id, {$set: set});
Telescope.callbacks.runAsync("posts.approve.async", post);
@ -164,15 +165,15 @@ Meteor.methods({
'posts.reject': function(postId){
check(postId, String);
const post = Posts.findOne(postId);
if(Users.isAdmin(Meteor.user())){
Posts.update(post._id, {$set: {status: Posts.config.STATUS_REJECTED}});
Telescope.callbacks.runAsync("postRejectAsync", post);
}else{
Messages.flash('You need to be an admin to do that.', "error");
}
@ -188,7 +189,7 @@ Meteor.methods({
check(postId, String);
check(sessionId, Match.Any);
// only let users increment a post's view counter once per session
var view = {_id: postId, userId: this.userId, sessionId: sessionId};
@ -237,7 +238,7 @@ Meteor.methods({
* @param {String} url - the URL to check
*/
'posts.checkForDuplicates': function (url) {
Posts.checkForSameUrl(url);
Posts.checkForSameUrl(url);
},
/**

View file

@ -1,9 +1,10 @@
import Telescope from 'meteor/nova:lib';
import Posts from './collection.js'
import { Injected } from 'meteor/meteorhacks:inject-initial';
import moment from 'moment';
import Posts from './collection.js'
/**
* @summary Parameter callbacks let you add parameters to subscriptions
* @summary Parameter callbacks let you add parameters to subscriptions
* @namespace Posts.parameters
*/
Posts.parameters = {};
@ -32,25 +33,25 @@ Posts.parameters.get = function (terms) {
// iterate over posts.parameters callbacks
parameters = Telescope.callbacks.run("posts.parameters", parameters, _.clone(terms));
// if sort options are not provided, default to "createdAt" sort
if (_.isEmpty(parameters.options.sort)) {
parameters.options.sort = {sticky: -1, createdAt: -1};
}
// extend sort to sort posts by _id to break ties
// NOTE: always do this last to avoid _id sort overriding another sort
parameters = Telescope.utils.deepExtend(true, parameters, {options: {sort: {_id: -1}}});
// console.log(parameters);
return parameters;
};
// Parameter callbacks
// View Parameter
// Add a "view" property to terms which can be used to filter posts.
// Add a "view" property to terms which can be used to filter posts.
function addViewParameter (parameters, terms) {
// if view is not defined, default to "new"
@ -65,25 +66,25 @@ function addViewParameter (parameters, terms) {
Telescope.callbacks.add("posts.parameters", addViewParameter);
// View Parameter
// Add "after" and "before" properties to terms which can be used to limit posts in time.
// Add "after" and "before" properties to terms which can be used to limit posts in time.
function addTimeParameter (parameters, terms) {
// console.log("// addTimeParameter")
if (typeof parameters.selector.postedAt === "undefined") {
let postedAt = {}, mAfter, mBefore, startOfDay, endOfDay, clientTimezoneOffset, serverTimezoneOffset, timeDifference;
/*
/*
If we're on the client, add the time difference between client and server
Example: client is on Japanese time (+9 hours),
Example: client is on Japanese time (+9 hours),
server on UCT (Greenwich) time (+0 hours), for a total difference of +9 hours.
So the time "00:00, UCT" is equivalent to "09:00, JST".
So if we want to express the timestamp "00:00, UCT" on the client,
So if we want to express the timestamp "00:00, UCT" on the client,
we *add* 9 hours to "00:00, JST" on the client to get "09:00, JST" and
sync up both times.
@ -93,7 +94,7 @@ function addTimeParameter (parameters, terms) {
clientTimezoneOffset = -1 * new Date().getTimezoneOffset();
serverTimezoneOffset = -1 * Injected.obj('serverTimezoneOffset').offset;
timeDifference = clientTimezoneOffset - serverTimezoneOffset;
// console.log("client time:"+clientTimezoneOffset);
// console.log("server time:"+serverTimezoneOffset);
// console.log("difference: "+timeDifference);
@ -127,7 +128,7 @@ function addTimeParameter (parameters, terms) {
}
postedAt.$lt = endOfDay.toDate();
}
if (!_.isEmpty(postedAt)) {

View file

@ -1,6 +1,7 @@
import Telescope from 'meteor/nova:lib';
import Posts from './collection.js';
import Users from 'meteor/nova:users';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import Posts from './collection.js';
/**
* @summary Posts config namespace
@ -235,7 +236,7 @@ Posts.schemaJSON = {
publish: true,
},
/**
The post author's `_id`.
The post author's `_id`.
*/
userId: {
type: String,

View file

@ -1,5 +1,6 @@
import { SyncedCron } from 'meteor/percolatestudio:synced-cron';
// import moment from 'moment';
import Posts from '../collection.js';
import moment from 'moment';
SyncedCron.options = {
log: true,
@ -18,17 +19,17 @@ const addJob = function () {
job() {
// fetch all posts tagged as future
const scheduledPosts = Posts.find({isFuture: true}, {fields: {_id: 1, status: 1, postedAt: 1, userId: 1, title: 1}}).fetch();
// filter the scheduled posts to retrieve only the one that should update, considering their schedule
const postsToUpdate = scheduledPosts.filter(post => post.postedAt <= new Date());
// update posts found
if (!_.isEmpty(postsToUpdate)) {
const postsIds = _.pluck(postsToUpdate, '_id');
Posts.update({_id: {$in: postsIds}}, {$set: {isFuture: false}}, {multi: true});
// log the action
console.log('// Scheduled posts approved:', postsIds);
console.log('// Scheduled posts approved:', postsIds); // eslint-disable-line
}
}
});

View file

@ -1,7 +1,8 @@
import Telescope from 'meteor/nova:lib';
import Posts from '../collection.js';
// import Comments from "meteor/nova:comments";
import Users from 'meteor/nova:users';
import { Counts } from 'meteor/tmeasday:publish-counts';
import Posts from '../collection.js';
Posts._ensureIndex({"status": 1, "postedAt": 1});
@ -25,7 +26,7 @@ const getPostsListUsers = posts => {
userIds = _.unique(userIds);
return Users.find({_id: {$in: userIds}}, {fields: Users.publishedFields.list});
};
/**
@ -37,12 +38,12 @@ const getSinglePostUsers = post => {
let users = [post.userId]; // publish post author's ID
/*
NOTE: to avoid circular dependencies between nova:posts and nova:comments,
/*
NOTE: to avoid circular dependencies between nova:posts and nova:comments,
use callback hook to get comment authors
*/
users = Telescope.callbacks.run("posts.single.getUsers", users, post);
// add upvoters
if (post.upvoters && post.upvoters.length) {
users = users.concat(post.upvoters);
@ -67,15 +68,15 @@ const getSinglePostUsers = post => {
*/
Meteor.publish('posts.list', function (terms) {
// this.unblock(); // causes bug where publication returns 0 results
// this.unblock(); // causes bug where publication returns 0 results
this.autorun(function () {
const currentUser = this.userId && Users.findOne(this.userId);
terms.currentUserId = this.userId; // add currentUserId to terms
const {selector, options} = Posts.parameters.get(terms);
Counts.publish(this, terms.listId, Posts.find(selector, options), {noReady: true});
options.fields = Posts.publishedFields.list;
@ -90,7 +91,7 @@ Meteor.publish('posts.list', function (terms) {
});
return Users.canDo(currentUser, "posts.view.approved.all") ? [posts, users] : [];
});
});
@ -112,8 +113,8 @@ Meteor.publish('posts.single', function (terms) {
const users = getSinglePostUsers(post);
return Users.canView(currentUser, post) ? [posts, users] : [];
} else {
console.log(`// posts.single: no post found for _id “${terms._id}`)
console.log(`// posts.single: no post found for _id “${terms._id}`); // eslint-disable-line
return [];
}
});
});

View file

@ -1,11 +1,12 @@
import Posts from '../collection.js';
import { Picker } from 'meteor/meteorhacks:picker';
import escapeStringRegexp from 'escape-string-regexp';
import Posts from '../collection.js';
Picker.route('/out', function(params, req, res, next) {
var query = params.query;
if(query.url){ // for some reason, query.url doesn't need to be decoded
/*
/*
If the URL passed to ?url= is in plain text, any hash fragment
will get stripped out.
So we search for any post whose URL contains the current URL to get a match
@ -25,4 +26,4 @@ Picker.route('/out', function(params, req, res, next) {
} else {
res.end("Please provide a URL");
}
});
});

View file

@ -1,3 +1,4 @@
import Users from 'meteor/nova:users';
import Posts from './collection.js'
/**
@ -103,7 +104,7 @@ Posts.views.add("userPosts", function (terms) {
isFuture: {$ne: true}
},
options: {
limit: 5,
limit: 5,
sort: {
postedAt: -1
}

View file

@ -1,3 +1,4 @@
import { Picker } from 'meteor/meteorhacks:picker';
import { servePostRSS, serveCommentRSS } from './rss.js';
Picker.route('/feed.xml', function(params, req, res, next) {

View file

@ -52,9 +52,9 @@ const serveCommentRSS = function (terms, url) {
var feed = new RSS(getMeta(url));
Comments.find({isDeleted: {$ne: true}}, {sort: {postedAt: -1}, limit: 20}).forEach(function(comment) {
post = Posts.findOne(comment.postId);
var post = Posts.findOne(comment.postId);
feed.item({
title: 'Comment on '+post.title,
title: 'Comment on ' + post.title,
description: `${comment.body}</br></br><a href="${comment.getPageUrl(true)}">Discuss</a>`,
author: comment.author,
date: comment.postedAt,

View file

@ -1,5 +1,6 @@
import Telescope from 'meteor/nova:lib';
import Users from 'meteor/nova:users';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
const isInSettingsJSON = function () {
// settings can either be in settings json's public, or in the special object we publish only for admins for private settings
@ -371,4 +372,4 @@ Telescope.settings.schema = new SimpleSchema({
Telescope.settings.collection.attachSchema(Telescope.settings.schema);
Telescope.subscriptions.preload("settings");
Telescope.subscriptions.preload("settings");

View file

@ -16,7 +16,7 @@ Meteor.methods({
"settings.exportToJSON": function () {
if (Users.isAdminById(this.userId)) {
let settings = Telescope.settings.collection.findOne();
const schema = Telescope.settings.collection.simpleSchema()._schema;
// const schema = Telescope.settings.collection.simpleSchema()._schema;
const publicFields = Telescope.settings.collection.getPublicFields();
delete settings._id;
settings.public = {};
@ -26,7 +26,7 @@ Meteor.methods({
delete settings[key];
}
});
console.log(JSON.stringify(settings, null, 2));
console.log(JSON.stringify(settings, null, 2)); // eslint-disable-line
return settings;
}
},
@ -36,4 +36,4 @@ Meteor.methods({
Telescope.settings.collection.update(settings._id, {}, {validate: false});
}
}
})
})

View file

@ -1,5 +1,5 @@
import PublicationUtils from 'meteor/utilities:smart-publications';
import Users from "meteor/nova:users";
import Users from 'meteor/nova:users';
Users.addField([
{

View file

@ -6,13 +6,13 @@ import Users from 'meteor/nova:users';
* @param {Collection} collection
* @param {String} itemId
* @param {Object} user
* @returns {Object} collectionName, fields: object, item, hasSubscribedItem: boolean
* @returns {Object} collectionName, fields: object, item, hasSubscribedItem: boolean
*/
const prepareSubscription = (action, collection, itemId, user) => {
// get item's collection name
const collectionName = collection._name.slice(0,1).toUpperCase() + collection._name.slice(1);
// get item data
const item = collection.findOne(itemId);
@ -20,7 +20,7 @@ const prepareSubscription = (action, collection, itemId, user) => {
if (!user || !item) {
return false;
}
// edge case: Users collection
if (collectionName === 'Users') {
// someone can't subscribe to themself, abort process
@ -35,12 +35,12 @@ const prepareSubscription = (action, collection, itemId, user) => {
}
// assign the right fields depending on the collection
const fields = {
const fields = {
subscribers: collectionName === 'Users' ? 'telescope.subscribers' : 'subscribers',
subscriberCount: collectionName === 'Users' ? 'telescope.subscriberCount' : 'subscriberCount',
};
// return true if the item has the subscriber's id in its fields
// return true if the item has the subscriber's id in its fields
const hasSubscribedItem = !!_.deep(item, fields.subscribers) && _.deep(item, fields.subscribers) && _.deep(item, fields.subscribers).indexOf(user._id) !== -1;
// assign the right update operator and count depending on the action type
@ -107,7 +107,7 @@ const performSubscriptionAction = (action, collection, itemId, user) => {
itemId: item._id,
};
// in case of subscription, log also the date
// in case of subscription, log also the date
if (action === 'subscribe') {
loggedItem = {
...loggedItem,
@ -129,11 +129,12 @@ const performSubscriptionAction = (action, collection, itemId, user) => {
};
/**
* @summary Generate methods 'collection.subscribe' & 'collection.unsubscribe' automatically
* @summary Generate methods 'collection.subscribe' & 'collection.unsubscribe' automatically
* @params {Array[Collections]} collections
*/
let subscribeMethodsGenerator;
export default subscribeMethodsGenerator = (collection) => {
// generic method function calling the performSubscriptionAction
const genericMethodFunction = (col, action) => {
// return the method code
@ -151,7 +152,7 @@ const performSubscriptionAction = (action, collection, itemId, user) => {
return performSubscriptionAction(action, col, docId, user);
};
};
const collectionName = collection._name;
// return an object of the shape expected by Meteor.methods
return {
@ -162,7 +163,7 @@ const performSubscriptionAction = (action, collection, itemId, user) => {
// Finally. Add the methods to the Meteor namespace 🖖
// nova:users is a dependency of this package, it is alreay imported
// nova:users is a dependency of this package, it is alreay imported
Meteor.methods(subscribeMethodsGenerator(Users));
// check if nova:posts exists, if yes, add the methods to Posts

View file

@ -1,3 +1,5 @@
import Users from 'meteor/nova:users';
if (typeof Package['nova:posts'] !== "undefined") {
import Posts from "meteor/nova:posts";

View file

@ -1,3 +1,4 @@
import { Gravatar } from 'meteor/jparker:gravatar';
import Users from './collection.js';
// var _ = require('underscore');
@ -191,7 +192,7 @@ Users.avatar = {
return service[0];
},
computeUrl: function(prop) {
computeUrl: function(prop, user) {
if (typeof prop === 'function') {
prop = prop.call(user);
}
@ -210,9 +211,9 @@ Users.avatar = {
var customProp = user && this.options.customImageProperty;
if (typeof customProp === 'function') {
return this.computeUrl(customProp);
return this.computeUrl(customProp, user);
} else if (customProp) {
return this.computeUrl(this.getDescendantProp(user, customProp));
return this.computeUrl(this.getDescendantProp(user, customProp), user);
}
},
@ -230,7 +231,7 @@ Users.avatar = {
}
var emailOrHash = this.getUserEmail(user) || Users.getEmailHash(user);
var secure = true;
// var secure = true;
var options = {
// NOTE: Gravatar's default option requires a publicly accessible URL,
// so it won't work when your app is running on localhost and you're

View file

@ -1,8 +1,9 @@
import Telescope from 'meteor/nova:lib';
import Users from './collection.js';
import marked from 'marked';
import Events from "meteor/nova:events";
import NovaEmail from 'meteor/nova:email';
import { Gravatar } from 'meteor/jparker:gravatar';
import marked from 'marked';
import Users from './collection.js';
//////////////////////////////////////////////////////
// Collection Hooks //
@ -130,7 +131,7 @@ function setupUser (user, options) {
user.telescope.displayName = user.services.linkedin.firstName + " " + user.services.linkedin.lastName;
} else {
user.telescope.displayName = user.username;
}
}
// create a basic slug from display name and then modify it if this slugs already exists;
const basicSlug = Telescope.utils.slugify(user.telescope.displayName);

View file

@ -39,7 +39,7 @@ Users.getUserName = function (user) {
return user.services.twitter.screenName;
}
catch (error){
console.log(error);
console.log(error); // eslint-disable-line
return null;
}
};

View file

@ -1,6 +1,7 @@
import Telescope from 'meteor/nova:lib';
import Users from './collection.js';
/*
var completeUserProfile = function (userId, modifier, user) {
Users.update(userId, modifier);
@ -10,6 +11,7 @@ var completeUserProfile = function (userId, modifier, user) {
return Users.findOne(userId);
};
*/
Users.methods = {};
@ -97,7 +99,7 @@ Meteor.methods({
},
'users.remove'(userId, options) {
// do the user which to delete his account or another user?
const actionType = this.userId === userId ? "own" : "all";

Some files were not shown because too many files have changed in this diff Show more