mirror of
https://github.com/wassname/talk.git
synced 2026-07-25 13:30:59 +08:00
Merge branch 'master' of github.com:coralproject/talk into passport
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
dist
|
||||
dist
|
||||
+2
-1
@@ -59,6 +59,7 @@
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{"max": 1}
|
||||
]
|
||||
],
|
||||
"newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }]
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -24,11 +24,13 @@ program
|
||||
const Setting = require('../models/setting');
|
||||
const defaults = {id: '1', moderation: 'pre'};
|
||||
|
||||
Setting.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true})
|
||||
Setting
|
||||
.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true})
|
||||
.then(() => {
|
||||
console.log('Created settings object.');
|
||||
mongoose.disconnect();
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`failed to create the settings object ${JSON.stringify(err)}`);
|
||||
throw new Error(err); // just to be safe
|
||||
});
|
||||
|
||||
+6
-3
@@ -71,10 +71,12 @@ function createUser(options) {
|
||||
})
|
||||
.then((result) => {
|
||||
return User.createLocalUser(result.email.trim(), result.password.trim(), result.displayName.trim());
|
||||
}).then((user) => {
|
||||
})
|
||||
.then((user) => {
|
||||
console.log(`Created user ${user.id}.`);
|
||||
mongoose.disconnect();
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
mongoose.disconnect();
|
||||
});
|
||||
@@ -249,7 +251,8 @@ function mergeUsers(dstUserID, srcUserID) {
|
||||
.then(() => {
|
||||
console.log(`User ${srcUserID} was merged into user ${dstUserID}.`);
|
||||
mongoose.disconnect();
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
mongoose.disconnect();
|
||||
});
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"modqueue": {
|
||||
"pending": "pending",
|
||||
"rejected": "rejected",
|
||||
"flagged": "flagged",
|
||||
"shortcuts": "Shortcuts",
|
||||
"close": "Close",
|
||||
"actions": "Actions",
|
||||
"navigation": "Navigation",
|
||||
"approve": "Approve comment",
|
||||
"reject": "Reject comment",
|
||||
"nextcomment": "Go to the next comment",
|
||||
"prevcomment": "Go to the previous comment",
|
||||
"singleview": "Toggle single comment edit view",
|
||||
"thismenu": "Open this menu"
|
||||
},
|
||||
"comment": {
|
||||
"flagged": "flagged",
|
||||
"anon": "Anonymous"
|
||||
},
|
||||
"embedlink": {
|
||||
"copy": "Copy to Clipboard"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"modqueue": {
|
||||
"pending": "pendiente",
|
||||
"rejected": "rechazado",
|
||||
"flagged": "marcado",
|
||||
"shortcuts": "Atajos de teclado",
|
||||
"close": "Cerrar"
|
||||
},
|
||||
"comment": {
|
||||
"flagged": "marcado",
|
||||
"anon": "Anónimo"
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import {Router, Route, IndexRoute, browserHistory} from 'react-router';
|
||||
import ModerationQueue from 'containers/ModerationQueue';
|
||||
import CommentStream from 'containers/CommentStream';
|
||||
import Configure from 'containers/Configure';
|
||||
import CommunityContainer from 'containers/CommunityContainer';
|
||||
import CommunityContainer from 'containers/Community/CommunityContainer';
|
||||
import LayoutContainer from 'containers/LayoutContainer';
|
||||
|
||||
const routes = (
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import qs from 'qs';
|
||||
|
||||
import {
|
||||
FETCH_COMMENTERS_REQUEST,
|
||||
FETCH_COMMENTERS_SUCCESS,
|
||||
FETCH_COMMENTERS_FAILURE,
|
||||
SORT_UPDATE,
|
||||
COMMENTERS_NEW_PAGE
|
||||
} from '../constants/community';
|
||||
|
||||
import {base, getInit, handleResp} from '../helpers/response';
|
||||
|
||||
export const fetchCommenters = (query = {}) => dispatch => {
|
||||
dispatch(requestFetchCommenters());
|
||||
fetch(`${base}/user?${qs.stringify(query)}`, getInit('GET'))
|
||||
.then(handleResp)
|
||||
.then(({result, page, count, limit, totalPages}) =>
|
||||
dispatch({
|
||||
type: FETCH_COMMENTERS_SUCCESS,
|
||||
commenters: result,
|
||||
page,
|
||||
count,
|
||||
limit,
|
||||
totalPages
|
||||
})
|
||||
)
|
||||
.catch(error => dispatch({type: FETCH_COMMENTERS_FAILURE, error}));
|
||||
};
|
||||
|
||||
const requestFetchCommenters = () => ({
|
||||
type: FETCH_COMMENTERS_REQUEST
|
||||
});
|
||||
|
||||
export const updateSorting = sort => ({
|
||||
type: SORT_UPDATE,
|
||||
sort
|
||||
});
|
||||
|
||||
export const newPage = () => ({
|
||||
type: COMMENTERS_NEW_PAGE
|
||||
});
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import React from 'react';
|
||||
import {Layout} from 'react-mdl';
|
||||
import 'material-design-lite';
|
||||
import Header from 'components/Header';
|
||||
|
||||
export default (props) => (
|
||||
<Layout>
|
||||
<Header>
|
||||
{props.children}
|
||||
</Header>
|
||||
</Layout>
|
||||
);
|
||||
@@ -9,6 +9,9 @@ export default () => (
|
||||
<Link className={styles.navLink} to="/admin">Moderate</Link>
|
||||
<Link className={styles.navLink} to="/admin/community">Community</Link>
|
||||
<Link className={styles.navLink} to="/admin/configure">Configure</Link>
|
||||
<span>
|
||||
{`v${process.env.VERSION}`}
|
||||
</span>
|
||||
</Navigation>
|
||||
</Header>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.layout {
|
||||
max-width: 1170px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -2,11 +2,14 @@ import React from 'react';
|
||||
import {Layout as LayoutMDL} from 'react-mdl';
|
||||
import Header from './Header';
|
||||
import Drawer from './Drawer';
|
||||
import styles from './Layout.css';
|
||||
|
||||
export const Layout = ({children}) => (
|
||||
<LayoutMDL fixedDrawer>
|
||||
<Header />
|
||||
<Drawer />
|
||||
{children}
|
||||
<div className={styles.layout} >
|
||||
{children}
|
||||
</div>
|
||||
</LayoutMDL>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const FETCH_COMMENTERS_REQUEST = 'FETCH_COMMENTERS_REQUEST';
|
||||
export const FETCH_COMMENTERS_SUCCESS = 'FETCH_COMMENTERS_SUCCESS';
|
||||
export const FETCH_COMMENTERS_FAILURE = 'FETCH_COMMENTERS_FAILURE';
|
||||
export const SORT_UPDATE = 'SORT_UPDATE';
|
||||
export const COMMENTERS_NEW_PAGE = 'COMMENTERS_NEW_PAGE';
|
||||
@@ -0,0 +1,22 @@
|
||||
.dataTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.roleButton {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.searchInput {
|
||||
display: block;
|
||||
padding-left: 40px;
|
||||
/*border: none;*/
|
||||
}
|
||||
|
||||
.searchBox {
|
||||
/*border: 1px solid rgba(0,0,0,.12);*/
|
||||
background: white;
|
||||
}
|
||||
|
||||
.email {
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import I18n from 'coral-framework/i18n/i18n';
|
||||
import translations from '../../translations';
|
||||
import {Grid, Cell} from 'react-mdl';
|
||||
|
||||
import styles from './Community.css';
|
||||
import Table from './Table';
|
||||
import Loading from './Loading';
|
||||
import NoResults from './NoResults';
|
||||
import Pager from './Pager';
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
const tableHeaders = [
|
||||
{
|
||||
title: lang.t('community.username_and_email'),
|
||||
field: 'displayName'
|
||||
},
|
||||
{
|
||||
title: lang.t('community.account_creation_date'),
|
||||
field: 'created_at'
|
||||
}
|
||||
];
|
||||
|
||||
const Community = ({isFetching, commenters, ...props}) => {
|
||||
const hasResults = !isFetching && !!commenters.length;
|
||||
return (
|
||||
<Grid>
|
||||
<Cell col={4}>
|
||||
<form action="">
|
||||
<div className={`mdl-textfield ${styles.searchBox}`}>
|
||||
<label className="mdl-button mdl-js-button mdl-button--icon" htmlFor="commenters-search">
|
||||
<i className="material-icons">search</i>
|
||||
</label>
|
||||
<div className="">
|
||||
<input
|
||||
id="commenters-search"
|
||||
className={`mdl-textfield__input ${styles.searchInput}`}
|
||||
type="text"
|
||||
value={props.searchValue}
|
||||
onKeyDown={props.onKeyDownHandler}
|
||||
onChange={props.onChangeHandler}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Cell>
|
||||
<Cell col={8}>
|
||||
{ isFetching && <Loading /> }
|
||||
{ !hasResults && <NoResults /> }
|
||||
{ hasResults &&
|
||||
<Table
|
||||
headers={tableHeaders}
|
||||
data={commenters}
|
||||
onHeaderClickHandler={props.onHeaderClickHandler}
|
||||
/>
|
||||
}
|
||||
<Pager
|
||||
totalPages={props.totalPages}
|
||||
page={props.page}
|
||||
onNewPageHandler={props.onNewPageHandler}
|
||||
/>
|
||||
</Cell>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Community;
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
fetchCommenters,
|
||||
updateSorting,
|
||||
newPage,
|
||||
} from '../../actions/community';
|
||||
|
||||
import Community from './Community';
|
||||
|
||||
class CommunityContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
searchValue: ''
|
||||
};
|
||||
|
||||
this.onKeyDownHandler = this.onKeyDownHandler.bind(this);
|
||||
this.onChangeHandler = this.onChangeHandler.bind(this);
|
||||
this.onHeaderClickHandler = this.onHeaderClickHandler.bind(this);
|
||||
this.onNewPageHandler = this.onNewPageHandler.bind(this);
|
||||
}
|
||||
|
||||
onKeyDownHandler(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
|
||||
onChangeHandler(e) {
|
||||
this.setState({
|
||||
searchValue: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
search(query = {}) {
|
||||
const {community} = this.props;
|
||||
|
||||
this.props.dispatch(fetchCommenters({
|
||||
value: this.state.searchValue,
|
||||
field: community.get('field'),
|
||||
asc: community.get('asc'),
|
||||
...query
|
||||
}));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.search();
|
||||
}
|
||||
|
||||
onHeaderClickHandler(sort) {
|
||||
this.props.dispatch(updateSorting(sort));
|
||||
this.search();
|
||||
}
|
||||
|
||||
onNewPageHandler(page) {
|
||||
this.props.dispatch(newPage(page));
|
||||
this.search({page});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {searchValue} = this.state;
|
||||
const {community} = this.props;
|
||||
return (
|
||||
<Community
|
||||
searchValue={searchValue}
|
||||
commenters={community.get('commenters')}
|
||||
isFetching={community.get('isFetching')}
|
||||
error={community.get('error')}
|
||||
totalPages={community.get('totalPages')}
|
||||
page={community.get('page')}
|
||||
{...this}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(({community}) => ({community}))(CommunityContainer);
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
const Loading = () => (
|
||||
<h1> Loading results </h1>
|
||||
);
|
||||
|
||||
export default Loading;
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const NoResults = () => (
|
||||
<div>
|
||||
No users found with that user name or email address
|
||||
</div>
|
||||
);
|
||||
|
||||
export default NoResults;
|
||||
@@ -0,0 +1,10 @@
|
||||
.li {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
padding: 0;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
.current {
|
||||
background: #e3edf3;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import styles from './Pager.css';
|
||||
|
||||
const Rows = (curr, total, onClickHandler) => Array.from(Array(total)).map((e, i) =>
|
||||
<li className={`mdl-button mdl-js-button ${styles.li} ${curr === i ? styles.current : ''}`}
|
||||
key={i} onClick={() => onClickHandler(i + 1)}>
|
||||
{i + 1}
|
||||
</li>
|
||||
);
|
||||
|
||||
const Pager = ({totalPages, page, onNewPageHandler}) => (
|
||||
<div className="pager">
|
||||
<ul>
|
||||
{
|
||||
(totalPages > page) ?
|
||||
<li
|
||||
className={`mdl-button mdl-js-button ${styles.li}`}
|
||||
onClick={() => onNewPageHandler(page - 1)}>
|
||||
Prev
|
||||
</li>
|
||||
:
|
||||
null
|
||||
}
|
||||
{Rows(page, totalPages, onNewPageHandler)}
|
||||
{
|
||||
(page < totalPages) ?
|
||||
<li
|
||||
className={`mdl-button mdl-js-button ${styles.li}`}
|
||||
onClick={() => onNewPageHandler(page + 1)}>
|
||||
Next
|
||||
</li>
|
||||
:
|
||||
null
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
||||
Pager.propTypes = {
|
||||
totalPages: PropTypes.number.isRequired,
|
||||
page: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default Pager;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import styles from './Community.css';
|
||||
|
||||
const Table = ({headers, data, onHeaderClickHandler}) => (
|
||||
<table className={`mdl-data-table ${styles.dataTable}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
{headers.map((header, i) =>(
|
||||
<th
|
||||
key={i}
|
||||
className="mdl-data-table__cell--non-numeric"
|
||||
onClick={() => onHeaderClickHandler({field: header.field})}>
|
||||
{header.title}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((row, i)=> (
|
||||
<tr key={i}>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
{row.displayName}
|
||||
<span className={styles.email}>{row.profiles.map(({id}) => id)}</span>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
{row.created_at}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
export default Table;
|
||||
@@ -1,11 +0,0 @@
|
||||
import React, {Component} from 'react';
|
||||
|
||||
export default class CommunityContainer extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Community</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
import React, {Component}from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {Layout} from '../components/ui/Layout';
|
||||
|
||||
class LayoutContainer extends Component {
|
||||
render () {
|
||||
return <Layout { ...this.props } />;
|
||||
return <Layout {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutContainer.propTypes = {};
|
||||
|
||||
const mapStateToProps = () => ({data: {}});
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({dispatch});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LayoutContainer);
|
||||
|
||||
|
||||
@@ -73,7 +73,12 @@ class ModerationQueue extends React.Component {
|
||||
<CommentList
|
||||
isActive={activeTab === 'pending'}
|
||||
singleView={singleView}
|
||||
commentIds={comments.get('ids').filter(id => !comments.get('byId').get(id).get('status'))}
|
||||
commentIds={
|
||||
comments.get('ids')
|
||||
.filter(id => !comments.get('byId')
|
||||
.get(id)
|
||||
.get('status'))
|
||||
}
|
||||
comments={comments.get('byId')}
|
||||
onClickAction={(action, id) => this.onCommentAction(action, id)}
|
||||
actions={['reject', 'approve']}
|
||||
@@ -83,7 +88,15 @@ class ModerationQueue extends React.Component {
|
||||
<CommentList
|
||||
isActive={activeTab === 'rejected'}
|
||||
singleView={singleView}
|
||||
commentIds={comments.get('ids').filter(id => comments.get('byId').get(id).get('status') === 'rejected')}
|
||||
commentIds={
|
||||
comments
|
||||
.get('ids')
|
||||
.filter(id =>
|
||||
comments
|
||||
.get('byId')
|
||||
.get(id)
|
||||
.get('status') === 'rejected')
|
||||
}
|
||||
comments={comments.get('byId')}
|
||||
onClickAction={(action, id) => this.onCommentAction(action, id)}
|
||||
actions={['approve']}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
export const base = '/api/v1';
|
||||
|
||||
export const getInit = (method, body) => {
|
||||
const headers = new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
});
|
||||
|
||||
const init = {method, headers};
|
||||
if (method.toLowerCase() !== 'get') {
|
||||
init.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
return init;
|
||||
};
|
||||
|
||||
export const handleResp = res => {
|
||||
if (res.status === 401) {
|
||||
throw new Error('Not Authorized to make this request');
|
||||
} else if (res.status > 399) {
|
||||
throw new Error('Error! Status ', res.status);
|
||||
} else if (res.status === 204) {
|
||||
return res.text();
|
||||
} else {
|
||||
return res.json();
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './components/App';
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import {Map} from 'immutable';
|
||||
|
||||
import {
|
||||
FETCH_COMMENTERS_REQUEST,
|
||||
FETCH_COMMENTERS_FAILURE,
|
||||
FETCH_COMMENTERS_SUCCESS,
|
||||
SORT_UPDATE
|
||||
} from '../constants/community';
|
||||
|
||||
const initialState = Map({
|
||||
community: Map(),
|
||||
isFetching: false,
|
||||
error: '',
|
||||
commenters: [],
|
||||
field: 'created_at',
|
||||
asc: false,
|
||||
totalPages: 0,
|
||||
page: 0
|
||||
});
|
||||
|
||||
export default function community (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case FETCH_COMMENTERS_REQUEST :
|
||||
return state
|
||||
.set('isFetching', true);
|
||||
case FETCH_COMMENTERS_FAILURE :
|
||||
return state
|
||||
.set('isFetching', false)
|
||||
.set('error', action.error);
|
||||
case FETCH_COMMENTERS_SUCCESS : {
|
||||
const {commenters, type, ...rest} = action; // eslint-disable-line
|
||||
return state
|
||||
.merge({
|
||||
isFetching: false,
|
||||
error: '',
|
||||
...rest
|
||||
})
|
||||
.set('commenters', commenters); // Sets to normal array
|
||||
}
|
||||
case SORT_UPDATE :
|
||||
return state
|
||||
.set('field', action.sort.field)
|
||||
.set('asc', !state.get('asc'));
|
||||
default :
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
|
||||
import {combineReducers} from 'redux';
|
||||
import comments from 'reducers/comments';
|
||||
import settings from 'reducers/settings';
|
||||
import community from 'reducers/community';
|
||||
|
||||
// Combine all reducers into a main one
|
||||
export default combineReducers({
|
||||
settings,
|
||||
comments
|
||||
comments,
|
||||
community
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export default {
|
||||
en: {
|
||||
'community': {
|
||||
username_and_email: 'Username and Email',
|
||||
account_creation_date: 'Account Creation Date'
|
||||
},
|
||||
'modqueue': {
|
||||
'pending': 'pending',
|
||||
'rejected': 'rejected',
|
||||
@@ -24,6 +28,10 @@ export default {
|
||||
}
|
||||
},
|
||||
es: {
|
||||
'community': {
|
||||
username_and_email: 'Usuario y E-mail',
|
||||
account_creation_date: 'Fecha de creación de la cuenta'
|
||||
},
|
||||
'modqueue': {
|
||||
'pending': 'pendiente',
|
||||
'rejected': 'rechazado',
|
||||
|
||||
@@ -108,6 +108,7 @@ class CommentStream extends Component {
|
||||
appendItemArray={this.props.appendItemArray}
|
||||
updateItem={this.props.updateItem}
|
||||
id={rootItemId}
|
||||
premod={this.props.config.moderation}
|
||||
reply={false}/>
|
||||
</div>
|
||||
{
|
||||
@@ -138,6 +139,7 @@ class CommentStream extends Component {
|
||||
updateItem={this.props.updateItem}
|
||||
id={rootItemId}
|
||||
parent_id={commentId}
|
||||
premod={this.props.config.moderation}
|
||||
showReply={comment.showReply}/>
|
||||
{
|
||||
comment.children &&
|
||||
@@ -168,7 +170,7 @@ class CommentStream extends Component {
|
||||
})
|
||||
}
|
||||
<Notification
|
||||
notifLength={this.props.config.notifLength}
|
||||
notifLength={4500}
|
||||
clearNotification={this.props.clearNotification}
|
||||
notification={this.props.notification}/>
|
||||
</div>
|
||||
|
||||
@@ -14,17 +14,24 @@ export const FETCH_CONFIG_SUCCESS = 'FETCH_CONFIG_SUCCESS';
|
||||
* Action creators
|
||||
*/
|
||||
|
||||
export const fetchConfig = () => async (dispatch) => {
|
||||
dispatch({type: FETCH_CONFIG_REQUEST});
|
||||
export function fetchConfig () {
|
||||
return (dispatch) => {
|
||||
|
||||
dispatch({type: FETCH_CONFIG_REQUEST});
|
||||
|
||||
try {
|
||||
//TODO: Replace with fetching config from backend
|
||||
// const response = await fetch(`./talk.config.json`)
|
||||
// const json = await response.json()
|
||||
dispatch({type: FETCH_CONFIG_SUCCESS, config: fromJS({
|
||||
notifLength: 4500
|
||||
})});
|
||||
} catch (error) {
|
||||
dispatch({type: FETCH_CONFIG_FAILED});
|
||||
}
|
||||
};
|
||||
return fetch('/api/v1/settings')
|
||||
.then(
|
||||
response => {
|
||||
return response.ok ? response.json()
|
||||
: Promise.reject(`${response.status} ${response.statusText}`);
|
||||
}
|
||||
)
|
||||
.then((json) => {
|
||||
return dispatch({type: FETCH_CONFIG_SUCCESS, config: fromJS(json)});
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch({type: FETCH_CONFIG_FAILED, error});
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ export function getStream (assetId) {
|
||||
|
||||
export function getItemsArray (ids) {
|
||||
return (dispatch) => {
|
||||
return fetch(`/v1/item/${ ids}`)
|
||||
return fetch(`/v1/item/${ids}`)
|
||||
.then(
|
||||
response => {
|
||||
return response.ok ? response.json()
|
||||
@@ -241,7 +241,8 @@ export function postAction (item_id, action_type, user_id, item_type) {
|
||||
return response.ok ? response.json()
|
||||
: Promise.reject(`${response.status} ${response.statusText}`);
|
||||
}
|
||||
).then((json)=>{
|
||||
)
|
||||
.then((json)=>{
|
||||
return json;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
const packagename = 'coral-plugin-author-name';
|
||||
|
||||
const AuthorName = ({name}) =>
|
||||
<div className={`${packagename }-text`}>
|
||||
<div className={`${packagename}-text`}>
|
||||
{name}
|
||||
</div>;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
const name = 'coral-plugin-comment-count';
|
||||
|
||||
const CommentCount = ({items, id}) => {
|
||||
@@ -15,9 +16,11 @@ const CommentCount = ({items, id}) => {
|
||||
}
|
||||
}
|
||||
|
||||
return <div className={`${name }-text`}>
|
||||
{`${count } ${ count === 1 ? 'Comment' : 'Comments'}`}
|
||||
return <div className={`${name}-text`}>
|
||||
{`${count} ${count === 1 ? lang.t('comment') : lang.t('comment-plural')}`}
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default CommentCount;
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"en": {
|
||||
"comment": "Comment",
|
||||
"comment-plural": "Comments"
|
||||
},
|
||||
"es": {
|
||||
"comment": "Comentario",
|
||||
"comment-plural": "Comentarios"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
|
||||
const name = 'coral-plugin-commentbox';
|
||||
|
||||
@@ -19,7 +20,7 @@ class CommentBox extends Component {
|
||||
}
|
||||
|
||||
postComment = () => {
|
||||
const {postItem, updateItem, id, parent_id, addNotification, appendItemArray} = this.props;
|
||||
const {postItem, updateItem, id, parent_id, addNotification, appendItemArray, premod} = this.props;
|
||||
let comment = {
|
||||
body: this.state.body,
|
||||
asset_id: id,
|
||||
@@ -38,9 +39,14 @@ class CommentBox extends Component {
|
||||
updateItem(parent_id, 'showReply', false, 'comments');
|
||||
postItem(comment, 'comments')
|
||||
.then((comment_id) => {
|
||||
appendItemArray(parent_id || id, related, comment_id, !parent_id, parent_type);
|
||||
addNotification('success', 'Your comment has been posted.');
|
||||
}).catch((err) => console.error(err));
|
||||
if (premod === 'pre') {
|
||||
addNotification('success', lang.t('comment-post-notif-premod'));
|
||||
} else {
|
||||
appendItemArray(parent_id || id, related, comment_id, !parent_id, parent_type);
|
||||
addNotification('success', 'Your comment has been posted.');
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
this.setState({body: ''});
|
||||
}
|
||||
|
||||
@@ -54,7 +60,7 @@ class CommentBox extends Component {
|
||||
style={styles && styles.textarea}
|
||||
value={this.state.username}
|
||||
id={reply ? 'replyUser' : 'commentUser'}
|
||||
placeholder='Name'
|
||||
placeholder={lang.t('name')}
|
||||
onChange={(e) => this.setState({username: e.target.value})}/>
|
||||
</div>
|
||||
<div
|
||||
@@ -69,7 +75,7 @@ class CommentBox extends Component {
|
||||
className={`${name}-textarea`}
|
||||
style={styles && styles.textarea}
|
||||
value={this.state.body}
|
||||
placeholder='Comment'
|
||||
placeholder={lang.t('comment')}
|
||||
id={reply ? 'replyText' : 'commentText'}
|
||||
onChange={(e) => this.setState({body: e.target.value})}
|
||||
rows={3}/>
|
||||
@@ -88,15 +94,4 @@ class CommentBox extends Component {
|
||||
|
||||
export default CommentBox;
|
||||
|
||||
const lang = new I18n({
|
||||
en: {
|
||||
post: 'Post',
|
||||
reply: 'Reply',
|
||||
comment: 'Comment',
|
||||
},
|
||||
es: {
|
||||
post: 'Publicar',
|
||||
reply: 'Respuesta',
|
||||
comment: 'Comentario'
|
||||
}
|
||||
});
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"en": {
|
||||
"post": "Post",
|
||||
"reply": "Reply",
|
||||
"comment": "Comment",
|
||||
"name": "Name",
|
||||
"comment-post-notif": "Your comment has been posted.",
|
||||
"comment-post-notif-premod": "Thank you for reporting this comment. Our moderation team has been notified and will review it shortly."
|
||||
},
|
||||
"es": {
|
||||
"post": "Publicar",
|
||||
"reply": "Respuesta",
|
||||
"comment": "Comentario",
|
||||
"name": "Nombre",
|
||||
"comment-post-notif": "¡traduceme!",
|
||||
"comment-post-notif-premod": "¡traduceme!"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import React from 'react';
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
|
||||
const name = 'coral-plugin-flags';
|
||||
|
||||
@@ -10,7 +12,7 @@ const FlagButton = ({flag, id, postAction, addItem, updateItem, addNotification}
|
||||
addItem({...action, current_user:true}, 'actions');
|
||||
updateItem(action.item_id, action.action_type, action.id, 'comments');
|
||||
});
|
||||
addNotification('success', 'Thank you for reporting this comment. Our moderation team has been notified and will review it shortly.');
|
||||
addNotification('success', lang.t('flag-notif'));
|
||||
};
|
||||
|
||||
return <div className={`${name }-container`}>
|
||||
@@ -20,8 +22,8 @@ const FlagButton = ({flag, id, postAction, addItem, updateItem, addNotification}
|
||||
aria-hidden={true}>flag</i>
|
||||
{
|
||||
flagged
|
||||
? <span className={`${name }-button-text`}>Flagged</span>
|
||||
: <span className={`${name }-button-text`}>Flag</span>
|
||||
? <span className={`${name}-button-text`}>{lang.t('flag')}</span>
|
||||
: <span className={`${name}-button-text`}>{lang.t('flagged')}</span>
|
||||
}
|
||||
</button>
|
||||
</div>;
|
||||
@@ -37,3 +39,5 @@ const styles = {
|
||||
color: 'inherit'
|
||||
}
|
||||
};
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"en": {
|
||||
"flag": "Flag",
|
||||
"flagged": "Flagged",
|
||||
"flag-notif": "Thank you for reporting this comment. Our moderation team has been notified and will review it shortly."
|
||||
},
|
||||
"es": {
|
||||
"flag": "Marcar",
|
||||
"flagged": "Marcado",
|
||||
"flag-notif": "Gracias por marcar este comentario. Nuestro equipo de moderación ha sido notificado y muy pronto lo va a revisar."
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,11 @@ import CommentBox from '../coral-plugin-commentbox/CommentBox';
|
||||
const name = 'coral-plugin-replies';
|
||||
|
||||
const ReplyBox = (props) => <div
|
||||
className={`${name }-textarea`}
|
||||
className={`${name}-textarea`}
|
||||
style={props.styles && props.styles.container}>
|
||||
{
|
||||
props.showReply && <CommentBox
|
||||
id = {props.id}
|
||||
parent_id = {props.parent_id}
|
||||
postItem = {props.postItem}
|
||||
addNotification = {props.addNotification}
|
||||
appendItemArray = {props.appendItemArray}
|
||||
updateItem = {props.updateItem}
|
||||
{...props}
|
||||
comments = {props.child}
|
||||
reply = {true}/>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
|
||||
const name = 'coral-plugin-replies';
|
||||
|
||||
@@ -13,11 +14,4 @@ const ReplyButton = (props) => <button
|
||||
|
||||
export default ReplyButton;
|
||||
|
||||
const lang = new I18n({
|
||||
en: {
|
||||
'reply': 'Reply'
|
||||
},
|
||||
es: {
|
||||
'reply': '¡traduceme!'
|
||||
}
|
||||
});
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"en": {
|
||||
"reply": "Reply"
|
||||
},
|
||||
"es": {
|
||||
"reply": "Responder"
|
||||
}
|
||||
}
|
||||
+21
-6
@@ -86,9 +86,13 @@ CommentSchema.statics.findAcceptedAndNewByAssetId = function(asset_id) {
|
||||
* @param {String} action_type the type of action that was performed on the comment
|
||||
*/
|
||||
CommentSchema.statics.findByActionType = function(action_type) {
|
||||
return Action.findCommentsIdByActionType(action_type, 'comment').then((actions) => {
|
||||
return Comment.find({'id': {'$in': actions.map(function(a){return a.item_id;})}});
|
||||
});
|
||||
return Action
|
||||
.findCommentsIdByActionType(action_type, 'comment')
|
||||
.then((actions) => {
|
||||
return Comment.find({'id': {'$in': actions.map(function(a){
|
||||
return a.item_id;})}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -97,9 +101,20 @@ CommentSchema.statics.findByActionType = function(action_type) {
|
||||
* @param {String} status the status of the comment to search for
|
||||
*/
|
||||
CommentSchema.statics.findByStatusByActionType = function(status, action_type) {
|
||||
return Action.findCommentsIdByActionType(action_type, 'comment').then((actions) => {
|
||||
return Comment.find({'status': status, 'id': {'$in': actions.map(function(a){return a.item_id;})}});
|
||||
});
|
||||
return Action
|
||||
.findCommentsIdByActionType(action_type, 'comment')
|
||||
.then((actions) => {
|
||||
|
||||
return Comment.find({
|
||||
'status': status,
|
||||
'id': {
|
||||
'$in': actions.map(a => {
|
||||
return a.item_id;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+5
-4
@@ -20,7 +20,7 @@ SettingSchema.statics.init = function (defaults) {
|
||||
};
|
||||
|
||||
/**
|
||||
* gets the entire settings record and sends it back
|
||||
* Gets the entire settings record and sends it back
|
||||
* @return {Promise} settings the whole settings record
|
||||
*/
|
||||
SettingSchema.statics.getSettings = function () {
|
||||
@@ -28,7 +28,7 @@ SettingSchema.statics.getSettings = function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* gets the moderation settings and sends it back
|
||||
* Gets the moderation settings and sends it back
|
||||
* @return {Promise} moderation the settings for how to moderate comments
|
||||
*/
|
||||
SettingSchema.statics.getModerationSetting = function () {
|
||||
@@ -36,12 +36,13 @@ SettingSchema.statics.getModerationSetting = function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* this will update the settings object with whatever you pass in
|
||||
* This will update the settings object with whatever you pass in
|
||||
* @param {object} setting a hash of whatever settings you want to update
|
||||
* @return {Promise} settings Promise that resolves to the entire (updated) settings object.
|
||||
*/
|
||||
SettingSchema.statics.updateSettings = function (setting) {
|
||||
// there should only ever be one record unless something has gone wrong.
|
||||
// There should only ever be one record unless something has gone wrong.
|
||||
// In the future we may have multiple records for custom settings for objects/users.
|
||||
return this.findOneAndUpdate({id: '1'}, {$set: setting}, {new: true});
|
||||
};
|
||||
|
||||
|
||||
+59
-34
@@ -25,6 +25,11 @@ const UserSchema = new mongoose.Schema({
|
||||
}
|
||||
}],
|
||||
roles: [String]
|
||||
}, {
|
||||
timestamps: {
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at'
|
||||
}
|
||||
});
|
||||
|
||||
// Add the indixies on the user profile data.
|
||||
@@ -52,6 +57,22 @@ UserSchema.options.toJSON.transform = (doc, ret, options) => {
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* toObject overrides to remove the password field from the toObject
|
||||
* output.
|
||||
*/
|
||||
UserSchema.options.toObject = {};
|
||||
UserSchema.options.toObject.hide = 'password';
|
||||
UserSchema.options.toObject.transform = (doc, ret, options) => {
|
||||
if (options.hide) {
|
||||
options.hide.split(' ').forEach((prop) => {
|
||||
delete ret[prop];
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds a user given their email address that we have for them in the system
|
||||
* and ensures that the retuned user matches the password passed in as well.
|
||||
@@ -100,19 +121,22 @@ UserSchema.statics.findLocalUser = function(email, password) {
|
||||
UserSchema.statics.mergeUsers = function(dstUserID, srcUserID) {
|
||||
let srcUser, dstUser;
|
||||
|
||||
return Promise.all([
|
||||
User.findOne({id: dstUserID}).exec(),
|
||||
User.findOne({id: srcUserID}).exec()
|
||||
]).then((users) => {
|
||||
dstUser = users[0];
|
||||
srcUser = users[1];
|
||||
return Promise
|
||||
.all([
|
||||
User.findOne({id: dstUserID}).exec(),
|
||||
User.findOne({id: srcUserID}).exec()
|
||||
])
|
||||
.then((users) => {
|
||||
dstUser = users[0];
|
||||
srcUser = users[1];
|
||||
|
||||
srcUser.profiles.forEach((profile) => {
|
||||
dstUser.profiles.push(profile);
|
||||
});
|
||||
srcUser.profiles.forEach((profile) => {
|
||||
dstUser.profiles.push(profile);
|
||||
});
|
||||
|
||||
return srcUser.remove();
|
||||
}).then(() => dstUser.save());
|
||||
return srcUser.remove();
|
||||
})
|
||||
.then(() => dstUser.save());
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -122,33 +146,34 @@ UserSchema.statics.mergeUsers = function(dstUserID, srcUserID) {
|
||||
* @param {Function} done [description]
|
||||
*/
|
||||
UserSchema.statics.findOrCreateExternalUser = function(profile) {
|
||||
return User.findOne({
|
||||
profiles: {
|
||||
$elemMatch: {
|
||||
id: profile.id,
|
||||
provider: profile.provider
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((user) => {
|
||||
if (user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
// The user was not found, lets create them!
|
||||
user = new User({
|
||||
displayName: profile.displayName,
|
||||
roles: [],
|
||||
profiles: [
|
||||
{
|
||||
return User
|
||||
.findOne({
|
||||
profiles: {
|
||||
$elemMatch: {
|
||||
id: profile.id,
|
||||
provider: profile.provider
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((user) => {
|
||||
if (user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
return user.save();
|
||||
});
|
||||
// The user was not found, lets create them!
|
||||
user = new User({
|
||||
displayName: profile.displayName,
|
||||
roles: [],
|
||||
profiles: [
|
||||
{
|
||||
id: profile.id,
|
||||
provider: profile.provider
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return user.save();
|
||||
});
|
||||
};
|
||||
|
||||
UserSchema.statics.changePassword = function(id, password) {
|
||||
|
||||
@@ -12,17 +12,17 @@ const router = express.Router();
|
||||
router.get('/', (req, res, next) => {
|
||||
Comment.find({}).then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router.get('/:comment_id', (req, res, next) => {
|
||||
Comment.findById(req.params.comment_id).then((comment) => {
|
||||
res.status(200).json(comment);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.findById(req.params.comment_id)
|
||||
.then(comment => {
|
||||
res.status(200).json(comment);
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
@@ -31,20 +31,22 @@ router.get('/:comment_id', (req, res, next) => {
|
||||
|
||||
// Get all the comments that have that action_type over them.
|
||||
router.get('/action/:action_type', (req, res, next) => {
|
||||
Comment.findByActionType(req.params.action_type).then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.findByActionType(req.params.action_type)
|
||||
.then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
// Get all the comments that were rejected.
|
||||
router.get('/status/rejected', (req, res, next) => {
|
||||
Comment.findByStatus('rejected').then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.findByStatus('rejected')
|
||||
.then(comments => {
|
||||
res.status(200).json(comments);
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
// Returns back all the comments that are in the moderation queue. The moderation queue is pre or post moderated,
|
||||
@@ -52,17 +54,21 @@ router.get('/status/rejected', (req, res, next) => {
|
||||
// Pre-moderation: New comments are shown in the moderator queues immediately.
|
||||
// Post-moderation: New comments do not appear in moderation queues unless they are flagged by other users.
|
||||
router.get('/status/pending', (req, res, next) => {
|
||||
Setting.getModerationSetting().then(function({moderation}){
|
||||
let moderationValue = req.query.moderation;
|
||||
if (typeof moderationValue === 'undefined' || moderationValue === undefined) {
|
||||
moderationValue = moderation;
|
||||
}
|
||||
Comment.moderationQueue(moderationValue).then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
});
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
|
||||
Setting
|
||||
.getModerationSetting()
|
||||
.then(({moderation}) => {
|
||||
let moderationValue = req.query.moderation;
|
||||
if (typeof moderationValue === 'undefined' || moderationValue === undefined) {
|
||||
moderationValue = moderation;
|
||||
}
|
||||
Comment
|
||||
.moderationQueue(moderationValue)
|
||||
.then((comments) => {
|
||||
res.status(200).json(comments);
|
||||
});
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
@@ -70,27 +76,36 @@ router.get('/status/pending', (req, res, next) => {
|
||||
//==============================================================================
|
||||
|
||||
router.post('/', (req, res, next) => {
|
||||
|
||||
const {body, author_id, asset_id, parent_id, status, username} = req.body;
|
||||
Comment.new(body, author_id, asset_id, parent_id, status, username).then((comment) => {
|
||||
res.status(200).send({'id': comment.id});
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
|
||||
Comment
|
||||
.new(body, author_id, asset_id, parent_id, status, username)
|
||||
.then((comment) => {
|
||||
res.status(200).send({'id': comment.id});
|
||||
})
|
||||
.catch(error => {
|
||||
next(error);
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/:comment_id', (req, res, next) => {
|
||||
Comment.findById(req.params.comment_id).then((comment) => {
|
||||
comment.body = req.body.body;
|
||||
comment.author_id = req.body.author_id;
|
||||
comment.asset_id = req.body.asset_id;
|
||||
comment.parent_id = req.body.parent_id;
|
||||
comment.status = req.body.status;
|
||||
return comment.save();
|
||||
}).then((comment) => {
|
||||
res.status(200).send(comment);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.findById(req.params.comment_id)
|
||||
.then((comment) => {
|
||||
comment.body = req.body.body;
|
||||
comment.author_id = req.body.author_id;
|
||||
comment.asset_id = req.body.asset_id;
|
||||
comment.parent_id = req.body.parent_id;
|
||||
comment.status = req.body.status;
|
||||
return comment.save();
|
||||
})
|
||||
.then((comment) => {
|
||||
res.status(200).send(comment);
|
||||
})
|
||||
.catch(error => {
|
||||
next(error);
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/:comment_id/status', (req, res, next) => {
|
||||
@@ -103,11 +118,14 @@ router.post('/:comment_id/status', (req, res, next) => {
|
||||
});
|
||||
|
||||
router.post('/:comment_id/actions', (req, res, next) => {
|
||||
Comment.addAction(req.params.comment_id, req.body.user_id, req.body.action_type).then((action) => {
|
||||
res.status(200).send(action);
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.addAction(req.params.comment_id, req.body.user_id, req.body.action_type)
|
||||
.then((action) => {
|
||||
res.status(200).send(action);
|
||||
})
|
||||
.catch(error => {
|
||||
next(error);
|
||||
});
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
@@ -115,11 +133,14 @@ router.post('/:comment_id/actions', (req, res, next) => {
|
||||
//==============================================================================
|
||||
|
||||
router.delete('/:comment_id', (req, res, next) => {
|
||||
Comment.removeById(req.params.comment_id).then(() => {
|
||||
res.status(201).send('OK. Removed');
|
||||
}).catch(error => {
|
||||
next(error);
|
||||
});
|
||||
Comment
|
||||
.removeById(req.params.comment_id)
|
||||
.then(() => {
|
||||
res.status(201).send('OK. Removed');
|
||||
})
|
||||
.catch(error => {
|
||||
next(error);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -7,5 +7,6 @@ router.use('/auth', require('./auth'));
|
||||
router.use('/comments', require('./comments'));
|
||||
router.use('/settings', require('./settings'));
|
||||
router.use('/stream', require('./stream'));
|
||||
router.use('/user', require('./user'));
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -3,11 +3,17 @@ const router = express.Router();
|
||||
const Setting = require('../../../models/setting');
|
||||
|
||||
router.get('/', (req, res, next) => {
|
||||
Setting.getSettings().then(settings => res.json(settings)).catch(next);
|
||||
Setting
|
||||
.getSettings()
|
||||
.then(settings => res.json(settings))
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router.put('/', (req, res, next) => {
|
||||
Setting.updateSettings(req.body).then(() => res.status(204).end()).catch(next);
|
||||
Setting
|
||||
.updateSettings(req.body)
|
||||
.then(() => res.status(204).end())
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -36,7 +36,8 @@ router.get('/', (req, res, next) => {
|
||||
users,
|
||||
actions
|
||||
});
|
||||
}).catch(error => {
|
||||
})
|
||||
.catch(error => {
|
||||
next(error);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const User = require('../../../models/user');
|
||||
|
||||
router.get('/', (req, res, next) => {
|
||||
const {
|
||||
value = '',
|
||||
field = 'created_at',
|
||||
page = 1,
|
||||
asc = 'false',
|
||||
limit = 50 // Total Per Page
|
||||
} = req.query;
|
||||
|
||||
let q = {
|
||||
$or: [
|
||||
{
|
||||
'displayName': {
|
||||
$regex: new RegExp(`^${value}`),
|
||||
$options: 'i'
|
||||
},
|
||||
'profiles': {
|
||||
$elemMatch: {
|
||||
id: {
|
||||
$regex: new RegExp(`^${value}`),
|
||||
$options: 'i'
|
||||
},
|
||||
provider: 'local'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
Promise.all([
|
||||
User.find(q)
|
||||
.sort({[field]: (asc === 'true') ? 1 : -1})
|
||||
.skip((page - 1) * limit)
|
||||
.limit(limit),
|
||||
User.count()
|
||||
])
|
||||
.then(([data, count]) => {
|
||||
const users = data.map((user) => {
|
||||
const {displayName, created_at} = user;
|
||||
return {
|
||||
displayName,
|
||||
created_at,
|
||||
profiles: user.toObject().profiles
|
||||
};
|
||||
});
|
||||
|
||||
res.json({
|
||||
result: users,
|
||||
limit: Number(limit),
|
||||
count,
|
||||
page: Number(page),
|
||||
totalPages: Math.ceil(count / limit)
|
||||
});
|
||||
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -43,11 +43,13 @@ describe('update settings', () => {
|
||||
|
||||
return Setting.getSettings();
|
||||
|
||||
}).then(settings => {
|
||||
})
|
||||
.then(settings => {
|
||||
// confirm updated settings in db
|
||||
expect(settings).to.have.property('moderation');
|
||||
expect(settings.moderation).to.equal('post');
|
||||
}).catch(err => {
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,6 +82,12 @@ module.exports = {
|
||||
precss,
|
||||
new webpack.ProvidePlugin({
|
||||
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': `"${'development'}"`,
|
||||
'VERSION': `"${require('./package.json').version}"`
|
||||
}
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ devConfig.plugins = devConfig.plugins.concat([
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': `"${'production'}"`,
|
||||
'VERSION': `"${require('./package.json')}"`
|
||||
'VERSION': `"${require('./package.json').version}"`
|
||||
}
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
|
||||
Reference in New Issue
Block a user