diff --git a/actions/loadDeck.js b/actions/loadDeck.js index 746a839f7..4106b4c61 100644 --- a/actions/loadDeck.js +++ b/actions/loadDeck.js @@ -37,6 +37,11 @@ import log from './log/clog'; export default function loadDeck(context, payload, done) { log.info(context); // do not remove such log messages. If you don't want to see them, change log level in config context.dispatch('UPDATE_MODE', {mode: 'loading'}); + + // resets the deck view store + // TODO (what other store to reset ???) + context.dispatch('LOAD_DECK_PAGE_START'); + if (!(AllowedPattern.DECK_ID.test(payload.params.id))) { context.executeAction(deckIdTypeError, payload, done); return; @@ -102,16 +107,6 @@ export default function loadDeck(context, payload, done) { payload.params.jwt = context.getStore(UserProfileStore).getState().jwt; - let permissionsPromise; - //if user is not logged in, only allow view mode and reset permissions, else load this user's permissions on the selected root deck - if (!payload.params.jwt){ - if (!payload.query.interestedUser) //NOTE should not be changed in the special case: Link from email for deck owner to add new editor - payloadCustom.params.mode = 'view'; - permissionsPromise = context.executeAction(resetPermissions, payloadCustom); - } else { - permissionsPromise = context.executeAction(loadPermissions, payloadCustom); - } - context.dispatch('UPDATE_DECK_PAGE_CONTENT', payloadCustom); pageTitle = pageTitle + ' | ' + payloadCustom.params.stype + ' | ' + payloadCustom.params.sid + ' | ' + payloadCustom.params.mode; if((currentState.selector.id === payloadCustom.params.id) && (currentState.selector.spath === payloadCustom.params.spath)){ @@ -131,6 +126,12 @@ export default function loadDeck(context, payload, done) { // load translation stuff context.executeAction(loadNodeTranslations, payload.params, (err, results) => { + if (err) { + // log the error and return!!! + log.error(context, {filepath: __filename, message: err.message}); + return done(err); + } + //load all required actions in parallel async.parallel([ (callback) => { @@ -141,6 +142,16 @@ export default function loadDeck(context, payload, done) { }, callback); }, (callback) => { + let permissionsPromise; + //if user is not logged in, only allow view mode and reset permissions, else load this user's permissions on the selected root deck + if (!payload.params.jwt){ + if (!payload.query.interestedUser) //NOTE should not be changed in the special case: Link from email for deck owner to add new editor + payloadCustom.params.mode = 'view'; + permissionsPromise = context.executeAction(resetPermissions, payloadCustom); + } else { + permissionsPromise = context.executeAction(loadPermissions, payloadCustom); + } + permissionsPromise.then(() => { let permissions = context.getStore(PermissionsStore).getState().permissions; //special handling for special case: Link from email for deck owner to add new editor diff --git a/actions/loadDeckView.js b/actions/loadDeckView.js index 156963249..3237cf11a 100644 --- a/actions/loadDeckView.js +++ b/actions/loadDeckView.js @@ -16,8 +16,7 @@ export default function loadDeckView(context, payload, done) { context.service.read('deck.content', payload, {timeout: 20 * 1000}, (err, res) => { if (err) { - console.log(err); - log.error(context, {filepath: __filename}); + log.error(context, {filepath: __filename, message: err.message }); context.executeAction(serviceUnavailable, payload, done); return; } else { diff --git a/actions/loadLegacy.js b/actions/loadLegacy.js index 08e2f6def..3c5481d0d 100644 --- a/actions/loadLegacy.js +++ b/actions/loadLegacy.js @@ -10,7 +10,7 @@ export default function loadLegacy(context, payload, done) { context.executeAction(serviceUnavailable, payload, done); //context.dispatch('LOAD_FEATURED_FAILURE', err); } else { - done({'statusCode':'301','redirectURL': '/deck/' + res.new_id}); + done({'statusCode': 301,'redirectURL': '/deck/' + res.new_id}); } }); } diff --git a/actions/translation/loadNodeTranslations.js b/actions/translation/loadNodeTranslations.js index 5f8151971..6358a835b 100644 --- a/actions/translation/loadNodeTranslations.js +++ b/actions/translation/loadNodeTranslations.js @@ -6,8 +6,8 @@ export default function loadNodeTranslations(context, payload, done) { context.service.read('decktree.nodetranslation', payload, {timeout: 20 * 1000}, (err, res) => { if (err) { - log.error(context, {filepath: __filename}); - context.executeAction(serviceUnavailable, payload, done); + log.error(context, {filepath: __filename, message: err.message}); + done(err); } else { context.dispatch('LOAD_TRANSLATIONS_SUCCESS', res); done(); diff --git a/components/Deck/ContentPanel/SlideModes/SlideViewPanel/SlideViewPanel.js b/components/Deck/ContentPanel/SlideModes/SlideViewPanel/SlideViewPanel.js index 31e24723a..f2f8b359c 100644 --- a/components/Deck/ContentPanel/SlideModes/SlideViewPanel/SlideViewPanel.js +++ b/components/Deck/ContentPanel/SlideModes/SlideViewPanel/SlideViewPanel.js @@ -50,7 +50,7 @@ class SlideViewPanel extends React.Component { deckTheme = this.props.DeckTreeStore.theme; } } - if (this.currentID === selector.sid){ + if (this.currentID === selector.sid && this.props.SlideViewStore.slideId) { let hideSpeakerNotes = true; if (this.props.SlideViewStore.speakernotes !== '' && this.props.SlideViewStore.speakernotes !== ' '){hideSpeakerNotes = false;} @@ -73,8 +73,7 @@ class SlideViewPanel extends React.Component { }; return (
- {(this.currentID !== selector.sid) ?
Loading
: ''} - {this.slideContentView} + {this.slideContentView ||
Loading
}
); } diff --git a/components/Deck/DeckLandingPage.js b/components/Deck/DeckLandingPage.js index c8e7491c2..61a9c05a2 100644 --- a/components/Deck/DeckLandingPage.js +++ b/components/Deck/DeckLandingPage.js @@ -4,6 +4,7 @@ import { NavLink } from 'fluxible-router'; import { Grid, Divider, Button, Header, Image, Icon, Item, Label, Menu, Segment, Container } from 'semantic-ui-react'; import { connectToStores } from 'fluxible-addons-react'; +import ContentStore from '../../stores/ContentStore'; import DeckPageStore from '../../stores/DeckPageStore'; import DeckViewStore from '../../stores/DeckViewStore'; import ContentLikeStore from '../../stores/ContentLikeStore'; @@ -55,8 +56,170 @@ class DeckLandingPage extends React.Component { return presLocation; } + getPlaceholder() { + return ( + + + ); + } + render() { let deckData = this.props.DeckViewStore.deckData; + if (lodash.isEmpty(deckData)) return this.getPlaceholder(); let firstSlide = (this.props.DeckViewStore.slidesData && this.props.DeckViewStore.slidesData.children && this.props.DeckViewStore.slidesData.children[0]); const totalSlides = lodash.get(this.props.DeckViewStore.slidesData, 'children.length', undefined); @@ -296,8 +459,17 @@ class DeckLandingPage extends React.Component { } } -DeckLandingPage = connectToStores(DeckLandingPage, [ContentLikeStore, DeckPageStore, DeckViewStore, TranslationStore, ContentModulesStore, SimilarContentStore], (context, props) => { +DeckLandingPage = connectToStores(DeckLandingPage, [ + ContentStore, + ContentLikeStore, + DeckPageStore, + DeckViewStore, + TranslationStore, + ContentModulesStore, + SimilarContentStore, +], (context, props) => { return { + ContentStore: context.getStore(ContentStore).getState(), ContentLikeStore: context.getStore(ContentLikeStore).getState(), DeckPageStore: context.getStore(DeckPageStore).getState(), DeckViewStore: context.getStore(DeckViewStore).getState(), diff --git a/configs/routes.js b/configs/routes.js index 0ab12d7a9..f790fc42b 100644 --- a/configs/routes.js +++ b/configs/routes.js @@ -23,6 +23,7 @@ import loadImportFile from '../actions/loadImportFile'; import loadPresentation from '../actions/loadPresentation'; import loadAddDeck from '../actions/loadAddDeck'; import notFoundError from '../actions/error/notFoundError'; +import serviceUnavailable from '../actions/error/serviceUnavailable'; import loadResetPassword from '../actions/loadResetPassword'; import async from 'async'; import { chooseAction } from '../actions/user/userprofile/chooseAction'; @@ -381,7 +382,16 @@ export default { handler: require('../components/Deck/DeckLandingPage'), page: 'decklandingpage', action: (context, payload, done) => { - context.executeAction(loadDeck, payload, done); + context.executeAction(loadDeck, payload, (err) => { + if (err) { + if (err.statusCode === 404) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } + done(); + }); } }, @@ -397,13 +407,18 @@ export default { }, (callback) => { context.executeAction(loadDeckStats, {deckId: payload.params.id}, callback); - }, + }], (err, result) => { - if(err) console.log(err); + if (err) { + if (err.statusCode === 404) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } done(); } - ]); - + ); } }, @@ -429,7 +444,17 @@ export default { } } - context.executeAction(loadDeck, payload, done); + context.executeAction(loadDeck, payload, (err) => { + if (err) { + // check for either 404 or 422. 422 is returned from deck service when the deck/slide combo do not match + if (err.statusCode === 404 || err.statusCode === 422) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } + done(); + }); } }, @@ -448,7 +473,7 @@ export default { ]; urlParts = urlParts.filter((u) => !!u); - done({statusCode: '301', redirectURL: urlParts.join('/')}); + done({statusCode: 301, redirectURL: urlParts.join('/')}); }, }, legacydeck: { @@ -656,12 +681,18 @@ export default { payload.params.sid = payload.params.slideID;//needs to be reset for loadPresentation payload.params.language = payload.query.language; context.executeAction(loadPresentation, payload, callback); - }, + }], (err, result) => { - if(err) console.log(err); + if (err) { + if (err.statusCode === 404) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } done(); } - ]); + ); } }, presentationIE: { @@ -683,12 +714,18 @@ export default { // adding language to the params payload.params.language = payload.query.language; context.executeAction(loadPresentation, payload, callback); - }, + }], (err, result) => { - if(err) console.log(err); + if (err) { + if (err.statusCode === 404) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } done(); } - ]); + ); } }, print: { @@ -714,12 +751,18 @@ export default { // adding language to the params payload.params.language = payload.query.language; context.executeAction(loadPresentation, payload, callback); - }, + }], (err, result) => { - if(err) console.log(err); + if (err) { + if (err.statusCode === 404) { + return context.executeAction(notFoundError, payload, done); + } else { + return context.executeAction(serviceUnavailable, payload, done); + } + } done(); } - ]); + ); } }, oldSlugPresentation: { @@ -735,7 +778,7 @@ export default { ]; urlParts = urlParts.filter((u) => !!u); - done({statusCode: '301', redirectURL: urlParts.join('/')}); + done({statusCode: 301, redirectURL: urlParts.join('/')}); }, }, neo4jguide: { @@ -760,7 +803,7 @@ export default { ]; urlParts = urlParts.filter((u) => !!u); - done({statusCode: '301', redirectURL: urlParts.join('/')}); + done({statusCode: 301, redirectURL: urlParts.join('/')}); }, }, importfile: { diff --git a/server/handleServerRendering.js b/server/handleServerRendering.js index ee32707cd..286f49298 100644 --- a/server/handleServerRendering.js +++ b/server/handleServerRendering.js @@ -120,26 +120,25 @@ export default function handleServerRendering(req, res, next){ reqId: req.reqId }, (err) => { if (err) { - if (err.statusCode && err.statusCode === '301') { - //console.log('REDIRECTING to '+ JSON.stringify(err)); + if (err.statusCode === 301) { res.redirect(301, err.redirectURL); - }else - if (err.statusCode && err.statusCode === '404') { + } else if (err.statusCode) { + // render page and also set status to the error code let html = renderApp(req, res, context); debug('Sending markup'); res.type('html'); res.status(err.statusCode); log.error({Id: res.reqId, URL: req.url, StatusCode: res.statusCode, StatusMessage: res.statusMessage, Message: 'Sending response'}); + res.write('' + html); res.end(); - return; - }else{ + } else { + // TODO render page even though there was an error ???? let html = renderApp(req, res, context); debug('Sending markup'); res.type('html'); res.write('' + html); log.error({Id: res.reqId, URL: req.url, StatusCode: res.statusCode, StatusMessage: res.statusMessage, Message: 'Sending response'}); res.end(); - return; } } else { diff --git a/services/deck.js b/services/deck.js index dacf2cbda..d21a51ad1 100644 --- a/services/deck.js +++ b/services/deck.js @@ -225,6 +225,8 @@ export default { return userPromisesMap[user] = userPromisesMap[user] || rp.get({ uri: Microservices.user.uri + '/user/' + user.toString(), json: true, + }).catch((err) => { + // ignore this for now, return nothing }); }); return Promise.all(userPromises); @@ -252,8 +254,8 @@ export default { callback(null, { deckData, slidesData, - creatorData: usersData[0], - ownerData: usersData[1], + creatorData: usersData[0] || {}, + ownerData: usersData[1] || {}, originCreatorData: usersData[2] || {}, }); }).catch((err) => { diff --git a/services/decktree.js b/services/decktree.js index 22d1e279e..cffbe70e4 100644 --- a/services/decktree.js +++ b/services/decktree.js @@ -30,8 +30,7 @@ export default { }).then((res) => { callback(null, {translations: res, selector: selector, language: args.language}); }).catch((err) => { - console.log(err); - callback(null, {translations: [], selector: selector, language: args.language}); + callback(err); }); } diff --git a/stores/DeckViewStore.js b/stores/DeckViewStore.js index 4d4aa0d7d..c0fd69e08 100644 --- a/stores/DeckViewStore.js +++ b/stores/DeckViewStore.js @@ -34,6 +34,16 @@ class DeckViewStore extends BaseStore { this.emitChange(); } + resetContent() { + this.deckData = {}; + this.slidesData = {}; + this.creatorData = {}; + this.ownerData = {}; + this.originCreatorData = {}; + this.deckViewPanelHeight = 450; + this.emitChange(); + } + getState() { return { deckData: this.deckData, @@ -59,6 +69,7 @@ class DeckViewStore extends BaseStore { DeckViewStore.storeName = 'DeckViewStore'; DeckViewStore.handlers = { + 'LOAD_DECK_PAGE_START': 'resetContent', 'LOAD_DECK_CONTENT_SUCCESS': 'updateContent', 'UPDATE_DECK_VIEW_PANEL_HEIGHT': 'updateDeckViewPanelHeight', 'INCREMENT_DECK_VIEW_COUNTER': 'incrementDeckViewCounter' diff --git a/stores/SlideViewStore.js b/stores/SlideViewStore.js index f5d548fed..4a8f80f81 100644 --- a/stores/SlideViewStore.js +++ b/stores/SlideViewStore.js @@ -14,6 +14,16 @@ class SlideViewStore extends BaseStore { this.annotations = []; } + resetContent() { + this.id = ''; + this.slideId = ''; + this.title = ''; + this.content = ''; + this.speakernotes = ''; + this.tags = []; + this.emitChange(); + } + updateContent(payload) { //this.id = payload.slide.id; this.slideId = payload.selector.sid; @@ -78,6 +88,7 @@ class SlideViewStore extends BaseStore { SlideViewStore.storeName = 'SlideViewStore'; SlideViewStore.handlers = { + 'LOAD_DECK_PAGE_START': 'resetContent', 'LOAD_SLIDE_CONTENT_SUCCESS': 'updateContent', 'ZOOM': 'zoomContent' };