fix(user/settings): Add theme server validations
This commit is contained in:
@ -2,7 +2,6 @@ import analyticsEpic from './analytics-epic.js';
|
||||
import errEpic from './err-epic.js';
|
||||
import hardGoToEpic from './hard-go-to-epic.js';
|
||||
import mouseTrapEpic from './mouse-trap-epic.js';
|
||||
import nightModeEpic from './night-mode-epic.js';
|
||||
import titleEpic from './title-epic.js';
|
||||
|
||||
export default [
|
||||
@ -10,6 +9,5 @@ export default [
|
||||
errEpic,
|
||||
hardGoToEpic,
|
||||
mouseTrapEpic,
|
||||
nightModeEpic,
|
||||
titleEpic
|
||||
];
|
||||
|
@ -12,9 +12,11 @@ import { createSelector } from 'reselect';
|
||||
import fetchUserEpic from './fetch-user-epic.js';
|
||||
import updateMyCurrentChallengeEpic from './update-my-challenge-epic.js';
|
||||
import fetchChallengesEpic from './fetch-challenges-epic.js';
|
||||
import nightModeEpic from './night-mode-epic.js';
|
||||
|
||||
import { createFilesMetaCreator } from '../files';
|
||||
import { updateThemeMetacreator, entitiesSelector } from '../entities';
|
||||
import { utils } from '../Flash/redux';
|
||||
import { types as challenges } from '../routes/Challenges/redux';
|
||||
import { challengeToFiles } from '../routes/Challenges/utils';
|
||||
|
||||
@ -23,8 +25,9 @@ import ns from '../ns.json';
|
||||
import { themes, invertTheme } from '../../utils/themes.js';
|
||||
|
||||
export const epics = [
|
||||
fetchUserEpic,
|
||||
fetchChallengesEpic,
|
||||
fetchUserEpic,
|
||||
nightModeEpic,
|
||||
updateMyCurrentChallengeEpic
|
||||
];
|
||||
|
||||
@ -48,7 +51,7 @@ export const types = createTypes([
|
||||
|
||||
// night mode
|
||||
'toggleNightMode',
|
||||
'postThemeComplete'
|
||||
createAsyncTypes('postTheme')
|
||||
], ns);
|
||||
|
||||
const throwIfUndefined = () => {
|
||||
@ -130,6 +133,7 @@ export const createErrorObservable = error => Observable.just({
|
||||
type: types.handleError,
|
||||
error
|
||||
});
|
||||
// use sparingly
|
||||
// doActionOnError(
|
||||
// actionCreator: (() => Action|Null)
|
||||
// ) => (error: Error) => Observable[Action]
|
||||
@ -147,9 +151,18 @@ export const toggleNightMode = createAction(
|
||||
(username, theme) => updateThemeMetacreator(username, invertTheme(theme))
|
||||
);
|
||||
export const postThemeComplete = createAction(
|
||||
types.postThemeComplete,
|
||||
types.postTheme.complete,
|
||||
null,
|
||||
updateThemeMetacreator
|
||||
utils.createFlashMetaAction
|
||||
);
|
||||
|
||||
export const postThemeError = createAction(
|
||||
types.postTheme.error,
|
||||
null,
|
||||
(username, theme, err) => ({
|
||||
...updateThemeMetacreator(username, invertTheme(theme)),
|
||||
...utils.createFlashMetaAction(err)
|
||||
})
|
||||
);
|
||||
|
||||
const defaultState = {
|
||||
|
@ -6,14 +6,12 @@ import store from 'store';
|
||||
import { themes } from '../../utils/themes.js';
|
||||
import { postJSON$ } from '../../utils/ajax-stream.js';
|
||||
import {
|
||||
types,
|
||||
|
||||
csrfSelector,
|
||||
postThemeComplete,
|
||||
createErrorObservable,
|
||||
|
||||
postThemeError,
|
||||
themeSelector,
|
||||
usernameSelector,
|
||||
csrfSelector
|
||||
types,
|
||||
usernameSelector
|
||||
} from './index.js';
|
||||
|
||||
function persistTheme(theme) {
|
||||
@ -33,7 +31,8 @@ export default function nightModeEpic(
|
||||
::ofType(
|
||||
types.fetchUser.complete,
|
||||
types.toggleNightMode,
|
||||
types.postThemeComplete
|
||||
types.postTheme.complete,
|
||||
types.postTheme.error
|
||||
)
|
||||
.map(_.flow(getState, themeSelector))
|
||||
// catch existing night mode users
|
||||
@ -54,9 +53,10 @@ export default function nightModeEpic(
|
||||
const theme = themeSelector(getState());
|
||||
const username = usernameSelector(getState());
|
||||
return postJSON$('/update-my-theme', { _csrf, theme })
|
||||
.pluck('updatedTo')
|
||||
.map(theme => postThemeComplete(username, theme))
|
||||
.catch(createErrorObservable);
|
||||
.map(postThemeComplete)
|
||||
.catch(err => {
|
||||
return Observable.of(postThemeError(username, theme, err));
|
||||
});
|
||||
});
|
||||
|
||||
return Observable.merge(toggleBodyClass, postThemeEpic);
|
||||
|
@ -703,9 +703,7 @@ module.exports = function(User) {
|
||||
);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return this.update$({ theme })
|
||||
.map({ updatedTo: theme })
|
||||
.toPromise();
|
||||
return this.update$({ theme }).toPromise();
|
||||
};
|
||||
|
||||
// deprecated. remove once live
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
createValidatorErrorHandler
|
||||
} from '../utils/middleware';
|
||||
import supportedLanguages from '../../common/utils/supported-languages.js';
|
||||
import { themes } from '../../common/utils/themes.js';
|
||||
|
||||
export default function settingsController(app) {
|
||||
const api = app.loopback.Router();
|
||||
@ -79,22 +80,29 @@ export default function settingsController(app) {
|
||||
updateMyCurrentChallenge
|
||||
);
|
||||
|
||||
const updateMyThemeValidators = [
|
||||
check('theme')
|
||||
.isIn(Object.keys(themes))
|
||||
.withMessage('Theme is invalid.')
|
||||
];
|
||||
function updateMyTheme(req, res, next) {
|
||||
req.checkBody('theme', 'Theme is invalid.').isLength({ min: 4 });
|
||||
const { body: { theme } } = req;
|
||||
const errors = req.validationErrors(true);
|
||||
if (errors) {
|
||||
return res.status(403).json({ errors });
|
||||
}
|
||||
if (req.user.theme === theme) {
|
||||
return res.json({ msg: 'Theme already set' });
|
||||
return res.sendFlash('info', 'Theme already set');
|
||||
}
|
||||
return req.user.updateTheme('' + theme)
|
||||
return req.user.updateTheme(theme)
|
||||
.then(
|
||||
data => res.json(data),
|
||||
() => res.sendFlash('info', 'Your theme has been updated'),
|
||||
next
|
||||
);
|
||||
}
|
||||
api.post(
|
||||
'/update-my-theme',
|
||||
ifNoUser401,
|
||||
updateMyThemeValidators,
|
||||
createValidatorErrorHandler('errors'),
|
||||
updateMyTheme
|
||||
);
|
||||
|
||||
api.post(
|
||||
'/toggle-available-for-hire',
|
||||
@ -131,11 +139,6 @@ export default function settingsController(app) {
|
||||
ifNoUser401,
|
||||
updateMyLang
|
||||
);
|
||||
api.post(
|
||||
'/update-my-theme',
|
||||
ifNoUser401,
|
||||
updateMyTheme
|
||||
);
|
||||
|
||||
app.use(api);
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ export function wrapHandledError(err, {
|
||||
}
|
||||
|
||||
// for use with express-validator error formatter
|
||||
export const createValidatorErrorFormatter = (type, redirectTo, status) =>
|
||||
export const createValidatorErrorFormatter = (type, redirectTo) =>
|
||||
({ msg }) => wrapHandledError(
|
||||
new Error(msg),
|
||||
{
|
||||
type,
|
||||
message: msg,
|
||||
redirectTo,
|
||||
status
|
||||
// we default to 400 as these are malformed requests
|
||||
status: 400
|
||||
}
|
||||
);
|
||||
|
Reference in New Issue
Block a user