From a1a4ac883db283f361c6ca0ef5c967ceee2969c2 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Fri, 24 Jul 2015 17:52:07 -0700 Subject: [PATCH] add user stores/actions construct fetchr on every request --- client/index.js | 8 +++- common/app/App.jsx | 49 +++++++++++++++---------- common/app/Cat.js | 10 +++-- common/app/flux/Actions.js | 31 ++++++++++++++++ common/app/flux/Store.js | 18 +++++++++ common/app/flux/index.js | 2 + common/app/routes/Hikes/flux/Actions.js | 8 +--- server/boot/a-react.js | 6 ++- server/boot/a-services.js | 3 ++ server/services/user.js | 30 +++++++++++++++ 10 files changed, 131 insertions(+), 34 deletions(-) create mode 100644 common/app/flux/Actions.js create mode 100644 common/app/flux/Store.js create mode 100644 common/app/flux/index.js create mode 100644 server/services/user.js diff --git a/client/index.js b/client/index.js index e95bd0f9084..c39b55c644b 100644 --- a/client/index.js +++ b/client/index.js @@ -1,8 +1,9 @@ import Rx from 'rx'; import React from 'react'; +import Fetchr from 'fetchr'; +import debugFactory from 'debug'; import { Router } from 'react-router'; import { history } from 'react-router/lib/BrowserHistory'; -import debugFactory from 'debug'; import { hydrate } from 'thundercats'; import { Render } from 'thundercats-react'; @@ -11,6 +12,9 @@ import { app$ } from '../common/app'; const debug = debugFactory('fcc:client'); const DOMContianer = document.getElementById('fcc'); const catState = window.__fcc__.data || {}; +const services = new Fetchr({ + xhrPath: '/services' +}); Rx.longStackSupport = !!debug.enabled; @@ -18,7 +22,7 @@ Rx.longStackSupport = !!debug.enabled; app$(history) .flatMap( ({ AppCat }) => { - const appCat = AppCat(); + const appCat = AppCat(null, services); return hydrate(appCat, catState) .map(() => appCat); }, diff --git a/common/app/App.jsx b/common/app/App.jsx index e97ac4d83f3..6ebfa221f0e 100644 --- a/common/app/App.jsx +++ b/common/app/App.jsx @@ -1,28 +1,37 @@ import React, { PropTypes } from 'react'; +import { contain } from 'thundercats-react'; import { Row } from 'react-bootstrap'; import { Nav } from './components/Nav'; import { Footer } from './components/Footer'; -export default class extends React.Component { - constructor(props) { - super(props); - } +export default contain( + { + store: 'appStore', + fetchAction: 'appActions.getUser', + getPayload(props) { + return { + isPrimed: !!props.username + }; + } + }, + React.createClass({ + displayName: 'FreeCodeCamp', - static displayName = 'FreeCodeCamp' - static propTypes = { - children: PropTypes.node - } + propTypes: { + children: PropTypes.node + }, - render() { - return ( -
-
- ); - } -} + render() { + return ( +
+
+ ); + } + }) +); diff --git a/common/app/Cat.js b/common/app/Cat.js index d1686b78fc9..3a7c3246e6f 100644 --- a/common/app/Cat.js +++ b/common/app/Cat.js @@ -1,9 +1,11 @@ import { Cat } from 'thundercats'; import { HikesActions, HikesStore } from './routes/Hikes/flux'; - +import { AppActions, AppStore } from './flux'; export default Cat() - .init(({ instance }) => { - instance.register(HikesActions); - instance.register(HikesStore, null, instance); + .init(({ instance: cat, args: [services] }) => { + cat.register(AppActions, null, services); + cat.register(AppStore, null, cat); + cat.register(HikesActions, null, services); + cat.register(HikesStore, null, cat); }); diff --git a/common/app/flux/Actions.js b/common/app/flux/Actions.js new file mode 100644 index 00000000000..f915d34f9dc --- /dev/null +++ b/common/app/flux/Actions.js @@ -0,0 +1,31 @@ +import { Actions } from 'thundercats'; +import debugFactory from 'debug'; + +const debug = debugFactory('freecc:app:actions'); + +export default Actions({ + setUser({ username, picture, progressTimestamps = [] }) { + return { + username, + picture, + points: progressTimestamps.length + }; + }, + getUser: null +}) + .refs({ displayName: 'AppActions' }) + .init(({ instance: appActions, args: [services] }) => { + appActions.getUser.subscribe(({ isPrimed }) => { + if (isPrimed) { + debug('isPrimed'); + return; + } + services.read('user', null, null, (err, user) => { + if (err) { + return debug('user service error'); + } + debug('user service returned successful'); + return appActions.setUser(user); + }); + }); + }); diff --git a/common/app/flux/Store.js b/common/app/flux/Store.js new file mode 100644 index 00000000000..09d50e69c0f --- /dev/null +++ b/common/app/flux/Store.js @@ -0,0 +1,18 @@ +import { Store } from 'thundercats'; + +const { createRegistrar, setter } = Store; +const initValue = { + username: null, + picture: null, + points: 0 +}; + +export default Store(initValue) + .refs({ displayName: 'AppStore' }) + .init(({ instance: appStore, args: [cat] }) => { + const { setUser } = cat.getActions('appActions'); + const register = createRegistrar(appStore); + register(setter(setUser)); + + return appStore; + }); diff --git a/common/app/flux/index.js b/common/app/flux/index.js new file mode 100644 index 00000000000..a07e138ae6c --- /dev/null +++ b/common/app/flux/index.js @@ -0,0 +1,2 @@ +export AppActions from './Actions'; +export AppStore from './Store'; diff --git a/common/app/routes/Hikes/flux/Actions.js b/common/app/routes/Hikes/flux/Actions.js index b3532f15f06..ddc41005649 100644 --- a/common/app/routes/Hikes/flux/Actions.js +++ b/common/app/routes/Hikes/flux/Actions.js @@ -1,12 +1,8 @@ import { Actions } from 'thundercats'; import assign from 'object.assign'; import debugFactory from 'debug'; -import Fetchr from 'fetchr'; const debug = debugFactory('freecc:hikes:actions'); -const service = new Fetchr({ - xhrPath: '/services' -}); function getCurrentHike(hikes =[{}], dashedName, currentHike) { if (!dashedName) { @@ -36,7 +32,7 @@ export default Actions({ setHikes: null }) .refs({ displayName: 'HikesActions' }) - .init(({ instance }) => { + .init(({ instance, args: [services] }) => { // set up hikes fetching instance.fetchHikes.subscribe( ({ isPrimed, dashedName }) => { @@ -53,7 +49,7 @@ export default Actions({ } }); } - service.read('hikes', null, null, (err, hikes) => { + services.read('hikes', null, null, (err, hikes) => { if (err) { debug('an error occurred fetching hikes', err); } diff --git a/server/boot/a-react.js b/server/boot/a-react.js index cf4bb86d43b..9cf7d06f694 100644 --- a/server/boot/a-react.js +++ b/server/boot/a-react.js @@ -1,11 +1,12 @@ import React from 'react'; import Router from 'react-router'; +import Fetchr from 'fetchr'; import Location from 'react-router/lib/Location'; import debugFactory from 'debug'; import { app$ } from '../../common/app'; import { RenderToString } from 'thundercats-react'; -const debug = debugFactory('freecc:servereact'); +const debug = debugFactory('freecc:react-server'); // add routes here as they slowly get reactified // remove their individual controllers @@ -25,6 +26,7 @@ export default function reactSubRouter(app) { app.use(router); function serveReactApp(req, res, next) { + const services = new Fetchr({ req }); const location = new Location(req.path, req.query); // returns a router wrapped app @@ -42,7 +44,7 @@ export default function reactSubRouter(app) { // prefetches data and sets up it up for current state debug('rendering to string'); return RenderToString( - AppCat(), + AppCat(null, services), React.createElement(Router, initialState) ); }) diff --git a/server/boot/a-services.js b/server/boot/a-services.js index 3cb288a99dd..a93cc217c9c 100644 --- a/server/boot/a-services.js +++ b/server/boot/a-services.js @@ -1,8 +1,11 @@ import Fetchr from 'fetchr'; import getHikesService from '../services/hikes'; +import getUserServices from '../services/user'; export default function bootServices(app) { const hikesService = getHikesService(app); + const userServices = getUserServices(app); Fetchr.registerFetcher(hikesService); + Fetchr.registerFetcher(userServices); app.use('/services', Fetchr.middleware()); } diff --git a/server/services/user.js b/server/services/user.js new file mode 100644 index 00000000000..5f293bfee07 --- /dev/null +++ b/server/services/user.js @@ -0,0 +1,30 @@ +import debugFactory from 'debug'; +import assign from 'object.assign'; + +const censor = '**********************:P********'; +const debug = debugFactory('freecc:services:user'); +const protectedUserFields = { + id: censor, + password: censor, + profiles: censor +}; + +export default function userServices(/* app */) { + return { + name: 'user', + read: (req, resource, params, config, cb) => { + let { user } = req; + if (user) { + debug('user is signed in'); + // Zalgo!!! + return process.nextTick(() => { + cb(null, assign({}, user.toJSON(), protectedUserFields)); + }); + } + debug('user is not signed in'); + return process.nextTick(() => { + cb(null, {}); + }); + } + }; +}