From d765181edc1ed6919e4d2ba4459979891efeef65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Fri, 4 Nov 2016 23:37:22 -0300 Subject: [PATCH 01/60] Added react, redux, glamor and babel --- .babelrc | 24 ++++++ .eslintrc | 24 ++++++ .gitignore | 2 - lib/app/actions/apps.js | 31 ++++++++ lib/app/actions/index.js | 3 + lib/app/components/Drawer/index.js | 49 ++++++++++++ lib/app/components/Footer/index.js | 16 ++++ lib/app/components/Footer/styles.js | 20 +++++ lib/app/containers/Header.js | 49 ++++++++++++ lib/app/home.js | 17 +++++ lib/app/reducers/apps.js | 46 +++++++++++ lib/app/reducers/index.js | 3 + lib/app/server/index.js | 25 ++++++ lib/app/server/public/app.css | 114 ++++++++++++++++++++++++++++ lib/app/server/templates/home.pug | 12 +++ lib/app/store/index.js | 5 ++ package.json | 41 +++++++++- webpack.config.babel.js | 48 ++++++++++++ 18 files changed, 524 insertions(+), 5 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintrc create mode 100644 lib/app/actions/apps.js create mode 100644 lib/app/actions/index.js create mode 100644 lib/app/components/Drawer/index.js create mode 100644 lib/app/components/Footer/index.js create mode 100644 lib/app/components/Footer/styles.js create mode 100644 lib/app/containers/Header.js create mode 100644 lib/app/home.js create mode 100644 lib/app/reducers/apps.js create mode 100644 lib/app/reducers/index.js create mode 100644 lib/app/server/index.js create mode 100644 lib/app/server/public/app.css create mode 100644 lib/app/server/templates/home.pug create mode 100644 lib/app/store/index.js create mode 100644 webpack.config.babel.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..b36fc3a --- /dev/null +++ b/.babelrc @@ -0,0 +1,24 @@ +{ + "presets": ["es2015", "stage-0", "react"], + "plugins": [ + "transform-runtime" + ], + "env": { + "start": { + "plugins": [ + "react-transform" + ] + }, + "extra": { + "react-transform": { + "transforms": [ + { + "transform": "react-transform-hmr", + "imports": ["react"], + "locals": ["module"] + } + ] + } + } + } +} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..0bc6cfd --- /dev/null +++ b/.eslintrc @@ -0,0 +1,24 @@ +{ + "parser": "babel-eslint", + "extends": ["standard", "standard-react"], + "plugins": [ + "react" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true, + "experimentalObjectRestSpread": true + } + }, + "env": { + "node": true, + "es6": true + }, + "rules": { + "react/jsx-curly-spacing": [2, "never"], + "space-before-function-paren": [2, "never"], + "object-curly-spacing": [2, "always"], + "array-bracket-spacing": [2, "never"], + "no-console": 2 + } +} diff --git a/.gitignore b/.gitignore index f952ee6..8c2dd89 100755 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,4 @@ node_modules /mm-config.*.json # Extra ignores -components -public .DS_Store diff --git a/lib/app/actions/apps.js b/lib/app/actions/apps.js new file mode 100644 index 0000000..378c2f0 --- /dev/null +++ b/lib/app/actions/apps.js @@ -0,0 +1,31 @@ +const fetch = require('isomorphic-fetch') + +module.exports.fetchApps = () => (dispatch, getState) => { + dispatch(requestApps()) + fetch('/api/applications/approved') + .then(response => response.status >= 400 ? dispatch(failReceivingApps(response.status)) : response.json()) + .then(data => dispatch(receiveApps(data))) +} + +const requestApps = () => ({ + type: 'REQUEST_APPS' +}) + +const receiveApps = apps => ({ + type: 'RECEIVE_APPS', + apps +}) + +const failReceivingApps = error => ({ + type: 'FAIL_RECEIVING_APPS', + error +}) + +const filterApps = filters => ({ + type: 'FILTER_APPS', + filters +}) + +const clearAppsFilters = () => ({ + type: 'CLEAR_APPS_FILTERS' +}) diff --git a/lib/app/actions/index.js b/lib/app/actions/index.js new file mode 100644 index 0000000..15f0c8a --- /dev/null +++ b/lib/app/actions/index.js @@ -0,0 +1,3 @@ +const apps = require('./apps') + +module.exports.fetchApps = apps.fetchApps diff --git a/lib/app/components/Drawer/index.js b/lib/app/components/Drawer/index.js new file mode 100644 index 0000000..df5e6a7 --- /dev/null +++ b/lib/app/components/Drawer/index.js @@ -0,0 +1,49 @@ +const React = require('react') + +class Drawer extends React.Component { + render () { + return ( + + ) + } +} + +module.exports = Drawer diff --git a/lib/app/components/Footer/index.js b/lib/app/components/Footer/index.js new file mode 100644 index 0000000..2e06f0c --- /dev/null +++ b/lib/app/components/Footer/index.js @@ -0,0 +1,16 @@ +const React = require('react') +const { footer, container } = require('./styles') + +class Footer extends React.Component { + render () { + return ( + + ) + } +} + +module.exports = Footer diff --git a/lib/app/components/Footer/styles.js b/lib/app/components/Footer/styles.js new file mode 100644 index 0000000..f74efb7 --- /dev/null +++ b/lib/app/components/Footer/styles.js @@ -0,0 +1,20 @@ +const { style, merge, $ } = require('glamor') + +module.exports.footer = merge({ + paddingTop: '60px', + paddingBottom: '30px', + textAlign: 'center' + }, + $(' a', { + fontWeight: 'bold' + })) + +module.exports.container = style({ + paddingRight: '15px', + paddingLeft: '15px', + marginRight: 'auto', + marginLeft: 'auto', + '@media (min-width: 768px)': { + width: '750px' + } +}) diff --git a/lib/app/containers/Header.js b/lib/app/containers/Header.js new file mode 100644 index 0000000..da6f59b --- /dev/null +++ b/lib/app/containers/Header.js @@ -0,0 +1,49 @@ +const React = require('react') +const { style } = require('glamor') + +const Drawer = require('../components/Drawer') + +const siteHeader = style({ + height: '80px', + borderBottom: '2px', + backgroundColor: '#fafafa', + ':after': { + content: '', + display: 'block', + position: 'absolute', + bottom: 0, + left: 0, + width: '100%', + height: '1px', + backgroundPosition: 'center center', + backgroundImage: 'repeating-linear-gradient(to right, #f7c64d 0px, #f7c64d 120px, #61baa8 120px, #61baa8 240px, #1394af 240px, #1394af 360px, #d93f5d 360px, #d93f5d 480px, #714c80 480px, #714c80 600px, #e16b55 600px, #e16b55 720px)' + } +}) + +class Header extends React.Component { + render () { + return ( + + ) + } +} + +module.exports = Header diff --git a/lib/app/home.js b/lib/app/home.js new file mode 100644 index 0000000..b0b128b --- /dev/null +++ b/lib/app/home.js @@ -0,0 +1,17 @@ +const React = require('react') +const ReactDOM = require('react-dom') + +const store = require('./store') +const actions = require('./actions') + +const Header = require('./containers/Header') +const Footer = require('./components/Footer') + +store.dispatch(actions.fetchApps()) + +ReactDOM.render( +
+
+ Helo worl +
+
, document.getElementById('react-root')) diff --git a/lib/app/reducers/apps.js b/lib/app/reducers/apps.js new file mode 100644 index 0000000..b906a4d --- /dev/null +++ b/lib/app/reducers/apps.js @@ -0,0 +1,46 @@ +const initialState = { + items: [], + invalid: true, + fetching: false, + filters: [], + error: null +} + +module.exports = (state = initialState, action) => { + switch (action.type) { + case 'REQUEST_APPS': + return { + ...state, + error: null, + invalid: true, + fetching: true + } + case 'RECEIVE_APPS': + return { + ...state, + error: null, + invalid: false, + fetching: false, + items: action.apps + } + case 'FAIL_RECEIVING_APPS': + return { + ...state, + error: action.error, + invalid: true, + fetching: false + } + case 'FILTER_APPS': + return { + ...state, + filters: action.filters + } + case 'CLEAR_APPS_FILTERS': + return { + ...state, + filters: [] + } + default: + return state + } +} diff --git a/lib/app/reducers/index.js b/lib/app/reducers/index.js new file mode 100644 index 0000000..1cc74b9 --- /dev/null +++ b/lib/app/reducers/index.js @@ -0,0 +1,3 @@ +const combineReducers = require('redux').combineReducers + +module.exports = combineReducers([ require('./apps') ]) diff --git a/lib/app/server/index.js b/lib/app/server/index.js new file mode 100644 index 0000000..d1372c8 --- /dev/null +++ b/lib/app/server/index.js @@ -0,0 +1,25 @@ +const express = require('express') +const app = express() + +app.set('view engine', 'pug') +app.set('views', './lib/app/server/templates') + +const webpack = require('webpack') +const webpackConfig = require('../../../webpack.config.babel') +const compiler = webpack(webpackConfig) + +app.use(express.static('./public')) + +app.use(require('webpack-dev-middleware')(compiler, { + noInfo: true, + publicPath: webpackConfig.output.publicPath +})) + +app.use(require('webpack-hot-middleware')(compiler)) + + +app.get('/', (req, res) => { + res.render('home', { algo: 4 }) +}) + +app.listen(3000) diff --git a/lib/app/server/public/app.css b/lib/app/server/public/app.css new file mode 100644 index 0000000..4c5abe2 --- /dev/null +++ b/lib/app/server/public/app.css @@ -0,0 +1,114 @@ +html, +body { + height: 100%; + margin: 0; + padding: 0; +} + +body { + background-color: #dfdfdf; + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + padding-top: 80px; + transition: all ease 0.3s; + -webkit-font-smoothing: antialiased; +} + +.no-gutter [class*="col-"] { + padding: 0 !important; +} + +h1, +h2, +h3 { + font-weight: 100; +} + +a { + color: #333; +} + +a:focus { + outline: none; +} + +a:hover { + color: #333; +} + +.btn { + border-radius: 1px; + box-shadow: none; + border: 0; +} + +.btn-primary { + color: #fafafa; + border-color: transparent; + background-color: #27aeaa; +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary:focus, +.btn-primary.active { + color: #fafafa; + background-color: #239d99; +} + +.btn-primary:hover:active, +.btn-primary:active:focus { + color: #fafafa; + box-shadow: inset 0 3px 5px rgba(0,0,0,0.125); + background-color: #219491; +} + +.btn-upvote span { + font-family: monospace; + font-weight: 900; +} + +.btn-upvote i:before { + position: relative; + top: 0.09em; + font-size: 1.4em; + line-height: 0.8; +} + +.app-logo { + position: relative; + display: block; + width: 100%; + background-repeat: no-repeat; + background-size: 70%; + background-position: center center; +} + +.app-logo h1 { + position: absolute; + visibility: hidden; + opacity: 0; + pointer-events: none; +} + +.app-logo:after { + content: ''; + display: block; + padding-top: 64%; +} + +textarea { + resize: none; +} + +.modal .modal-header, +.modal .modal-footer { + background-color: #f4f4f4; +} + +.modal .modal-header { + font-weight: bold; +} + +.site-content { + padding-top: 30px; +} diff --git a/lib/app/server/templates/home.pug b/lib/app/server/templates/home.pug new file mode 100644 index 0000000..31700cf --- /dev/null +++ b/lib/app/server/templates/home.pug @@ -0,0 +1,12 @@ +doctype html +html + head + title Civic Stack + meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no") + link(href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css", rel="stylesheet", media="screen") + link(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css", rel="stylesheet", media="screen") + link(rel="stylesheet", href="/app.css") + body + #react-root=reactOutput + script(type="text/javascript", src="/dist/vendors.js") + script(type="text/javascript", src="/dist/home.js") diff --git a/lib/app/store/index.js b/lib/app/store/index.js new file mode 100644 index 0000000..f56370c --- /dev/null +++ b/lib/app/store/index.js @@ -0,0 +1,5 @@ +const { createStore, applyMiddleware } = require('redux') +const thunk = require('redux-thunk').default +const reducers = require('../reducers') + +module.exports = createStore(reducers, applyMiddleware(thunk)) diff --git a/package.json b/package.json index f8eeaf8..dc718ac 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,14 @@ }, "dependencies": { "autoprefixer-stylus": "^0.9.4", + "babel-cli": "^6.18.0", + "babel-loader": "^6.2.7", + "babel-plugin-react-transform": "^2.0.2", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-polyfill": "^6.16.0", + "babel-preset-es2015": "^6.18.0", + "babel-preset-react": "^6.16.0", + "babel-preset-stage-0": "^6.16.0", "batch": "0.5.2", "bluebird": "^3.4.0", "body-parser": "1.12.0", @@ -44,6 +52,9 @@ "errorhandler": "1.3.0", "express": "4.12.0", "express-session": "v1.9.2", + "extract-text-webpack-plugin": "^1.0.1", + "glamor": "^2.17.14", + "isomorphic-fetch": "^2.2.1", "jade": "1.7.0 ", "merge-util": "0.1.0", "mkdirp": "0.5.0", @@ -58,18 +69,36 @@ "passport": "0.2.0", "passport-github": "0.1.5", "passport-twitter": "1.0.2", + "pug": "^2.0.0-beta6", + "react": "^15.3.2", + "react-dom": "^15.3.2", + "react-redux": "^4.4.5", "ready": "0.1.1", + "redux": "^3.6.0", + "redux-thunk": "^2.1.0", "serve-favicon": "2.1.7", "string-to-js": "0.0.1", "stylus": "0.49.3", "t-component": "1.0.0", - "type-component": "0.0.1" + "type-component": "0.0.1", + "webpack": "^1.13.3" }, "scripts": { + "start": "node ./lib/app/server", + "build": "webpack -p --colors --config webpack.config.babel.js", "postinstall": "node ./bin/civicstack-install --config && node ./bin/civicstack-config && node ./bin/civicstack-build" }, "devDependencies": { + "eslint": "^3.9.1", "mongodb-migrations": "^0.5.2", + "react-transform-hmr": "^1.0.4", + "eslint-config-standard": "^6.0.0", + "eslint-config-standard-react": "^4.0.0", + "eslint-plugin-promise": "^2.0.1", + "eslint-plugin-react": "^6.3.0", + "eslint-plugin-standard": "^2.0.0", + "webpack-dev-middleware": "^1.8.4", + "webpack-hot-middleware": "^2.13.1", "xo": "^0.16.0" }, "xo": { @@ -81,8 +110,14 @@ ], "rules": { "import/no-extraneous-dependencies": 0, - "curly": ["error", "multi-line"], - "space-before-function-paren": ["error", "always"] + "curly": [ + "error", + "multi-line" + ], + "space-before-function-paren": [ + "error", + "always" + ] } } } diff --git a/webpack.config.babel.js b/webpack.config.babel.js new file mode 100644 index 0000000..31b32a2 --- /dev/null +++ b/webpack.config.babel.js @@ -0,0 +1,48 @@ +const path = require('path') +const webpack = require('webpack') +const ExtractTextPlugin = require('extract-text-webpack-plugin') + +const paths = { + app: path.join(__dirname, 'lib', 'app'), + home: path.join(__dirname, 'lib', 'app', 'home.js'), + build: path.join(__dirname, 'dist') +} + +const entry = commonEntry => ({ + home: [...commonEntry, paths.home], + vendors: ['react'] +}) + +const resolve = { + extensions: ['', '.js', '.jsx'] +} + +const output = { + path: paths.build, + filename: '[name].js', + publicPath: '/dist/' +} + +const loaders = [ + { + test: /\.jsx?$/, + loader: 'babel-loader', + include: [paths.app] + } +] + +module.exports = { + entry: entry(['babel-polyfill', 'webpack-hot-middleware/client']), + resolve, + output, + // https://github.com/webpack/webpack/issues/91 + devtool: '#cheap-module-eval-source-map', + module: { loaders }, + plugins: [ + new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'), + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin(), + new ExtractTextPlugin('[name].css') + ] +} From 2388ee564d8949e5076a461fb25427baf081392c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 14:19:41 -0300 Subject: [PATCH 02/60] Refactor components --- lib/app/components/Drawer/index.js | 87 +++++++++++++++--------------- lib/app/components/Header/index.js | 47 ++++++++++++++++ lib/app/containers/App.js | 39 ++++++++++++++ lib/app/containers/Header.js | 49 ----------------- lib/app/home.js | 12 ++--- 5 files changed, 135 insertions(+), 99 deletions(-) create mode 100644 lib/app/components/Header/index.js create mode 100644 lib/app/containers/App.js delete mode 100644 lib/app/containers/Header.js diff --git a/lib/app/components/Drawer/index.js b/lib/app/components/Drawer/index.js index df5e6a7..c8691f8 100644 --- a/lib/app/components/Drawer/index.js +++ b/lib/app/components/Drawer/index.js @@ -1,49 +1,50 @@ const React = require('react') +const { PropTypes } = React + +const Drawer = ({ onCloseClick }) => ( + +) + +Drawer.propTypes = { + onCloseClick: PropTypes.func } module.exports = Drawer diff --git a/lib/app/components/Header/index.js b/lib/app/components/Header/index.js new file mode 100644 index 0000000..3500f8c --- /dev/null +++ b/lib/app/components/Header/index.js @@ -0,0 +1,47 @@ +const React = require('react') +const { PropTypes } = React +const { style } = require('glamor') + +const siteHeader = style({ + height: '80px', + borderBottom: '2px', + backgroundColor: '#fafafa', + ':after': { + content: '', + display: 'block', + position: 'absolute', + bottom: 0, + left: 0, + width: '100%', + height: '1px', + backgroundPosition: 'center center', + backgroundImage: 'repeating-linear-gradient(to right, #f7c64d 0px, #f7c64d 120px, #61baa8 120px, #61baa8 240px, #1394af 240px, #1394af 360px, #d93f5d 360px, #d93f5d 480px, #714c80 480px, #714c80 600px, #e16b55 600px, #e16b55 720px)' + } +}) + +const Header = ({ onHamburgerClick }) => ( + +) + +Header.propTypes = { + onHamburgerClick: PropTypes.func +} + +module.exports = Header diff --git a/lib/app/containers/App.js b/lib/app/containers/App.js new file mode 100644 index 0000000..b19c983 --- /dev/null +++ b/lib/app/containers/App.js @@ -0,0 +1,39 @@ +const React = require('react') +const { connect } = require('react-redux') + +const Header = require('../components/Header') +const Footer = require('../components/Footer') +const Drawer = require('../components/Drawer') + +class App extends React.Component { + constructor (props) { + super(props) + this.state = { + showDrawer: false + } + } + + toggleDrawer = () => { + this.setState({ + showDrawer: !this.state.showDrawer + }) + } + + render () { + const { showDrawer } = this.state + + return ( +
+
+
+ {showDrawer ? : null} +
+ ) + } +} + +const mapStateToProps = state => ({ + +}) + +module.exports = connect(mapStateToProps)(App) diff --git a/lib/app/containers/Header.js b/lib/app/containers/Header.js deleted file mode 100644 index da6f59b..0000000 --- a/lib/app/containers/Header.js +++ /dev/null @@ -1,49 +0,0 @@ -const React = require('react') -const { style } = require('glamor') - -const Drawer = require('../components/Drawer') - -const siteHeader = style({ - height: '80px', - borderBottom: '2px', - backgroundColor: '#fafafa', - ':after': { - content: '', - display: 'block', - position: 'absolute', - bottom: 0, - left: 0, - width: '100%', - height: '1px', - backgroundPosition: 'center center', - backgroundImage: 'repeating-linear-gradient(to right, #f7c64d 0px, #f7c64d 120px, #61baa8 120px, #61baa8 240px, #1394af 240px, #1394af 360px, #d93f5d 360px, #d93f5d 480px, #714c80 480px, #714c80 600px, #e16b55 600px, #e16b55 720px)' - } -}) - -class Header extends React.Component { - render () { - return ( - - ) - } -} - -module.exports = Header diff --git a/lib/app/home.js b/lib/app/home.js index b0b128b..99761f5 100644 --- a/lib/app/home.js +++ b/lib/app/home.js @@ -1,17 +1,15 @@ const React = require('react') const ReactDOM = require('react-dom') +const { Provider } = require('react-redux') const store = require('./store') const actions = require('./actions') -const Header = require('./containers/Header') -const Footer = require('./components/Footer') +const App = require('./containers/App') store.dispatch(actions.fetchApps()) ReactDOM.render( -
-
- Helo worl -
-
, document.getElementById('react-root')) + + + , document.getElementById('react-root')) From 1a58e1575f8ed52c201c40aa8b004424405b9b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 14:20:03 -0300 Subject: [PATCH 03/60] Tune up linter rules --- .eslintignore | 2 ++ .eslintrc | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..b947077 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/.eslintrc b/.eslintrc index 0bc6cfd..0b5d4cf 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,7 +16,7 @@ }, "rules": { "react/jsx-curly-spacing": [2, "never"], - "space-before-function-paren": [2, "never"], + "space-before-function-paren": [2, "always"], "object-curly-spacing": [2, "always"], "array-bracket-spacing": [2, "never"], "no-console": 2 diff --git a/package.json b/package.json index dc718ac..ef78670 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "scripts": { "start": "node ./lib/app/server", "build": "webpack -p --colors --config webpack.config.babel.js", - "postinstall": "node ./bin/civicstack-install --config && node ./bin/civicstack-config && node ./bin/civicstack-build" + "lint": "eslint ." }, "devDependencies": { "eslint": "^3.9.1", From c17e6fa8e4dcd288f903f761131d1854d9f4c4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 14:20:13 -0300 Subject: [PATCH 04/60] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef78670..cf0651f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "civic-stack", - "version": "1.1.0", + "version": "2.0.0", "description": "Stack of online civic webapps", "main": "index.js", "repository": { From 61ff3e9ac6ef11dd060cb19f467fe9a57b2b50dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 16:13:14 -0300 Subject: [PATCH 05/60] Add build dirs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8c2dd89..e11fbd5 100755 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ node_modules /mm-config.*.json # Extra ignores +dist +public .DS_Store From 766a1bbef62ce1ec1bfa78bd0f82aedce9500da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 16:14:16 -0300 Subject: [PATCH 06/60] Make server to work --- lib/app/actions/apps.js | 7 +- lib/app/server/public/app.css | 114 -------------- lib/models/country.js | 31 ---- lib/models/i18n-schema.js | 14 -- lib/server/api/apps/index.js | 191 ++++++++++++++++++++++++ lib/{ => server}/db-api/application.js | 29 +--- lib/{ => server}/db-api/country.js | 6 +- lib/{ => server}/db-api/index.js | 0 lib/{ => server}/db-api/license.js | 4 +- lib/{ => server}/db-api/tag.js | 6 +- lib/{ => server}/db-api/technology.js | 2 +- lib/{app => }/server/index.js | 6 +- lib/{ => server}/models/application.js | 49 +++--- lib/server/models/country.js | 26 ++++ lib/server/models/i18n-schema.js | 14 ++ lib/{ => server}/models/index.js | 4 +- lib/{ => server}/models/license.js | 0 lib/{ => server}/models/tag.js | 0 lib/{ => server}/models/technology.js | 0 lib/{ => server}/models/user.js | 27 ++-- lib/{app => }/server/templates/home.pug | 0 lib/server/utils/accepts.js | 56 +++++++ lib/{ => server}/utils/index.js | 3 + lib/server/utils/open-graph.js | 37 +++++ package.json | 2 +- 25 files changed, 394 insertions(+), 234 deletions(-) delete mode 100644 lib/app/server/public/app.css delete mode 100644 lib/models/country.js delete mode 100644 lib/models/i18n-schema.js create mode 100644 lib/server/api/apps/index.js rename lib/{ => server}/db-api/application.js (93%) rename lib/{ => server}/db-api/country.js (98%) rename lib/{ => server}/db-api/index.js (100%) rename lib/{ => server}/db-api/license.js (98%) rename lib/{ => server}/db-api/tag.js (98%) rename lib/{ => server}/db-api/technology.js (99%) rename lib/{app => }/server/index.js (73%) rename lib/{ => server}/models/application.js (73%) create mode 100644 lib/server/models/country.js create mode 100644 lib/server/models/i18n-schema.js rename lib/{ => server}/models/index.js (82%) rename lib/{ => server}/models/license.js (100%) rename lib/{ => server}/models/tag.js (100%) rename lib/{ => server}/models/technology.js (100%) rename lib/{ => server}/models/user.js (84%) rename lib/{app => }/server/templates/home.pug (100%) create mode 100644 lib/server/utils/accepts.js rename lib/{ => server}/utils/index.js (97%) create mode 100644 lib/server/utils/open-graph.js diff --git a/lib/app/actions/apps.js b/lib/app/actions/apps.js index 378c2f0..01f937e 100644 --- a/lib/app/actions/apps.js +++ b/lib/app/actions/apps.js @@ -2,7 +2,12 @@ const fetch = require('isomorphic-fetch') module.exports.fetchApps = () => (dispatch, getState) => { dispatch(requestApps()) - fetch('/api/applications/approved') + fetch('/api/applications/approved', { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }) .then(response => response.status >= 400 ? dispatch(failReceivingApps(response.status)) : response.json()) .then(data => dispatch(receiveApps(data))) } diff --git a/lib/app/server/public/app.css b/lib/app/server/public/app.css deleted file mode 100644 index 4c5abe2..0000000 --- a/lib/app/server/public/app.css +++ /dev/null @@ -1,114 +0,0 @@ -html, -body { - height: 100%; - margin: 0; - padding: 0; -} - -body { - background-color: #dfdfdf; - font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - padding-top: 80px; - transition: all ease 0.3s; - -webkit-font-smoothing: antialiased; -} - -.no-gutter [class*="col-"] { - padding: 0 !important; -} - -h1, -h2, -h3 { - font-weight: 100; -} - -a { - color: #333; -} - -a:focus { - outline: none; -} - -a:hover { - color: #333; -} - -.btn { - border-radius: 1px; - box-shadow: none; - border: 0; -} - -.btn-primary { - color: #fafafa; - border-color: transparent; - background-color: #27aeaa; -} - -.btn-primary:hover, -.btn-primary:active, -.btn-primary:focus, -.btn-primary.active { - color: #fafafa; - background-color: #239d99; -} - -.btn-primary:hover:active, -.btn-primary:active:focus { - color: #fafafa; - box-shadow: inset 0 3px 5px rgba(0,0,0,0.125); - background-color: #219491; -} - -.btn-upvote span { - font-family: monospace; - font-weight: 900; -} - -.btn-upvote i:before { - position: relative; - top: 0.09em; - font-size: 1.4em; - line-height: 0.8; -} - -.app-logo { - position: relative; - display: block; - width: 100%; - background-repeat: no-repeat; - background-size: 70%; - background-position: center center; -} - -.app-logo h1 { - position: absolute; - visibility: hidden; - opacity: 0; - pointer-events: none; -} - -.app-logo:after { - content: ''; - display: block; - padding-top: 64%; -} - -textarea { - resize: none; -} - -.modal .modal-header, -.modal .modal-footer { - background-color: #f4f4f4; -} - -.modal .modal-header { - font-weight: bold; -} - -.site-content { - padding-top: 30px; -} diff --git a/lib/models/country.js b/lib/models/country.js deleted file mode 100644 index a6306ba..0000000 --- a/lib/models/country.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Module dependencies. - */ - -var i18nSchema = require('./i18n-schema') -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; -var ObjectId = Schema.ObjectId; - -/** - * Country Schema - */ - -var CountrySchema = new Schema({ - name: i18nSchema -}); - -/** - * Make Schema `.toObject()` and - * `.toJSON()` parse getters for - * proper JSON API response - */ - -CountrySchema.set('toObject', { getters: true }); -CountrySchema.set('toJSON', { getters: true }); - -/** - * Expose Mongoose model loaded - */ - -module.exports = mongoose.model('Country', CountrySchema); diff --git a/lib/models/i18n-schema.js b/lib/models/i18n-schema.js deleted file mode 100644 index 32265ef..0000000 --- a/lib/models/i18n-schema.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Module dependencies. - */ - -var config = require('lib/config'); -var languages = config('languages'); - -var i18nSchema = {}; - -languages.forEach(function (language) { - i18nSchema[language] = { type: String }; -}); - -module.exports = i18nSchema; diff --git a/lib/server/api/apps/index.js b/lib/server/api/apps/index.js new file mode 100644 index 0000000..5a84aca --- /dev/null +++ b/lib/server/api/apps/index.js @@ -0,0 +1,191 @@ +const express = require('express') +const api = require('../../db-api') +const log = require('debug')('civicstack:api:application') +const utils = require('../../utils') +const { admin, restrict, handleError, openGraph, accepts } = utils + +const app = module.exports = express() + +/** + * Limit request to json format only + */ + +app.use(accepts('application/json')) + +const all = ['id name logo backgroundColor video description technology technologyids links', + 'organization github website country twitter license contact partnership', + 'comments tags approved tagids uploadedBy upvotesCount upvoted'].join(' ') + +function expose (user) { + return function (app) { + var obj = utils.expose(all)(app) + obj.upvoted = user && app.upvotes !== undefined && + (app.upvotes.map(a => a.toString()).indexOf(user.id) >= 0) + + return obj + } +} + +app.get('/applications', utils.admin, function (req, res) { + log('Request /applications') + api.application.all(function (err, applications) { + if (err) return handleError(err, req, res) + log('Serving %s applications', applications.length) + + res.json(applications.map(expose(req.user))) + }) +}) + +app.get('/applications/approved', function (req, res) { + function parse (key) { + return req.query[key] ? req.query[key].split(',') : undefined + } + + function serveApplications (err, applications) { + if (err) return handleError(err, req, res) + log('Serving %s applications', applications.length) + res.json(applications.map(expose(req.user))) + } + + log('Request /applications/approved') + + // Filters + var tags = parse('tags') + var technologies = parse('technologies') + var countries = parse('countries') + var search = req.query.q + // Sorting + var sortBy = req.query.sort === '_id' || req.query.sort === 'upvotesCount' + ? req.query.sort : undefined + var sortOrder = req.query.order === 'asc' || req.query.order === 'desc' ? req.query.order : 'asc' + + // Fetch data + if (tags || countries || technologies || search || sortBy) { + var filter = { + tags: tags, + technologies: technologies, + countries: countries, + search: search, + sortBy: sortBy, + sortOrder: sortOrder + } + + api.application.filter(filter, serveApplications) + } else { + api.application.approved(serveApplications) + } +}) + +app.get('/applications/:id', function (req, res) { + log('Request GET /application/%s', req.params.id) + + api.application.get(req.params.id, function (err, application) { + if (err) return handleError(err, req, res) + if (!application) return res.send(404) + + log('Serving application %s', application.id) + + res.json(expose(req.user)(application.toJSON())) + }) +}) + +app.get('/applications/:id/links', function (req, res, next) { + function promisify (links) { + return links.map(function (link) { + return new Promise(function (resolve) { + openGraph.get(link.url, function (err, result) { + var data = { url: link.url, description: link.description } + data.og = err ? {} : ({ + title: result.data.ogTitle || result.data.title, + description: result.data.ogDescription, + image: result.data.ogImage && result.data.ogImage.url + }) + return resolve(data) + }) + }) + }) + } + + log('Request GET /application/%s/links', req.params.id) + + api.application.get(req.params.id, function (err, application) { + if (err) return handleError(err, req, res) + if (!application) return res.send(404) + + log('Serving application links for %s: %j', application.id, application.links) + Promise.all(promisify(application.links)) + .then(function (result) { + return res.json(result) + }) + .catch(function (err) { + return next(err) + }) + }) +}) + +app.post('/applications/create', restrict, protect, function (req, res) { + log('Request POST /applications/create %j', req.body) + + req.body.uploadedBy = req.user + if (req.body.license === '') delete req.body.license + + api.application.create(req.body, function (err, application) { + if (err) return handleError(err, req, res) + + log('Serving application %s', application.id) + + res.json(expose(req.user)(application.toJSON())) + }) +}) + +app.post('/applications/:id', admin, protect, function (req, res) { + log('Request POST /applications/%s %j', req.params.id, req.body) + + if (req.body.license === '') delete req.body.license + req.body.video = utils.getEmbeddableYouTubeURL(req.body.video) + + api.application.update(req.body, function (err, app) { + if (err) return handleError(err, req, res) + + log('Serving application %s', app.id) + + res.json(expose(req.user)(app.toJSON())) + }) +}) + +app.post('/applications/:id/upvote', restrict, function (req, res) { + log('Request POST /applications/%s/upvote', req.params.id) + + api.application.upvote(req.params.id, req.user.id, function (err, app) { + if (err) return handleError(err, req, res) + res.json(expose(req.user)(app.toJSON())) + }) +}) + +app.delete('/applications/:id/upvote', restrict, function (req, res) { + log('Request DELETE /applications/%s/upvote', req.params.id) + + api.application.undoUpvote(req.params.id, req.user.id, function (err, app) { + if (err) return handleError(err, req, res) + res.json(expose(req.user)(app.toJSON())) + }) +}) + +app.delete('/applications/:id', admin, function (req, res) { + log('Request DEL /applications/%s %j', req.params.id, req.body) + + api.application.remove(req.params.id, function (err, id) { + if (err) return handleError(err, req, res) + + log('Deleted application %s', id.id) + + res.sendStatus(200) + }) +}) + +function protect (req, res, next) { + if (!req.user.admin) { + delete req.body.approved + } + next() +} diff --git a/lib/db-api/application.js b/lib/server/db-api/application.js similarity index 93% rename from lib/db-api/application.js rename to lib/server/db-api/application.js index 3a6feb8..841b9a7 100644 --- a/lib/db-api/application.js +++ b/lib/server/db-api/application.js @@ -1,24 +1,11 @@ -/** - * Extend module's NODE_PATH - * HACK: temporary solution - */ - -require('node-path')(module); - -/** - * Module dependencies. - */ - -var mongoose = require('mongoose'); -var Application = mongoose.model('Application'); -var utils = require('lib/utils'); -var pluck = utils.pluck; -var log = require('debug')('civicstack:db-api:application'); - -var fields = ['id name logo backgroundColor video description technology technologyids links tags', - 'organization github website country twitter license contact partnership comments approved tagids', - 'upvotes upvotesCount'] - .join(' ') +const mongoose = require('mongoose') +const { pluck } = require('../utils') +const log = require('debug')('civicstack:db-api:application') +const Application = mongoose.model('Application') + +const fields = ['id name logo backgroundColor video description technology technologyids links tags', + 'organization github website country twitter license contact partnership comments approved tagids', + 'upvotes upvotesCount'].join(' ') /** * Get all applications diff --git a/lib/db-api/country.js b/lib/server/db-api/country.js similarity index 98% rename from lib/db-api/country.js rename to lib/server/db-api/country.js index 2aa287b..1dadbad 100644 --- a/lib/db-api/country.js +++ b/lib/server/db-api/country.js @@ -11,7 +11,7 @@ require('node-path')(module); var mongoose = require('mongoose'); var Country = mongoose.model('Country'); -var utils = require('lib/utils'); +var utils = require('../utils'); var pluck = utils.pluck; var log = require('debug')('civicstack:db-api:country'); @@ -88,7 +88,7 @@ exports.get = function get(id, fn) { exports.create = function create(data, fn) { log('Creating new country %j', data); - + var country = new Country(data); country.save(onsave); @@ -132,7 +132,7 @@ exports.update = function update(data, fn) { function onupdate(err, country) { if (err) return log('Found error %s', err), fn(err); - + log('Saved country %s', country.id) fn(null, country); } diff --git a/lib/db-api/index.js b/lib/server/db-api/index.js similarity index 100% rename from lib/db-api/index.js rename to lib/server/db-api/index.js diff --git a/lib/db-api/license.js b/lib/server/db-api/license.js similarity index 98% rename from lib/db-api/license.js rename to lib/server/db-api/license.js index 7dcaf22..6131fe5 100644 --- a/lib/db-api/license.js +++ b/lib/server/db-api/license.js @@ -11,7 +11,7 @@ require('node-path')(module); var mongoose = require('mongoose'); var License = mongoose.model('License'); -var utils = require('lib/utils'); +var utils = require('../utils'); var pluck = utils.pluck; var log = require('debug')('civicstack:db-api:license'); @@ -164,4 +164,4 @@ exports.remove = function remove(id, fn) { }); return this; -}; \ No newline at end of file +}; diff --git a/lib/db-api/tag.js b/lib/server/db-api/tag.js similarity index 98% rename from lib/db-api/tag.js rename to lib/server/db-api/tag.js index 71b5c24..2189ffb 100644 --- a/lib/db-api/tag.js +++ b/lib/server/db-api/tag.js @@ -11,7 +11,7 @@ require('node-path')(module); var mongoose = require('mongoose'); var Tag = mongoose.model('Tag'); -var utils = require('lib/utils'); +var utils = require('../utils'); var pluck = utils.pluck; var log = require('debug')('civicstack:db-api:tag'); @@ -86,7 +86,7 @@ exports.get = function get(id, fn) { exports.create = function create(data, fn) { log('Creating new tag %j', data); - + var tag = new Tag(data); tag.save(onsave); @@ -159,4 +159,4 @@ exports.remove = function remove(id, fn) { }); return this; -}; \ No newline at end of file +}; diff --git a/lib/db-api/technology.js b/lib/server/db-api/technology.js similarity index 99% rename from lib/db-api/technology.js rename to lib/server/db-api/technology.js index 88ef46c..82745ee 100644 --- a/lib/db-api/technology.js +++ b/lib/server/db-api/technology.js @@ -11,7 +11,7 @@ require('node-path')(module); var mongoose = require('mongoose'); var Technology = mongoose.model('Technology'); -var utils = require('lib/utils'); +var utils = require('../utils'); var pluck = utils.pluck; var log = require('debug')('civicstack:db-api:technology'); diff --git a/lib/app/server/index.js b/lib/server/index.js similarity index 73% rename from lib/app/server/index.js rename to lib/server/index.js index d1372c8..1f280f0 100644 --- a/lib/app/server/index.js +++ b/lib/server/index.js @@ -1,11 +1,12 @@ const express = require('express') const app = express() +require('./models')(app) app.set('view engine', 'pug') -app.set('views', './lib/app/server/templates') +app.set('views', './lib/server/templates') const webpack = require('webpack') -const webpackConfig = require('../../../webpack.config.babel') +const webpackConfig = require('../../webpack.config.babel') const compiler = webpack(webpackConfig) app.use(express.static('./public')) @@ -17,6 +18,7 @@ app.use(require('webpack-dev-middleware')(compiler, { app.use(require('webpack-hot-middleware')(compiler)) +app.use('/api', require('./api/apps')) app.get('/', (req, res) => { res.render('home', { algo: 4 }) diff --git a/lib/models/application.js b/lib/server/models/application.js similarity index 73% rename from lib/models/application.js rename to lib/server/models/application.js index 28aadd4..0c8623c 100644 --- a/lib/models/application.js +++ b/lib/server/models/application.js @@ -1,26 +1,21 @@ -/** - * Module dependencies. - */ - -var i18nSchema = require('./i18n-schema'); -var log = require('debug')('civicstack:models:law'); -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; -var ObjectId = Schema.ObjectId; -var t = require('t-component'); +var i18nSchema = require('./i18n-schema') +var mongoose = require('mongoose') +var Schema = mongoose.Schema +var ObjectId = Schema.ObjectId +var t = require('t-component') /** * Application Vote Schema */ function max300Characters(val) { - return val.length <= 300; + return val.length <= 300 } -var descriptionSchema = i18nSchema; +var descriptionSchema = i18nSchema Object.keys(descriptionSchema).forEach(function (key) { - descriptionSchema[key].validate = { validator: max300Characters, msg: t('app.description.exceeded') }; -}); + descriptionSchema[key].validate = { validator: max300Characters, msg: t('app.description.exceeded') } +}) var ApplicationSchema = new Schema({ name: { type: String, required: true } @@ -47,7 +42,7 @@ var ApplicationSchema = new Schema({ , uploadedBy: { type: ObjectId, ref: 'User', required: true } , upvotes: [ { type: ObjectId, ref: 'User' } ] , upvotesCount: { type: Number, default: 0 } -}); +}) /** * Make Schema `.toObject()` and @@ -55,8 +50,8 @@ var ApplicationSchema = new Schema({ * proper JSON API response */ -ApplicationSchema.set('toObject', { getters: true }); -ApplicationSchema.set('toJSON', { getters: true }); +ApplicationSchema.set('toObject', { getters: true }) +ApplicationSchema.set('toJSON', { getters: true }) /** * Get `tags` ids @@ -67,11 +62,11 @@ ApplicationSchema.set('toJSON', { getters: true }); */ ApplicationSchema.virtual('tagids').get(function() { - if (!this.tags.length) return; + if (!this.tags.length) return return this.tags.map(function(tag) { - return tag._id; - }); -}); + return tag._id + }) +}) /** * Get `technology` ids @@ -82,20 +77,20 @@ ApplicationSchema.virtual('tagids').get(function() { */ ApplicationSchema.virtual('technologyids').get(function() { - if (!this.technology.length) return; + if (!this.technology.length) return return this.technology.map(function(technology) { - return technology._id; - }); -}); + return technology._id + }) +}) /** * Index */ -ApplicationSchema.index({ name: 'text', 'description.en': 'text', 'description.fr': 'text', 'description.en': 'text' }); +ApplicationSchema.index({ name: 'text', 'description.en': 'text', 'description.fr': 'text', 'description.en': 'text' }) /** * Expose Mongoose model loaded */ -module.exports = mongoose.model('Application', ApplicationSchema); +module.exports = mongoose.model('Application', ApplicationSchema) diff --git a/lib/server/models/country.js b/lib/server/models/country.js new file mode 100644 index 0000000..da18f14 --- /dev/null +++ b/lib/server/models/country.js @@ -0,0 +1,26 @@ +var i18nSchema = require('./i18n-schema') +var mongoose = require('mongoose') +var Schema = mongoose.Schema + +/** + * Country Schema + */ + +var CountrySchema = new Schema({ + name: i18nSchema +}) + +/** + * Make Schema `.toObject()` and + * `.toJSON()` parse getters for + * proper JSON API response + */ + +CountrySchema.set('toObject', { getters: true }) +CountrySchema.set('toJSON', { getters: true }) + +/** + * Expose Mongoose model loaded + */ + +module.exports = mongoose.model('Country', CountrySchema) diff --git a/lib/server/models/i18n-schema.js b/lib/server/models/i18n-schema.js new file mode 100644 index 0000000..05974ad --- /dev/null +++ b/lib/server/models/i18n-schema.js @@ -0,0 +1,14 @@ +/** + * Module dependencies. + */ + +// TODO: Make it configurable +var languages = ['en', 'es'] + +var i18nSchema = {} + +languages.forEach(function (language) { + i18nSchema[language] = { type: String } +}) + +module.exports = i18nSchema diff --git a/lib/models/index.js b/lib/server/models/index.js similarity index 82% rename from lib/models/index.js rename to lib/server/models/index.js index 7a6c190..78649f3 100755 --- a/lib/models/index.js +++ b/lib/server/models/index.js @@ -3,6 +3,8 @@ */ var mongoose = require('mongoose'); +// TODO: Make it configurable +const mongoUrl = 'mongodb://localhost/civicstack2' /** * Expose models linker helper @@ -16,7 +18,7 @@ module.exports = function models (app) { * Connect to mongo */ - mongoose.connect(app.get('config').mongoUrl, { db: { safe: true }}); + mongoose.connect(mongoUrl, { db: { safe: true }}); /** * Register `User` model diff --git a/lib/models/license.js b/lib/server/models/license.js similarity index 100% rename from lib/models/license.js rename to lib/server/models/license.js diff --git a/lib/models/tag.js b/lib/server/models/tag.js similarity index 100% rename from lib/models/tag.js rename to lib/server/models/tag.js diff --git a/lib/models/technology.js b/lib/server/models/technology.js similarity index 100% rename from lib/models/technology.js rename to lib/server/models/technology.js diff --git a/lib/models/user.js b/lib/server/models/user.js similarity index 84% rename from lib/models/user.js rename to lib/server/models/user.js index 3d1fe2c..14d3a61 100644 --- a/lib/models/user.js +++ b/lib/server/models/user.js @@ -2,7 +2,7 @@ * Module dependencies. */ -var config = require('lib/config'); +// var config = require('lib/config'); var mongoose = require('mongoose'); var Schema = mongoose.Schema; var ObjectId = Schema.ObjectId; @@ -121,18 +121,19 @@ UserSchema.statics.findByProvider = function(profile, cb) { */ UserSchema.virtual('admin').get(function() { - var twadmins = config.admins.twitter || []; - var githubadmins = config.admins.github || []; - - if (this.profiles.twitter) { - var id = this.profiles.twitter.id; - return !!~twadmins.indexOf(id); - } - - if (this.profiles.github) { - var id = this.profiles.github._json.id.toString(); - return !!~githubadmins.indexOf(id); - } + // TODO: Enable this + // var twadmins = config.admins.twitter || []; + // var githubadmins = config.admins.github || []; + // + // if (this.profiles.twitter) { + // var id = this.profiles.twitter.id; + // return !!~twadmins.indexOf(id); + // } + // + // if (this.profiles.github) { + // var id = this.profiles.github._json.id.toString(); + // return !!~githubadmins.indexOf(id); + // } return false; }); diff --git a/lib/app/server/templates/home.pug b/lib/server/templates/home.pug similarity index 100% rename from lib/app/server/templates/home.pug rename to lib/server/templates/home.pug diff --git a/lib/server/utils/accepts.js b/lib/server/utils/accepts.js new file mode 100644 index 0000000..53e7e15 --- /dev/null +++ b/lib/server/utils/accepts.js @@ -0,0 +1,56 @@ +/** + * Module dependencies. + */ + +var log = require('debug')('civicstack:accepts') +var type = require('type-component'); + +/** + * Expose accepts middelware constructor + */ + +module.exports = accepts; + +/** + * Allow only provided formats, and optionally + * + * @param {String|Array} formats allowed for middleware + * @param {Function} reject middleware for rejected cases + * @return {Function} [description] + */ + +function accepts(formats, reject) { + if ('string' === type(formats)) formats = formats.split(/\s+/); + return function middleware(req, res, next) { + if (lookup(formats, req.accepts())) return next(); + if (reject) { + log('Rejecting request with reject middleware'); + return reject(req, res, next); + } + log('Rejecting request'); + res.send(406); + } +} + +/** + * Lookups for at least once accepted format in types + * and returns `true`. Returns `false` if not found + * + * @param {Array} formats + * @param {Array} types + * @return {Boolean} found format in types + */ + +function lookup(formats, types) { + for (var i = 0; i < formats.length; i++) { + var format = formats[i].replace('*', ''); + if (!format) continue; + + for (var j = 0; j < types.length; j++) { + var type = types[j]; + if (!type.indexOf(format)) return true; + }; + }; + + return false; +} diff --git a/lib/utils/index.js b/lib/server/utils/index.js similarity index 97% rename from lib/utils/index.js rename to lib/server/utils/index.js index 8168282..cd421b2 100644 --- a/lib/utils/index.js +++ b/lib/server/utils/index.js @@ -161,3 +161,6 @@ exports.getEmbeddableYouTubeURL = function getEmbeddableYoutubeURL(u) { var params = qs.parse(uri.query); return params.v ? uri.protocol + '//www.youtube.com/embed/' + params.v : u; } + +exports.OpenGraph = require('./open-graph') +exports.accepts = require('./accepts') diff --git a/lib/server/utils/open-graph.js b/lib/server/utils/open-graph.js new file mode 100644 index 0000000..411c6a4 --- /dev/null +++ b/lib/server/utils/open-graph.js @@ -0,0 +1,37 @@ +var og = require('open-graph-scraper') +var Cache = require('node-cache') + +var OpenGraph = function () { + var cache = new Cache({ stdTTL: 3600 }) + + return { + get: function (url, cb) { + cache.get(url, function (err, value) { + if (err) { + return cb(err) + } + + // If URL exists in cache, return it + if (value) { + return cb(null, value) + } + + // Get OG data from remote site + return og({ url: url }, function (err, result) { + // In case of error, pass control to callback + if (err) { + return cb(err) + } + + // Save in cache + cache.set(url, result, function () { + // Return control to callback + cb(null, result) + }) + }) + }) + } + } +} + +module.exports = new OpenGraph() diff --git a/package.json b/package.json index cf0651f..9d3e8ba 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "webpack": "^1.13.3" }, "scripts": { - "start": "node ./lib/app/server", + "start": "node ./lib/server", "build": "webpack -p --colors --config webpack.config.babel.js", "lint": "eslint ." }, From 16b86e52b62c8d0840f53c4ce0075e0a6b2843a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 16:14:46 -0300 Subject: [PATCH 07/60] Show app list --- lib/app/components/AppList/app-card.js | 47 +++++++++++++++++++ lib/app/components/AppList/index.js | 63 ++++++++++++++++++++++++++ lib/app/containers/App.js | 22 ++++++++- lib/app/reducers/index.js | 7 ++- lib/app/reducers/meta.js | 7 +++ lib/app/store/index.js | 3 +- package.json | 1 + 7 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 lib/app/components/AppList/app-card.js create mode 100644 lib/app/components/AppList/index.js create mode 100644 lib/app/reducers/meta.js diff --git a/lib/app/components/AppList/app-card.js b/lib/app/components/AppList/app-card.js new file mode 100644 index 0000000..966db96 --- /dev/null +++ b/lib/app/components/AppList/app-card.js @@ -0,0 +1,47 @@ +const React = require('react') +const { PropTypes } = React + +const AppCard = ({ href, name, backgroundColor, backgroundImageURL, countryName, description, twitterHandle, upvoteCount }) => ( +
+ +
+) + +AppCard.propTypes = { + href: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + backgroundColor: PropTypes.string, + backgroundImageURL: PropTypes.string, + countryName: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + twitterHandle: PropTypes.string, + upvoteCount: PropTypes.number.isRequired +} + +module.exports = AppCard diff --git a/lib/app/components/AppList/index.js b/lib/app/components/AppList/index.js new file mode 100644 index 0000000..034bdf7 --- /dev/null +++ b/lib/app/components/AppList/index.js @@ -0,0 +1,63 @@ +const React = require('react') +const { PropTypes } = React +const AppCard = require('./app-card') + +class AppList extends React.Component { + + static propTypes = { + apps: PropTypes.arrayOf(PropTypes.object) + } + + render () { + const { apps } = this.props + + return ( +
+
+
+

Herramientas de código abierto para acciones políticas y sociales.

+
+
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+
+
+ {apps.map(({ id, logo, backgroundColor, name, country, description, twitter, upvotesCount }) => ( + + ))} +
+
+
+ ) + } +} + +module.exports = AppList diff --git a/lib/app/containers/App.js b/lib/app/containers/App.js index b19c983..296b828 100644 --- a/lib/app/containers/App.js +++ b/lib/app/containers/App.js @@ -1,11 +1,18 @@ const React = require('react') +const { PropTypes } = React const { connect } = require('react-redux') const Header = require('../components/Header') const Footer = require('../components/Footer') const Drawer = require('../components/Drawer') +const AppList = require('../components/AppList') class App extends React.Component { + static propTypes = { + loading: PropTypes.bool.isRequired, + apps: PropTypes.arrayOf(PropTypes.object) + } + constructor (props) { super(props) this.state = { @@ -20,11 +27,13 @@ class App extends React.Component { } render () { + const { loading, apps } = this.props const { showDrawer } = this.state return (
+ {loading ? null : }
{showDrawer ? : null}
@@ -32,8 +41,17 @@ class App extends React.Component { } } -const mapStateToProps = state => ({ - +const mapStateToProps = ({ meta, apps }) => ({ + locale: meta.locale, + loading: apps.fetching, + apps: apps.items.map(app => ({ + ...app, + description: app.description[meta.locale], + country: { + ...app.country, + name: app.country.name[meta.locale] + } + })) }) module.exports = connect(mapStateToProps)(App) diff --git a/lib/app/reducers/index.js b/lib/app/reducers/index.js index 1cc74b9..15f4bcf 100644 --- a/lib/app/reducers/index.js +++ b/lib/app/reducers/index.js @@ -1,3 +1,6 @@ -const combineReducers = require('redux').combineReducers +const { combineReducers } = require('redux') -module.exports = combineReducers([ require('./apps') ]) +const meta = require('./meta') +const apps = require('./apps') + +module.exports = combineReducers({ meta, apps }) diff --git a/lib/app/reducers/meta.js b/lib/app/reducers/meta.js new file mode 100644 index 0000000..67cf933 --- /dev/null +++ b/lib/app/reducers/meta.js @@ -0,0 +1,7 @@ +const initialState = { + locale: 'es' +} + +module.exports = (state = initialState, action) => { + return state +} diff --git a/lib/app/store/index.js b/lib/app/store/index.js index f56370c..1927f99 100644 --- a/lib/app/store/index.js +++ b/lib/app/store/index.js @@ -1,5 +1,6 @@ const { createStore, applyMiddleware } = require('redux') const thunk = require('redux-thunk').default +const logger = require('redux-logger') const reducers = require('../reducers') -module.exports = createStore(reducers, applyMiddleware(thunk)) +module.exports = createStore(reducers, applyMiddleware(thunk, logger())) diff --git a/package.json b/package.json index 9d3e8ba..a118bba 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "react-redux": "^4.4.5", "ready": "0.1.1", "redux": "^3.6.0", + "redux-logger": "^2.7.4", "redux-thunk": "^2.1.0", "serve-favicon": "2.1.7", "string-to-js": "0.0.1", From e939d2a7adf285e0cabf50e39109e9e2204ea749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 19:41:45 -0300 Subject: [PATCH 08/60] Clean db-api code --- lib/server/db-api/country.js | 111 ++++++++++++++------------------ lib/server/db-api/license.js | 111 ++++++++++++++------------------ lib/server/db-api/tag.js | 109 ++++++++++++++----------------- lib/server/db-api/technology.js | 111 ++++++++++++++------------------ 4 files changed, 199 insertions(+), 243 deletions(-) diff --git a/lib/server/db-api/country.js b/lib/server/db-api/country.js index 1dadbad..5a21a34 100644 --- a/lib/server/db-api/country.js +++ b/lib/server/db-api/country.js @@ -1,19 +1,8 @@ -/** - * Extend module's NODE_PATH - * HACK: temporary solution - */ - -require('node-path')(module); - -/** - * Module dependencies. - */ - -var mongoose = require('mongoose'); -var Country = mongoose.model('Country'); -var utils = require('../utils'); -var pluck = utils.pluck; -var log = require('debug')('civicstack:db-api:country'); +var mongoose = require('mongoose') +var Country = mongoose.model('Country') +var utils = require('../utils') +var pluck = utils.pluck +var log = require('debug')('civicstack:db-api:country') /** * Get all countries @@ -33,16 +22,16 @@ exports.all = function all(fn) { .select('id name') .exec(function (err, countries) { if (err) { - log('Found error %j', err); - return fn(err); - }; + log('Found error %j', err) + return fn(err) + } - log('Delivering countries %j', pluck(countries, 'id')); - fn(null, countries); - }); + log('Delivering countries %j', pluck(countries, 'id')) + fn(null, countries) + }) - return this; -}; + return this +} /** * Get Country form `id` string or `ObjectId` @@ -55,25 +44,25 @@ exports.all = function all(fn) { */ exports.get = function get(id, fn) { - var query = { _id: id }; + var query = { _id: id } - log('Looking for country %s', id); + log('Looking for country %s', id) Country .findOne(query) .exec(function (err, country) { if (err) { - log('Found error %s', err); - return fn(err); - }; + log('Found error %s', err) + return fn(err) + } if (!country) { - log('Country %s not found', id); - return fn(null); + log('Country %s not found', id) + return fn(null) } - log('Delivering country %s', country.id); - fn(null, country); - }); -}; + log('Delivering country %s', country.id) + fn(null, country) + }) +} /** * Creates country @@ -87,20 +76,20 @@ exports.get = function get(id, fn) { */ exports.create = function create(data, fn) { - log('Creating new country %j', data); + log('Creating new country %j', data) - var country = new Country(data); - country.save(onsave); + var country = new Country(data) + country.save(onsave) function onsave(err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Saved country %s', country.id); - fn(null, country); + log('Saved country %s', country.id) + fn(null, country) } - return this; -}; + return this +} /** * Update given `country` @@ -114,31 +103,31 @@ exports.create = function create(data, fn) { */ exports.update = function update(data, fn) { - log('Updating country %s with %j', data.id, data); + log('Updating country %s with %j', data.id, data) // get country - exports.get(data.id, onget); + exports.get(data.id, onget) function onget(err, country) { if (err) { - log('Found error %s', err.message); - return fn(err); - }; + log('Found error %s', err.message) + return fn(err) + } // update and save country document with data - country.set(data); - country.save(onupdate); + country.set(data) + country.save(onupdate) } function onupdate(err, country) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) log('Saved country %s', country.id) - fn(null, country); + fn(null, country) } - return this; -}; + return this +} /** * Deletes country @@ -152,16 +141,16 @@ exports.update = function update(data, fn) { */ exports.remove = function remove(id, fn) { - log('Deleting country %s', id); + log('Deleting country %s', id) Country .remove({_id: id}) .exec(function (err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Removed country %s', id); - fn(null, id); - }); + log('Removed country %s', id) + fn(null, id) + }) - return this; -}; + return this +} diff --git a/lib/server/db-api/license.js b/lib/server/db-api/license.js index 6131fe5..cc9f1d5 100644 --- a/lib/server/db-api/license.js +++ b/lib/server/db-api/license.js @@ -1,19 +1,8 @@ -/** - * Extend module's NODE_PATH - * HACK: temporary solution - */ - -require('node-path')(module); - -/** - * Module dependencies. - */ - -var mongoose = require('mongoose'); -var License = mongoose.model('License'); -var utils = require('../utils'); -var pluck = utils.pluck; -var log = require('debug')('civicstack:db-api:license'); +var mongoose = require('mongoose') +var License = mongoose.model('License') +var utils = require('../utils') +var pluck = utils.pluck +var log = require('debug')('civicstack:db-api:license') /** * Get all licenses @@ -33,16 +22,16 @@ exports.all = function all(fn) { .select('id name') .exec(function (err, licenses) { if (err) { - log('Found error %j', err); - return fn(err); - }; + log('Found error %j', err) + return fn(err) + } - log('Delivering licenses %j', pluck(licenses, 'id')); - fn(null, licenses); - }); + log('Delivering licenses %j', pluck(licenses, 'id')) + fn(null, licenses) + }) - return this; -}; + return this +} /** * Get License form `id` string or `ObjectId` @@ -55,25 +44,25 @@ exports.all = function all(fn) { */ exports.get = function get(id, fn) { - var query = { _id: id }; + var query = { _id: id } - log('Looking for license %s', id); + log('Looking for license %s', id) License .findOne(query) .exec(function (err, license) { if (err) { - log('Found error %s', err); - return fn(err); - }; + log('Found error %s', err) + return fn(err) + } if (!license) { - log('License %s not found', id); - return fn(null); + log('License %s not found', id) + return fn(null) } - log('Delivering license %s', license.id); - fn(null, license); - }); -}; + log('Delivering license %s', license.id) + fn(null, license) + }) +} /** * Creates license @@ -87,20 +76,20 @@ exports.get = function get(id, fn) { */ exports.create = function create(data, fn) { - log('Creating new license %j', data); + log('Creating new license %j', data) - var license = new License(data); - license.save(onsave); + var license = new License(data) + license.save(onsave) function onsave(err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Saved license %s', license.id); - fn(null, license); + log('Saved license %s', license.id) + fn(null, license) } - return this; -}; + return this +} /** * Update given `license` @@ -114,31 +103,31 @@ exports.create = function create(data, fn) { */ exports.update = function update(data, fn) { - log('Updating license %s with %j', data.id, data); + log('Updating license %s with %j', data.id, data) // get license - exports.get(data.id, onget); + exports.get(data.id, onget) function onget(err, license) { if (err) { - log('Found error %s', err.message); - return fn(err); - }; + log('Found error %s', err.message) + return fn(err) + } // update and save license document with data - license.set(data); - license.save(onupdate); + license.set(data) + license.save(onupdate) } function onupdate(err, license) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) log('Saved license %s', license.id) - fn(null, license); + fn(null, license) } - return this; -}; + return this +} /** * Deletes license @@ -152,16 +141,16 @@ exports.update = function update(data, fn) { */ exports.remove = function remove(id, fn) { - log('Deleting license %s', id); + log('Deleting license %s', id) License .remove({_id: id}) .exec(function (err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Removed license %s', id); - fn(null, id); - }); + log('Removed license %s', id) + fn(null, id) + }) - return this; -}; + return this +} diff --git a/lib/server/db-api/tag.js b/lib/server/db-api/tag.js index 2189ffb..84991d0 100644 --- a/lib/server/db-api/tag.js +++ b/lib/server/db-api/tag.js @@ -1,19 +1,8 @@ -/** - * Extend module's NODE_PATH - * HACK: temporary solution - */ - -require('node-path')(module); - -/** - * Module dependencies. - */ - -var mongoose = require('mongoose'); -var Tag = mongoose.model('Tag'); -var utils = require('../utils'); -var pluck = utils.pluck; -var log = require('debug')('civicstack:db-api:tag'); +var mongoose = require('mongoose') +var Tag = mongoose.model('Tag') +var utils = require('../utils') +var pluck = utils.pluck +var log = require('debug')('civicstack:db-api:tag') /** * Get all tags @@ -33,16 +22,16 @@ exports.all = function all(fn) { .select('id name') .exec(function (err, tags) { if (err) { - log('Found error %j', err); - return fn(err); - }; + log('Found error %j', err) + return fn(err) + } - log('Delivering tags %j', pluck(tags, 'id')); - fn(null, tags); - }); + log('Delivering tags %j', pluck(tags, 'id')) + fn(null, tags) + }) - return this; -}; + return this +} /** * Get Tag form `id` string or `ObjectId` @@ -55,23 +44,23 @@ exports.all = function all(fn) { */ exports.get = function get(id, fn) { - log('Looking for tag %s', id); + log('Looking for tag %s', id) Tag .findById(id) .exec(function (err, tag) { if (err) { - log('Found error %s', err); - return fn(err); - }; + log('Found error %s', err) + return fn(err) + } if (!tag) { - log('Tag %s not found', id); - return fn(null); + log('Tag %s not found', id) + return fn(null) } - log('Delivering tag %s', tag.id); - fn(null, tag); - }); -}; + log('Delivering tag %s', tag.id) + fn(null, tag) + }) +} /** * Creates tag @@ -85,20 +74,20 @@ exports.get = function get(id, fn) { */ exports.create = function create(data, fn) { - log('Creating new tag %j', data); + log('Creating new tag %j', data) - var tag = new Tag(data); - tag.save(onsave); + var tag = new Tag(data) + tag.save(onsave) function onsave(err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Saved tag %s', tag.id); - fn(null, tag); + log('Saved tag %s', tag.id) + fn(null, tag) } - return this; -}; + return this +} /** * Update tag @@ -112,28 +101,28 @@ exports.create = function create(data, fn) { */ exports.update = function update(data, fn) { - log('Updating tag %s with %j', data.id, data); + log('Updating tag %s with %j', data.id, data) - exports.get(data.id, onget); + exports.get(data.id, onget) function onget(err, tag) { if (err) { - log('Found error %s', err.message); - return fn(err); - }; + log('Found error %s', err.message) + return fn(err) + } // update and save tag document with data - tag.set(data); - tag.save(onupdate); + tag.set(data) + tag.save(onupdate) } function onupdate(err, tag) { - if (!err) return log('Saved tag %s', tag.id), fn(null, tag); - return log('Found error %s', err), fn(err); + if (!err) return log('Saved tag %s', tag.id), fn(null, tag) + return log('Found error %s', err), fn(err) } - return this; -}; + return this +} /** * Deletes tag @@ -147,16 +136,16 @@ exports.update = function update(data, fn) { */ exports.remove = function remove(id, fn) { - log('Deleting tag %s', id); + log('Deleting tag %s', id) Tag .remove({_id: id}) .exec(function (err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Removed tag %s', id); - fn(null, id); - }); + log('Removed tag %s', id) + fn(null, id) + }) - return this; -}; + return this +} diff --git a/lib/server/db-api/technology.js b/lib/server/db-api/technology.js index 82745ee..0fbd96c 100644 --- a/lib/server/db-api/technology.js +++ b/lib/server/db-api/technology.js @@ -1,19 +1,8 @@ -/** - * Extend module's NODE_PATH - * HACK: temporary solution - */ - -require('node-path')(module); - -/** - * Module dependencies. - */ - -var mongoose = require('mongoose'); -var Technology = mongoose.model('Technology'); -var utils = require('../utils'); -var pluck = utils.pluck; -var log = require('debug')('civicstack:db-api:technology'); +var mongoose = require('mongoose') +var Technology = mongoose.model('Technology') +var utils = require('../utils') +var pluck = utils.pluck +var log = require('debug')('civicstack:db-api:technology') /** * Get all technologies @@ -33,16 +22,16 @@ exports.all = function all(fn) { .select('id name') .exec(function (err, technologies) { if (err) { - log('Found error %j', err); - return fn(err); - }; + log('Found error %j', err) + return fn(err) + } - log('Delivering technologies %j', pluck(technologies, 'id')); - fn(null, technologies); - }); + log('Delivering technologies %j', pluck(technologies, 'id')) + fn(null, technologies) + }) - return this; -}; + return this +} /** * Get Technology form `id` string or `ObjectId` @@ -55,25 +44,25 @@ exports.all = function all(fn) { */ exports.get = function get(id, fn) { - var query = { _id: id }; + var query = { _id: id } - log('Looking for technology %s', id); + log('Looking for technology %s', id) Technology .findOne(query) .exec(function (err, technology) { if (err) { - log('Found error %s', err); - return fn(err); - }; + log('Found error %s', err) + return fn(err) + } if (!technology) { - log('Technology %s not found', id); - return fn(null); + log('Technology %s not found', id) + return fn(null) } - log('Delivering technology %s', technology.id); - fn(null, technology); - }); -}; + log('Delivering technology %s', technology.id) + fn(null, technology) + }) +} /** * Creates technology @@ -87,20 +76,20 @@ exports.get = function get(id, fn) { */ exports.create = function create(data, fn) { - log('Creating new technology %j', data); + log('Creating new technology %j', data) - var technology = new Technology(data); - technology.save(onsave); + var technology = new Technology(data) + technology.save(onsave) function onsave(err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Saved technology %s', technology.id); - fn(null, technology); + log('Saved technology %s', technology.id) + fn(null, technology) } - return this; -}; + return this +} /** * Update given `technology` @@ -114,31 +103,31 @@ exports.create = function create(data, fn) { */ exports.update = function update(data, fn) { - log('Updating technology %s with %j', data.id, data); + log('Updating technology %s with %j', data.id, data) // get technology - exports.get(data.id, onget); + exports.get(data.id, onget) function onget(err, technology) { if (err) { - log('Found error %s', err.message); - return fn(err); - }; + log('Found error %s', err.message) + return fn(err) + } // update and save technology document with data - technology.set(data); - technology.save(onupdate); + technology.set(data) + technology.save(onupdate) } function onupdate(err, technology) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) log('Saved technology %s', technology.id) - fn(null, technology); + fn(null, technology) } - return this; -}; + return this +} /** * Deletes technology @@ -152,16 +141,16 @@ exports.update = function update(data, fn) { */ exports.remove = function remove(id, fn) { - log('Deleting technology %s', id); + log('Deleting technology %s', id) Technology .remove({_id: id}) .exec(function (err) { - if (err) return log('Found error %s', err), fn(err); + if (err) return log('Found error %s', err), fn(err) - log('Removed technology %s', id); - fn(null, id); - }); + log('Removed technology %s', id) + fn(null, id) + }) - return this; -}; + return this +} From 02d4fafd2ad55bc7799858b5b82170e4bbf46ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Sat, 5 Nov 2016 19:41:57 -0300 Subject: [PATCH 09/60] Remove unused packages and bump the remaining ones --- package.json | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index a118bba..10330c4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "repository": { "type": "git", - "url": "git://github.com/democracyos/civic-stack.git" + "url": "git://github.com/civicstack/civicstack.git" }, "keywords": [ "nodejs", @@ -19,14 +19,13 @@ "author": "slifszyc", "license": "MIT", "bugs": { - "url": "https://github.com/democracyos/civic-stack/issues" + "url": "https://github.com/civicstack/civicstack/issues" }, "engines": { - "node": "4.5.0", - "npm": "2.7.6" + "node": "6.9.1", + "npm": "4.0.2" }, "dependencies": { - "autoprefixer-stylus": "^0.9.4", "babel-cli": "^6.18.0", "babel-loader": "^6.2.7", "babel-plugin-react-transform": "^2.0.2", @@ -35,51 +34,43 @@ "babel-preset-es2015": "^6.18.0", "babel-preset-react": "^6.16.0", "babel-preset-stage-0": "^6.16.0", - "batch": "0.5.2", - "bluebird": "^3.4.0", "body-parser": "1.12.0", - "builder-jade": "1.0.1", "commander": "2.5.0", - "component": "1.0.0", - "component-builder": "1.2.0", - "component-resolver": "1.2.7", "compression": "1.2.1", "connect-mongo": "0.8.2", "cookie-parser": "1.3.4", "crypto": "0.0.3", - "debug": "2.1.3", + "debug": "^2.2.0", "disqus-sso-express": "^0.1.0", "errorhandler": "1.3.0", - "express": "4.12.0", - "express-session": "v1.9.2", + "express": "^4.14.0", + "express-session": "^1.14.2", "extract-text-webpack-plugin": "^1.0.1", "glamor": "^2.17.14", "isomorphic-fetch": "^2.2.1", - "jade": "1.7.0 ", "merge-util": "0.1.0", "mkdirp": "0.5.0", "mongodb": "^2.2.9", - "mongoose": "3.8.24", - "mongoose-type-url": "1.0.0", - "mongoose-validator": "1.0.3", + "mongoose": "^4.6.6", + "mongoose-type-url": "^1.0.0", + "mongoose-validator": "^1.2.5", "node-cache": "^3.2.1", - "node-path": "0.0.3", "nowww": "1.1.3", "open-graph-scraper": "^2.1.0", - "passport": "0.2.0", - "passport-github": "0.1.5", - "passport-twitter": "1.0.2", + "passport": "^0.3.2", + "passport-github": "1.1.0", + "passport-twitter": "1.0.4", "pug": "^2.0.0-beta6", "react": "^15.3.2", "react-dom": "^15.3.2", "react-redux": "^4.4.5", + "react-router": "^3.0.0", "ready": "0.1.1", "redux": "^3.6.0", "redux-logger": "^2.7.4", "redux-thunk": "^2.1.0", "serve-favicon": "2.1.7", "string-to-js": "0.0.1", - "stylus": "0.49.3", "t-component": "1.0.0", "type-component": "0.0.1", "webpack": "^1.13.3" @@ -91,13 +82,13 @@ }, "devDependencies": { "eslint": "^3.9.1", - "mongodb-migrations": "^0.5.2", - "react-transform-hmr": "^1.0.4", "eslint-config-standard": "^6.0.0", "eslint-config-standard-react": "^4.0.0", - "eslint-plugin-promise": "^2.0.1", + "eslint-plugin-promise": "^3.3.0", "eslint-plugin-react": "^6.3.0", "eslint-plugin-standard": "^2.0.0", + "mongodb-migrations": "^0.5.2", + "react-transform-hmr": "^1.0.4", "webpack-dev-middleware": "^1.8.4", "webpack-hot-middleware": "^2.13.1", "xo": "^0.16.0" From 76652ce3c2fc060a0c574ce2df6e67ee15acb3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fresco?= Date: Thu, 1 Dec 2016 19:32:26 -0300 Subject: [PATCH 10/60] wip --- lib/app/actions/apps.js | 5 +-- lib/app/actions/index.js | 7 ++-- lib/app/components/AppList/index.js | 50 +++++++++++++++++++++++++++-- lib/app/components/AppList/modal.js | 34 ++++++++++++++++++++ lib/app/components/Footer/index.js | 4 +-- lib/app/containers/App.js | 11 +++++-- lib/app/reducers/apps.js | 14 ++++++-- lib/server/index.js | 2 +- package.json | 6 ++-- 9 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 lib/app/components/AppList/modal.js diff --git a/lib/app/actions/apps.js b/lib/app/actions/apps.js index 01f937e..4c3023a 100644 --- a/lib/app/actions/apps.js +++ b/lib/app/actions/apps.js @@ -10,6 +10,7 @@ module.exports.fetchApps = () => (dispatch, getState) => { }) .then(response => response.status >= 400 ? dispatch(failReceivingApps(response.status)) : response.json()) .then(data => dispatch(receiveApps(data))) + .catch(err => dispatch(failReceivingApps(err))) } const requestApps = () => ({ @@ -26,11 +27,11 @@ const failReceivingApps = error => ({ error }) -const filterApps = filters => ({ +export const filterApps = filters => ({ type: 'FILTER_APPS', filters }) -const clearAppsFilters = () => ({ +export const clearAppsFilters = () => ({ type: 'CLEAR_APPS_FILTERS' }) diff --git a/lib/app/actions/index.js b/lib/app/actions/index.js index 15f0c8a..9a7752e 100644 --- a/lib/app/actions/index.js +++ b/lib/app/actions/index.js @@ -1,3 +1,6 @@ -const apps = require('./apps') +const { fetchApps, filterApps } = require('./apps') -module.exports.fetchApps = apps.fetchApps +module.exports = { + fetchApps, + filterApps +} diff --git a/lib/app/components/AppList/index.js b/lib/app/components/AppList/index.js index 034bdf7..df176c9 100644 --- a/lib/app/components/AppList/index.js +++ b/lib/app/components/AppList/index.js @@ -1,22 +1,68 @@ const React = require('react') const { PropTypes } = React + const AppCard = require('./app-card') class AppList extends React.Component { static propTypes = { - apps: PropTypes.arrayOf(PropTypes.object) + apps: PropTypes.arrayOf(PropTypes.object), + onApplyPrefilter: PropTypes.func.isRequired } + applyPrefilter = filter => () => this.props.onApplyPrefilter(filter) + render () { const { apps } = this.props return (
+
-

Herramientas de código abierto para acciones políticas y sociales.

+

Herramientas de código abierto para acciones políticas y sociales.

+ + + + + + + + +
+
diff --git a/lib/app/components/AppList/modal.js b/lib/app/components/AppList/modal.js new file mode 100644 index 0000000..0cb5e66 --- /dev/null +++ b/lib/app/components/AppList/modal.js @@ -0,0 +1,34 @@ +const React = require('react') +const { Component, PropTypes } = React + +export default class Modal extends Component { + + render () { + return ( +
+
+
Filtrar por país + +
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+ ) + } +} diff --git a/lib/app/components/Footer/index.js b/lib/app/components/Footer/index.js index 2e06f0c..4cf2dce 100644 --- a/lib/app/components/Footer/index.js +++ b/lib/app/components/Footer/index.js @@ -4,9 +4,9 @@ const { footer, container } = require('./styles') class Footer extends React.Component { render () { return ( -