diff --git a/ data-model.png b/ data-model.png new file mode 100644 index 000000000..43855b542 Binary files /dev/null and b/ data-model.png differ diff --git a/ data-model.xml b/ data-model.xml new file mode 100644 index 000000000..1597bf7d9 --- /dev/null +++ b/ data-model.xml @@ -0,0 +1 @@ +7Zxbb6M4FIB/TV5WmgjMNY+TtLP70JWqrVa781Q54IB3DI7AmTTz69cGc3VI0iYwKEMVVfHh2Bh/to99jsnMWEVvvydwG/5JfURmQPPfZsbDDABnofH/QnDIBZbr5IIgwX4u0ivBC/6BpFDmC3bYR2lDkVFKGN42hR6NY+SxhgwmCd031TaUNO+6hQFSBC8eJKr0H+yzMJe6llbJ/0A4CIs765q8sobetyChu1jebwaMTfaXX45gUZbUT0Po031NZDzOjFVCKcu/RW8rRETTFs2W5/vScbWsd4JidlEGK8/xHZKdfPYVjSKRO68fOxRtku5xRGDMU8uQRYQLdf51Q2P2IpU0nvZCTPwneKA7cf+U8fYoUsuQJvgH14dFZn45YZI+sEVpmJAVJTThgpjm9yozvYjC5G0SlPJsz8Vz6qXoCaasqAolBG5TvM4qJ1QimAQ4XlLGaCSViqf6UrtzBc1YyuZBCUNvnW2sl+T4gEA0Qiw5cBWZARgSthwMjmzzfdWzdFOqhLVeBVwphLI3B2XRFVH+RULtAGwrgPmlNlv+cKzJNWUJ/YZaLI7ggQQHMU8StBEliIbCfBx9lmJGt6KwLfRwHDxlOg9mJflLPq0Q7UPM0AuXizrt+bTCZZSXtyHZAAmx76NYcKYMMrgue9yW4phlLWQt+Ye32UqbWzOLP9eKp/UqzT9CPWErGvPngzjjh3iP2SPRay6EbR2nLekC+0K69g3gOgrcNfUPE97+8FpgOLyGqeCFaYrY6zSC+0TsuAOOYFdFvGPc5k2Me2Wsa+ZwkIty65A9hvnjTYh7RFwsuwZBDBTEfHHLdhPhPglbA661TEMhnFd1mqn7hewOuOIy1RWXlyDIkP8K1R3xRPl2uyZtwEWXqTo9dlt/otw/ZWPAVZelKyiRH6DCWcUfNaQBjSF5rKTLzHWHfNl8DeYwYZ+Fa7Him8mE40iqo9gvNDzCd2rYy4VSRRTzH2LsID1efKFPBceyIk9U9IgjXWwGDC37K68UXkk9uwNvmX9FHeaOVaS/yot5G4gHPwONNxTdJR5qWjv+hAE6AzdBBDL8vXmDY+Rk1mfRKSv3WOk7lZ3EMFtur7wOMlfFnzc1PNTUZF/vvE/pcy0My8KqF3dWv6hXl76uWaf0+Ze8xlXnLdvwsv6sLjFzinzaWl/i88kcpJ2Tw0NtwvJEqcmRKSviE002TghcI7Isnd3v8pxKp72syaxs53qftE67VD9pcwAarf1JFv7Rzlio0M0mRWzWnmfeh8pWd/XqZHTXgLT5YsR4Fgqe334tPHz8LIA1IiSG0Zuxrkxx3V7rTXstLXplrLW+jPUbZnVbzZNfy+WDtOOlUc+uzK0LzbhqxcExK+7ewoq/1/g6RtM46tZpY2o42in9q42poYbFcr/rPRrTfHCdmKuBaZsjnq7Vhc+9WdMzhMR0bbl2E5ExJkSqc+zeLOrZQWQb5pgsKlCR/J3yJmxTmY51nLaoncTt1rEOw7rwXEcZmLjGuwFUT+Xkh77KdwU6BvhPONdhqBbPx+mWwMNrDCM0Ye4P85DnO4Dqh56iDUNAHvKEB1B3GlOwYQjIwx7xsBWUwwUbhnde1D0Xc8deyPQzSjBvOrFQb3o0ysS1Ho2CX92jkVvLm8cl7Jb/3wQ9xSVa68jiTFhnnOFKfd04E/e4St0Et3XUmKqvdkNgENyjnyafRE5sMXUTyOYYxRbTVvcg97brP4tkYerN0TgmPur68hfjkznOzJbjbEy+TdO95bqhdhJA082mzdUcpxC0zfSIzzZ8cJUA1FVC12rx4m5w8bkT9bRvRH2UwLsM1Jsd4aRygjRtqxn6GdUMqW7O7i20cBaQu9BbsfpREVJfcbo7G3aaUBard8a07nOcWxqtEQfrP2Z9nH72o7rzsf3oRwCr/ufP2QsrCvcpenS6Z3SOarMF8+KXgovTmtcsURw1NjgFj67yRXaN+Z8QPHLUXTk7bKegUY94hwwaOeqmnrdh9Dox7pfxkDEj58iPNgjG0yTdJ+FBA0aO6tfepWh67btnxEO+E+yqjqApvD8I5SHfC3Z1dSBP8f0hKPf4YjBPVr/BlW+gq985Mx7/Bw== \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index f92aa27b1..eec982dac 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -36,7 +36,6 @@ "yoda": [1], "no-path-concat": [2], "no-process-exit": [2], - "camelcase": [1], "eol-last": [1], "no-continue": [1], "no-nested-ternary": [1], diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..079766d25 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,5 @@ +### Expected behavior + +### Actual behavior + +### Steps to reproduce behavior diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..c5ec0d6bf --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +## What does this PR do? + +## How do I test this PR? + +- click a button +- view the cat +- see the cat meow + +@coralproject/tech diff --git a/.gitignore b/.gitignore index b0359459e..d52442b57 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ npm-debug.log dist .DS_Store *.iml +.env diff --git a/README.md b/README.md index 5f8b6d3d7..70e2d1110 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Runs Talk. `npm test` ### Lint -`npm lint` +`npm run lint` ### Docs `swagger.yaml` diff --git a/bin/init.js b/bin/init.js new file mode 100644 index 000000000..d114d4819 --- /dev/null +++ b/bin/init.js @@ -0,0 +1,7 @@ +const Setting = require('../models/setting'); +const defaults = {id: '1', moderation: 'pre'}; + +Setting.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true}).then(() => { + console.log('created settings object.'); + process.exit(); +}).catch(console.error); diff --git a/client/coral-admin/.gitignore b/client/coral-admin/.gitignore new file mode 100644 index 000000000..c9c7cb580 --- /dev/null +++ b/client/coral-admin/.gitignore @@ -0,0 +1,7 @@ +node_modules +public/bundle.js +public/embed/comment-stream +.DS_Store +npm-debug.log +config.json +yarn.lock diff --git a/client/coral-admin/README.md b/client/coral-admin/README.md new file mode 100644 index 000000000..067a3cac9 --- /dev/null +++ b/client/coral-admin/README.md @@ -0,0 +1,23 @@ + +# Coral Admin + +This app handles moderation for Talk (and maybe more later on) + +## Installation + + $ npm install + $ cp config.sample.json config.json + +Then change `config.json` to adjust it to your project + +## Building for production + + $ npm run build + +The public folder has everything you need for deployment. You can just copy that folder to your favorite static web server + +## Development + + $ npm start + +A development server will be running at http://localhost:4132 diff --git a/client/coral-admin/config.sample.json b/client/coral-admin/config.sample.json new file mode 100644 index 000000000..5d23e2576 --- /dev/null +++ b/client/coral-admin/config.sample.json @@ -0,0 +1,5 @@ +{ + "basePath": "http://localhost:3142", + "talkHost": "http://localhost:16180", + "xeniaHost": "http://localhost:16180" +} diff --git a/client/coral-admin/index.ejs b/client/coral-admin/index.ejs new file mode 100644 index 000000000..9b5fe84bf --- /dev/null +++ b/client/coral-admin/index.ejs @@ -0,0 +1,22 @@ + + + + + + Talk - Coral Admin + + + + + +
+ + + diff --git a/client/coral-admin/package.json b/client/coral-admin/package.json new file mode 100644 index 000000000..c5a2d4c45 --- /dev/null +++ b/client/coral-admin/package.json @@ -0,0 +1,44 @@ +{ + "name": "coral-admin", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "./node_modules/.bin/webpack --config webpack.config.js", + "start": "./node_modules/.bin/webpack-dev-server --config webpack.config.dev.js --inline --hot --content-base public --port 3142" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "coral-framework": "0.0.1", + "hammerjs": "2.0.8", + "immutable": "3.8.1", + "keymaster": "1.6.2", + "material-design-lite": "1.2.1", + "react": "^15.3.2", + "react-dom": "^15.3.2", + "react-mdl": "^1.7.2", + "react-redux": "^4.4.5", + "react-router": "^3.0.0", + "redux": "3.6.0", + "redux-thunk": "2.1.0", + "timeago.js": "2.0.2", + "xenia-driver": "0.0.4" + }, + "devDependencies": { + "autoprefixer": "6.5.0", + "buble": "0.13.0", + "buble-loader": "0.3.0", + "copy-webpack-plugin": "3.0.1", + "css-loader": "0.25.0", + "json-loader": "0.5.4", + "postcss-loader": "0.13.0", + "postcss-modules": "0.5.2", + "precss": "1.4.0", + "standard": "8.2.0", + "style-loader": "0.13.1", + "webpack": "2.1.0-beta.25", + "webpack-dev-server": "1.16.1" + } +} diff --git a/client/coral-admin/public/index.html b/client/coral-admin/public/index.html new file mode 100644 index 000000000..707b82ebd --- /dev/null +++ b/client/coral-admin/public/index.html @@ -0,0 +1,22 @@ + + + + + + Talk - Coral Admin + + + + + +
+ + + diff --git a/client/coral-admin/public/manifest.json b/client/coral-admin/public/manifest.json new file mode 100644 index 000000000..5da846121 --- /dev/null +++ b/client/coral-admin/public/manifest.json @@ -0,0 +1,12 @@ +{ + "short_name": "Talk", + "name": "Talk", + "icons": [ + { + "src": "https://coralproject.net/images/icon-coral-white.svg", + "sizes": "150x150" + } + ], + "start_url": "./", + "display": "standalone" +} diff --git a/client/coral-admin/public/translations/en.json b/client/coral-admin/public/translations/en.json new file mode 100644 index 000000000..591de1754 --- /dev/null +++ b/client/coral-admin/public/translations/en.json @@ -0,0 +1,24 @@ +{ + "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" + } +} diff --git a/client/coral-admin/public/translations/es.json b/client/coral-admin/public/translations/es.json new file mode 100644 index 000000000..d151cf13c --- /dev/null +++ b/client/coral-admin/public/translations/es.json @@ -0,0 +1,13 @@ +{ + "modqueue": { + "pending": "pendiente", + "rejected": "rechazado", + "flagged": "marcado", + "shortcuts": "Atajos de teclado", + "close": "Cerrar" + }, + "comment": { + "flagged": "marcado", + "anon": "AnĂ³nimo" + } +} diff --git a/client/coral-admin/src/actions/comments.js b/client/coral-admin/src/actions/comments.js new file mode 100644 index 000000000..04751276e --- /dev/null +++ b/client/coral-admin/src/actions/comments.js @@ -0,0 +1,18 @@ + +/** + * Action disptacher related to comments + */ + +export const updateStatus = (status, id) => (dispatch, getState) => { + dispatch({ type: 'COMMENT_STATUS_UPDATE', id, status }) + dispatch({ type: 'COMMENT_UPDATE', comment: getState().comments.get('byId').get(id) }) +} + +export const flagComment = id => (dispatch, getState) => { + dispatch({ type: 'COMMENT_FLAG', id }) + dispatch({ type: 'COMMENT_UPDATE', comment: getState().comments.get('byId').get(id) }) +} + +export const createComment = (name, body) => dispatch => { + dispatch({ type: 'COMMENT_CREATE', name, body }) +} diff --git a/client/coral-admin/src/components/App.js b/client/coral-admin/src/components/App.js new file mode 100644 index 000000000..044d00989 --- /dev/null +++ b/client/coral-admin/src/components/App.js @@ -0,0 +1,33 @@ + +import React from 'react' +import { Provider } from 'react-redux' +import { Layout, Content } from 'react-mdl' +import 'material-design-lite' +import { Router, Route, browserHistory } from 'react-router' +import ModerationQueue from 'containers/ModerationQueue' +import Header from 'components/Header' +import store from 'services/store' +import CommentStream from 'containers/CommentStream' +import EmbedLink from 'components/EmbedLink' +import Configure from 'containers/Configure' + +export default class App extends React.Component { + render (props) { + return ( + + +
+
+ + + + + + +
+
+
+
+ ) + } +} diff --git a/client/coral-admin/src/components/Comment.js b/client/coral-admin/src/components/Comment.js new file mode 100644 index 000000000..ce4f6686e --- /dev/null +++ b/client/coral-admin/src/components/Comment.js @@ -0,0 +1,45 @@ + +import React from 'react' +import { Button, Icon } from 'react-mdl' +import timeago from 'timeago.js' +import styles from './CommentList.css' +import I18n from 'coral-framework/i18n/i18n' +import translations from '../translations' + +// Render a single comment for the list +export default props => ( +
  • +
    +
    + person + {props.comment.get('data').get('name') || lang.t('comment.anon')} + {timeago().format(props.comment.get('data').get('createdAt') || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))} + {props.comment.get('data').get('flagged') ?

    {lang.t('comment.flagged')}

    : null} +
    +
    + {props.actions.map(action => canShowAction(action, props.comment) ? ( + + ) : null)} +
    +
    +
    + {props.comment.get('data').get('body')} +
    +
  • +) + +// Check if an action can be performed over a comment +const canShowAction = (action, comment) => { + const status = comment.get('data').get('status') + const flagged = comment.get('data').get('flagged') + if (action === 'flag' && (status !== 'Untouched' || flagged === true)) { + return false + } + return true +} + +const lang = new I18n(translations) diff --git a/client/coral-admin/src/components/CommentBox.css b/client/coral-admin/src/components/CommentBox.css new file mode 100644 index 000000000..34c7ca6ef --- /dev/null +++ b/client/coral-admin/src/components/CommentBox.css @@ -0,0 +1,4 @@ + +.textareaContainer { + width: 100%; +} diff --git a/client/coral-admin/src/components/CommentBox.js b/client/coral-admin/src/components/CommentBox.js new file mode 100644 index 000000000..f0f0adbf2 --- /dev/null +++ b/client/coral-admin/src/components/CommentBox.js @@ -0,0 +1,35 @@ + +import React from 'react' +import styles from './CommentBox.css' +import { Button } from 'react-mdl' + +// Renders a comment box for creating a new comment +export default class CommentBox extends React.Component { + constructor (props) { + super(props) + this.state = { name: '', body: '' } + this.onSubmit = this.onSubmit.bind(this) + } + + onSubmit () { + const { name, body } = this.state + this.props.onSubmit({ name, body }) + this.setState({ body: '', name: '' }) + } + + render (props, { name, body }) { + return ( +
    +
    + + +
    +
    +