Feature(settings): add user flag logic
This also moves a couple of settings to their own controller
This commit is contained in:
@ -8,6 +8,7 @@ import {
|
|||||||
reducer as challengesApp,
|
reducer as challengesApp,
|
||||||
projectNormalizer
|
projectNormalizer
|
||||||
} from './routes/challenges/redux';
|
} from './routes/challenges/redux';
|
||||||
|
import { reducer as settingsApp } from './routes/settings/redux';
|
||||||
|
|
||||||
export default function createReducer(sideReducers = {}) {
|
export default function createReducer(sideReducers = {}) {
|
||||||
return combineReducers({
|
return combineReducers({
|
||||||
@ -16,6 +17,7 @@ export default function createReducer(sideReducers = {}) {
|
|||||||
app,
|
app,
|
||||||
toasts,
|
toasts,
|
||||||
challengesApp,
|
challengesApp,
|
||||||
|
settingsApp,
|
||||||
form: formReducer.normalize({ ...projectNormalizer })
|
form: formReducer.normalize({ ...projectNormalizer })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,11 @@ export const updateUserPoints = createAction(
|
|||||||
types.updateUserPoints,
|
types.updateUserPoints,
|
||||||
(username, points) => ({ username, points })
|
(username, points) => ({ username, points })
|
||||||
);
|
);
|
||||||
|
// updateUserPoints(username: String, flag: String) => Action
|
||||||
|
export const updateUserFlag = createAction(
|
||||||
|
types.updateUserFlag,
|
||||||
|
(username, flag) => ({ username, flag })
|
||||||
|
);
|
||||||
// updateCompletedChallenges(username: String) => Action
|
// updateCompletedChallenges(username: String) => Action
|
||||||
export const updateCompletedChallenges = createAction(
|
export const updateCompletedChallenges = createAction(
|
||||||
types.updateCompletedChallenges
|
types.updateCompletedChallenges
|
||||||
|
@ -9,7 +9,7 @@ const initialState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function entities(state = initialState, action) {
|
export default function entities(state = initialState, action) {
|
||||||
const { type, payload: { username, points } = {} } = action;
|
const { type, payload: { username, points, flag } = {} } = action;
|
||||||
if (type === updateCompletedChallenges) {
|
if (type === updateCompletedChallenges) {
|
||||||
const username = action.payload;
|
const username = action.payload;
|
||||||
const completedChallengeMap = state.user[username].challengeMap || {};
|
const completedChallengeMap = state.user[username].challengeMap || {};
|
||||||
@ -44,5 +44,17 @@ export default function entities(state = initialState, action) {
|
|||||||
...action.meta.entities
|
...action.meta.entities
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (action.type === types.updateUserFlag) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
user: {
|
||||||
|
...state.user,
|
||||||
|
[username]: {
|
||||||
|
...state.user[username],
|
||||||
|
[flag]: !state.user[username][flag]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ export default createTypes([
|
|||||||
'addUser',
|
'addUser',
|
||||||
'updateThisUser',
|
'updateThisUser',
|
||||||
'updateUserPoints',
|
'updateUserPoints',
|
||||||
|
'updateUserFlag',
|
||||||
'updateCompletedChallenges',
|
'updateCompletedChallenges',
|
||||||
'showSignIn',
|
'showSignIn',
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export function UpdateEmailButton() {
|
|||||||
bsSize='lg'
|
bsSize='lg'
|
||||||
bsStyle='primary'
|
bsStyle='primary'
|
||||||
className='btn-link-social'
|
className='btn-link-social'
|
||||||
|
href='/update-email'
|
||||||
>
|
>
|
||||||
<FA name='envelope' />
|
<FA name='envelope' />
|
||||||
Update my Email
|
Update my Email
|
||||||
@ -21,7 +22,10 @@ export default function EmailSettings({
|
|||||||
email,
|
email,
|
||||||
sendMonthlyEmail,
|
sendMonthlyEmail,
|
||||||
sendNotificationEmail,
|
sendNotificationEmail,
|
||||||
sendQuincyEmail
|
sendQuincyEmail,
|
||||||
|
toggleMonthlyEmail,
|
||||||
|
toggleNotificationEmail,
|
||||||
|
toggleQuincyEmail
|
||||||
}) {
|
}) {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
return (
|
return (
|
||||||
@ -63,6 +67,7 @@ export default function EmailSettings({
|
|||||||
className={
|
className={
|
||||||
classnames('positive-20', { active: sendMonthlyEmail })
|
classnames('positive-20', { active: sendMonthlyEmail })
|
||||||
}
|
}
|
||||||
|
onClick={ toggleMonthlyEmail }
|
||||||
>
|
>
|
||||||
{ sendMonthlyEmail ? 'On' : 'Off' }
|
{ sendMonthlyEmail ? 'On' : 'Off' }
|
||||||
</Button>
|
</Button>
|
||||||
@ -84,6 +89,7 @@ export default function EmailSettings({
|
|||||||
className={
|
className={
|
||||||
classnames('positive-20', { active: sendNotificationEmail })
|
classnames('positive-20', { active: sendNotificationEmail })
|
||||||
}
|
}
|
||||||
|
onClick={ toggleNotificationEmail }
|
||||||
>
|
>
|
||||||
{ sendNotificationEmail ? 'On' : 'Off' }
|
{ sendNotificationEmail ? 'On' : 'Off' }
|
||||||
</Button>
|
</Button>
|
||||||
@ -105,6 +111,7 @@ export default function EmailSettings({
|
|||||||
className={
|
className={
|
||||||
classnames('positive-20', { active: sendQuincyEmail })
|
classnames('positive-20', { active: sendQuincyEmail })
|
||||||
}
|
}
|
||||||
|
onClick={ toggleQuincyEmail }
|
||||||
>
|
>
|
||||||
{ sendQuincyEmail ? 'On' : 'Off' }
|
{ sendQuincyEmail ? 'On' : 'Off' }
|
||||||
</Button>
|
</Button>
|
||||||
@ -118,5 +125,8 @@ EmailSettings.propTypes = {
|
|||||||
email: PropTypes.string,
|
email: PropTypes.string,
|
||||||
sendMonthlyEmail: PropTypes.bool,
|
sendMonthlyEmail: PropTypes.bool,
|
||||||
sendNotificationEmail: PropTypes.bool,
|
sendNotificationEmail: PropTypes.bool,
|
||||||
sendQuincyEmail: PropTypes.bool
|
sendQuincyEmail: PropTypes.bool,
|
||||||
|
toggleMonthlyEmail: PropTypes.func.isRequired,
|
||||||
|
toggleNotificationEmail: PropTypes.func.isRequired,
|
||||||
|
toggleQuincyEmail: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,15 @@ import React, { PropTypes } from 'react';
|
|||||||
import { FormControl } from 'react-bootstrap';
|
import { FormControl } from 'react-bootstrap';
|
||||||
import langs from '../../../../utils/supported-languages';
|
import langs from '../../../../utils/supported-languages';
|
||||||
|
|
||||||
const langOptions = [
|
const options = [(
|
||||||
|
<option
|
||||||
|
disabled={ true }
|
||||||
|
key='default'
|
||||||
|
value='not-the-momma'
|
||||||
|
>
|
||||||
|
Prefered Langauge
|
||||||
|
</option>
|
||||||
|
),
|
||||||
...Object.keys(langs).map(tag => {
|
...Object.keys(langs).map(tag => {
|
||||||
return (
|
return (
|
||||||
<option
|
<option
|
||||||
@ -23,21 +31,12 @@ const langOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function LangaugeSettings({ userLang }) {
|
export default function LangaugeSettings({ userLang }) {
|
||||||
const options = [(
|
|
||||||
<option
|
|
||||||
disabled={ true }
|
|
||||||
key='default'
|
|
||||||
selected={ userLang ? false : true }
|
|
||||||
>
|
|
||||||
Prefered Langauge
|
|
||||||
</option>
|
|
||||||
),
|
|
||||||
...langOptions
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<FormControl
|
<FormControl
|
||||||
className='btn btn-block btn-primary btn-link-social'
|
className='btn btn-block btn-primary btn-link-social'
|
||||||
componentClass='select'
|
componentClass='select'
|
||||||
|
defaultValue='not-the-momma'
|
||||||
|
value={ userLang }
|
||||||
>
|
>
|
||||||
{ options }
|
{ options }
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
@ -2,7 +2,7 @@ import React, { PropTypes } from 'react';
|
|||||||
import { Button, Row, Col } from 'react-bootstrap';
|
import { Button, Row, Col } from 'react-bootstrap';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
export default function LockSettings({ isLocked }) {
|
export default function LockSettings({ isLocked, toggle }) {
|
||||||
const className = classnames({
|
const className = classnames({
|
||||||
'positive-20': true,
|
'positive-20': true,
|
||||||
active: isLocked
|
active: isLocked
|
||||||
@ -22,6 +22,7 @@ export default function LockSettings({ isLocked }) {
|
|||||||
bsSize='lg'
|
bsSize='lg'
|
||||||
bsStyle='primary'
|
bsStyle='primary'
|
||||||
className={ className }
|
className={ className }
|
||||||
|
onClick={ toggle }
|
||||||
>
|
>
|
||||||
{ isLocked ? 'On' : 'Off' }
|
{ isLocked ? 'On' : 'Off' }
|
||||||
</Button>
|
</Button>
|
||||||
@ -31,5 +32,6 @@ export default function LockSettings({ isLocked }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LockSettings.propTypes = {
|
LockSettings.propTypes = {
|
||||||
isLocked: PropTypes.bool
|
isLocked: PropTypes.bool,
|
||||||
|
toggle: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
import { Button, Row, Col } from 'react-bootstrap';
|
import { Button, Row, Col } from 'react-bootstrap';
|
||||||
import FA from 'react-fontawesome';
|
import FA from 'react-fontawesome';
|
||||||
|
|
||||||
@ -8,10 +9,58 @@ import EmailSettings from './Email-Setting.jsx';
|
|||||||
import LangaugeSettings from './Language-Settings.jsx';
|
import LangaugeSettings from './Language-Settings.jsx';
|
||||||
import DeleteModal from './Delete-Modal.jsx';
|
import DeleteModal from './Delete-Modal.jsx';
|
||||||
|
|
||||||
export default class Settings extends React.Component {
|
import {
|
||||||
|
toggleUserFlag,
|
||||||
|
openDeleteModal,
|
||||||
|
hideDeleteModal
|
||||||
|
} from '../redux/actions';
|
||||||
|
import { toggleNightMode } from '../../../redux/actions';
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
toggleNightMode,
|
||||||
|
openDeleteModal,
|
||||||
|
hideDeleteModal,
|
||||||
|
toggleIsLocked: () => toggleUserFlag('isLocked'),
|
||||||
|
toggleQuincyEmail: () => toggleUserFlag('sendQuincyEmail'),
|
||||||
|
toggleNotificationEmail: () => toggleUserFlag('sendNotificationEmail'),
|
||||||
|
toggleMonthlyEmail: () => toggleUserFlag('sendMonthlyEmail')
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const {
|
||||||
|
app: { user: username },
|
||||||
|
entities: { user: userMap },
|
||||||
|
settingsApp: { isDeleteOpen }
|
||||||
|
} = state;
|
||||||
|
const {
|
||||||
|
email,
|
||||||
|
isLocked,
|
||||||
|
isGithubCool,
|
||||||
|
isTwitter,
|
||||||
|
isLinkedIn,
|
||||||
|
sendMonthlyEmail,
|
||||||
|
sendNotificationEmail,
|
||||||
|
sendQuincyEmail
|
||||||
|
} = userMap[username] || {};
|
||||||
|
return {
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
isDeleteOpen,
|
||||||
|
isLocked,
|
||||||
|
isGithubCool,
|
||||||
|
isTwitter,
|
||||||
|
isLinkedIn,
|
||||||
|
sendMonthlyEmail,
|
||||||
|
sendNotificationEmail,
|
||||||
|
sendQuincyEmail
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Settings extends React.Component {
|
||||||
static displayName = 'Settings';
|
static displayName = 'Settings';
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
|
isDeleteOpen: PropTypes.bool,
|
||||||
isLocked: PropTypes.bool,
|
isLocked: PropTypes.bool,
|
||||||
isGithubCool: PropTypes.bool,
|
isGithubCool: PropTypes.bool,
|
||||||
isTwitter: PropTypes.bool,
|
isTwitter: PropTypes.bool,
|
||||||
@ -19,12 +68,20 @@ export default class Settings extends React.Component {
|
|||||||
email: PropTypes.string,
|
email: PropTypes.string,
|
||||||
sendMonthlyEmail: PropTypes.bool,
|
sendMonthlyEmail: PropTypes.bool,
|
||||||
sendNotificationEmail: PropTypes.bool,
|
sendNotificationEmail: PropTypes.bool,
|
||||||
sendQuincyEmail: PropTypes.bool
|
sendQuincyEmail: PropTypes.bool,
|
||||||
|
toggleNightMode: PropTypes.func,
|
||||||
|
toggleIsLocked: PropTypes.func,
|
||||||
|
toggleQuincyEmail: PropTypes.func,
|
||||||
|
toggleMonthlyEmail: PropTypes.func,
|
||||||
|
toggleNotificationEmail: PropTypes.func,
|
||||||
|
openDeleteModal: PropTypes.func,
|
||||||
|
hideDeleteModal: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
username,
|
username,
|
||||||
|
isDeleteOpen,
|
||||||
isLocked,
|
isLocked,
|
||||||
isGithubCool,
|
isGithubCool,
|
||||||
isTwitter,
|
isTwitter,
|
||||||
@ -32,7 +89,14 @@ export default class Settings extends React.Component {
|
|||||||
email,
|
email,
|
||||||
sendMonthlyEmail,
|
sendMonthlyEmail,
|
||||||
sendNotificationEmail,
|
sendNotificationEmail,
|
||||||
sendQuincyEmail
|
sendQuincyEmail,
|
||||||
|
toggleNightMode,
|
||||||
|
toggleIsLocked,
|
||||||
|
toggleQuincyEmail,
|
||||||
|
toggleMonthlyEmail,
|
||||||
|
toggleNotificationEmail,
|
||||||
|
openDeleteModal,
|
||||||
|
hideDeleteModal
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -77,6 +141,7 @@ export default class Settings extends React.Component {
|
|||||||
bsSize='lg'
|
bsSize='lg'
|
||||||
bsStyle='primary'
|
bsStyle='primary'
|
||||||
className='btn-link-social'
|
className='btn-link-social'
|
||||||
|
onClick={ toggleNightMode }
|
||||||
>
|
>
|
||||||
NightMode
|
NightMode
|
||||||
</Button>
|
</Button>
|
||||||
@ -116,7 +181,10 @@ export default class Settings extends React.Component {
|
|||||||
smOffset={ 2 }
|
smOffset={ 2 }
|
||||||
xs={ 12 }
|
xs={ 12 }
|
||||||
>
|
>
|
||||||
<LockedSettings isLocked={ isLocked } />
|
<LockedSettings
|
||||||
|
isLocked={ isLocked }
|
||||||
|
toggle={ toggleIsLocked }
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<div className='spacer' />
|
<div className='spacer' />
|
||||||
@ -134,6 +202,9 @@ export default class Settings extends React.Component {
|
|||||||
sendMonthlyEmail={ sendMonthlyEmail }
|
sendMonthlyEmail={ sendMonthlyEmail }
|
||||||
sendNotificationEmail={ sendNotificationEmail }
|
sendNotificationEmail={ sendNotificationEmail }
|
||||||
sendQuincyEmail={ sendQuincyEmail }
|
sendQuincyEmail={ sendQuincyEmail }
|
||||||
|
toggleMonthlyEmail={ toggleMonthlyEmail }
|
||||||
|
toggleNotificationEmail={ toggleNotificationEmail }
|
||||||
|
toggleQuincyEmail={ toggleQuincyEmail }
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -160,7 +231,11 @@ export default class Settings extends React.Component {
|
|||||||
smOffset={ 2 }
|
smOffset={ 2 }
|
||||||
xs={ 12 }
|
xs={ 12 }
|
||||||
>
|
>
|
||||||
<DeleteModal />
|
<DeleteModal
|
||||||
|
hide={ hideDeleteModal }
|
||||||
|
isOpen={ isDeleteOpen }
|
||||||
|
open={ openDeleteModal }
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
@ -168,3 +243,4 @@ export default class Settings extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, actions)(Settings);
|
||||||
|
@ -45,7 +45,7 @@ export default function SocialSettings({
|
|||||||
href='/link/linkedin'
|
href='/link/linkedin'
|
||||||
key='linkedin'
|
key='linkedin'
|
||||||
>
|
>
|
||||||
<FA name='linked' />
|
<FA name='linkedin' />
|
||||||
Add my LinkedIn to my portfolio
|
Add my LinkedIn to my portfolio
|
||||||
</Button>
|
</Button>
|
||||||
));
|
));
|
||||||
|
30
common/app/routes/settings/redux/actions.js
Normal file
30
common/app/routes/settings/redux/actions.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
|
|
||||||
|
import createTypes from '../../../utils/create-types';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
showDeleteModal: false
|
||||||
|
};
|
||||||
|
export const types = createTypes([
|
||||||
|
'toggleUserFlag',
|
||||||
|
'openDeleteModal',
|
||||||
|
'hideDeleteModal'
|
||||||
|
], 'settings');
|
||||||
|
|
||||||
|
export const toggleUserFlag = createAction(types.toggleUserFlag);
|
||||||
|
export const openDeleteModal = createAction(types.openDeleteModal);
|
||||||
|
export const hideDeleteModal = createAction(types.hideDeleteModal);
|
||||||
|
|
||||||
|
export default handleActions(
|
||||||
|
{
|
||||||
|
[openDeleteModal]: state => ({
|
||||||
|
...state,
|
||||||
|
isDeleteOpen: true
|
||||||
|
}),
|
||||||
|
[hideDeleteModal]: state => ({
|
||||||
|
...state,
|
||||||
|
isDeleteOpen: false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initialState
|
||||||
|
);
|
9
common/app/routes/settings/redux/index.js
Normal file
9
common/app/routes/settings/redux/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import userUpdateSaga from './update-user-saga';
|
||||||
|
|
||||||
|
export { types } from './actions';
|
||||||
|
export * as actions from './actions';
|
||||||
|
export { default as reducer } from './actions';
|
||||||
|
|
||||||
|
export const sagas = [
|
||||||
|
userUpdateSaga
|
||||||
|
];
|
40
common/app/routes/settings/redux/update-user-saga.js
Normal file
40
common/app/routes/settings/redux/update-user-saga.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Observable } from 'rx';
|
||||||
|
import { types } from './actions';
|
||||||
|
import { postJSON$ } from '../../../../utils/ajax-stream';
|
||||||
|
import { updateUserFlag, createErrorObservable } from '../../../redux/actions';
|
||||||
|
|
||||||
|
const urlMap = {
|
||||||
|
isLocked: 'lockdown',
|
||||||
|
sendQuincyEmail: 'quincy-email',
|
||||||
|
sendNotificationEmail: 'notification-email',
|
||||||
|
sendMonthlyEmail: 'announcement-email'
|
||||||
|
};
|
||||||
|
export default function userUpdateSaga(actions$, getState) {
|
||||||
|
const toggleFlag$ = actions$
|
||||||
|
.filter(({ type, payload }) => type === types.toggleUserFlag && payload)
|
||||||
|
.map(({ payload }) => payload);
|
||||||
|
const optimistic$ = toggleFlag$.map(flag => {
|
||||||
|
const { app: { user: username } } = getState();
|
||||||
|
return updateUserFlag(username, flag);
|
||||||
|
});
|
||||||
|
const serverUpdate$ = toggleFlag$
|
||||||
|
.debounce(500)
|
||||||
|
.flatMap(flag => {
|
||||||
|
const url = `/toggle-${urlMap[ flag ]}`;
|
||||||
|
const {
|
||||||
|
app: { user: username, csrfToken: _csrf },
|
||||||
|
entities: { user: userMap }
|
||||||
|
} = getState();
|
||||||
|
const user = userMap[username];
|
||||||
|
const currentValue = user[ flag ];
|
||||||
|
return postJSON$(url, { _csrf })
|
||||||
|
.map(({ flag, value }) => {
|
||||||
|
if (currentValue === value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return updateUserFlag(username, flag);
|
||||||
|
})
|
||||||
|
.catch(createErrorObservable);
|
||||||
|
});
|
||||||
|
return Observable.merge(optimistic$, serverUpdate$);
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
import { sagas as appSagas } from './redux';
|
import { sagas as appSagas } from './redux';
|
||||||
import { sagas as challengeSagas } from './routes/challenges/redux';
|
import { sagas as challengeSagas } from './routes/challenges/redux';
|
||||||
|
import { sagas as settingsSagas } from './routes/settings/redux';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
...appSagas,
|
...appSagas,
|
||||||
...challengeSagas
|
...challengeSagas,
|
||||||
|
...settingsSagas
|
||||||
];
|
];
|
||||||
|
38
server/boot/settings.js
Normal file
38
server/boot/settings.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { ifNoUser401 } from '../utils/middleware';
|
||||||
|
|
||||||
|
export default function settingsController(app) {
|
||||||
|
const api = app.loopback.Router();
|
||||||
|
const toggleUserFlag = flag => (req, res, next) => {
|
||||||
|
const { user } = req;
|
||||||
|
const currentValue = user[ flag ];
|
||||||
|
return user
|
||||||
|
.update$({ [ flag ]: !currentValue })
|
||||||
|
.subscribe(
|
||||||
|
() => res.status(200).json({
|
||||||
|
flag,
|
||||||
|
value: !currentValue
|
||||||
|
}),
|
||||||
|
next
|
||||||
|
);
|
||||||
|
};
|
||||||
|
api.post(
|
||||||
|
'/toggle-lockdown',
|
||||||
|
toggleUserFlag('isLocked')
|
||||||
|
);
|
||||||
|
api.post(
|
||||||
|
'/toggle-announcement-email',
|
||||||
|
ifNoUser401,
|
||||||
|
toggleUserFlag('sendMonthlyEmail')
|
||||||
|
);
|
||||||
|
api.post(
|
||||||
|
'/toggle-notification-email',
|
||||||
|
ifNoUser401,
|
||||||
|
toggleUserFlag('sendNotificationEmail')
|
||||||
|
);
|
||||||
|
api.post(
|
||||||
|
'/toggle-quincy-email',
|
||||||
|
ifNoUser401,
|
||||||
|
toggleUserFlag('sendQuincyEmail')
|
||||||
|
);
|
||||||
|
app.use(api);
|
||||||
|
}
|
@ -155,26 +155,6 @@ module.exports = function(app) {
|
|||||||
router.get('/email-signin', getEmailSignin);
|
router.get('/email-signin', getEmailSignin);
|
||||||
router.get('/deprecated-signin', getDepSignin);
|
router.get('/deprecated-signin', getDepSignin);
|
||||||
router.get('/update-email', getUpdateEmail);
|
router.get('/update-email', getUpdateEmail);
|
||||||
api.get(
|
|
||||||
'/toggle-lockdown-mode',
|
|
||||||
sendNonUserToMap,
|
|
||||||
toggleLockdownMode
|
|
||||||
);
|
|
||||||
api.get(
|
|
||||||
'/toggle-announcement-email-mode',
|
|
||||||
sendNonUserToMap,
|
|
||||||
toggleReceivesAnnouncementEmails
|
|
||||||
);
|
|
||||||
api.get(
|
|
||||||
'/toggle-notification-email-mode',
|
|
||||||
sendNonUserToMap,
|
|
||||||
toggleReceivesNotificationEmails
|
|
||||||
);
|
|
||||||
api.get(
|
|
||||||
'/toggle-quincy-email-mode',
|
|
||||||
sendNonUserToMap,
|
|
||||||
toggleReceivesQuincyEmails
|
|
||||||
);
|
|
||||||
api.post(
|
api.post(
|
||||||
'/account/delete',
|
'/account/delete',
|
||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
@ -434,62 +414,6 @@ module.exports = function(app) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleLockdownMode(req, res, next) {
|
|
||||||
const { user } = req;
|
|
||||||
user.update$({ isLocked: !user.isLocked })
|
|
||||||
.subscribe(
|
|
||||||
() => {
|
|
||||||
req.flash('info', {
|
|
||||||
msg: 'We\'ve successfully updated your Privacy preferences.'
|
|
||||||
});
|
|
||||||
return res.redirect('/settings');
|
|
||||||
},
|
|
||||||
next
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleReceivesAnnouncementEmails(req, res, next) {
|
|
||||||
const { user } = req;
|
|
||||||
return user.update$({ sendMonthlyEmail: !user.sendMonthlyEmail })
|
|
||||||
.subscribe(
|
|
||||||
() => {
|
|
||||||
req.flash('info', {
|
|
||||||
msg: 'We\'ve successfully updated your Email preferences.'
|
|
||||||
});
|
|
||||||
return res.redirect('/settings');
|
|
||||||
},
|
|
||||||
next
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleReceivesQuincyEmails(req, res, next) {
|
|
||||||
const { user } = req;
|
|
||||||
return user.update$({ sendQuincyEmail: !user.sendQuincyEmail })
|
|
||||||
.subscribe(
|
|
||||||
() => {
|
|
||||||
req.flash('info', {
|
|
||||||
msg: 'We\'ve successfully updated your Email preferences.'
|
|
||||||
});
|
|
||||||
return res.redirect('/settings');
|
|
||||||
},
|
|
||||||
next
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleReceivesNotificationEmails(req, res, next) {
|
|
||||||
const { user } = req;
|
|
||||||
return user.update$({ sendNotificationEmail: !user.sendNotificationEmail })
|
|
||||||
.subscribe(
|
|
||||||
() => {
|
|
||||||
req.flash('info', {
|
|
||||||
msg: 'We\'ve successfully updated your Email preferences.'
|
|
||||||
});
|
|
||||||
return res.redirect('/settings');
|
|
||||||
},
|
|
||||||
next
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function postDeleteAccount(req, res, next) {
|
function postDeleteAccount(req, res, next) {
|
||||||
User.destroyById(req.user.id, function(err) {
|
User.destroyById(req.user.id, function(err) {
|
||||||
if (err) { return next(err); }
|
if (err) { return next(err); }
|
||||||
|
@ -9,17 +9,23 @@ const publicUserProps = [
|
|||||||
'theme',
|
'theme',
|
||||||
'picture',
|
'picture',
|
||||||
'points',
|
'points',
|
||||||
|
'email',
|
||||||
'languageTag',
|
'languageTag',
|
||||||
|
|
||||||
'isCheater',
|
'isCheater',
|
||||||
'isGithubCool',
|
'isGithubCool',
|
||||||
|
|
||||||
|
'isLocked',
|
||||||
'isFrontEndCert',
|
'isFrontEndCert',
|
||||||
'isBackEndCert',
|
'isBackEndCert',
|
||||||
'isDataVisCert',
|
'isDataVisCert',
|
||||||
'isFullStackCert',
|
'isFullStackCert',
|
||||||
|
|
||||||
'githubURL',
|
'githubURL',
|
||||||
|
'sendMonthlyEmail',
|
||||||
|
'sendNotificationEmail',
|
||||||
|
'sendQuincyEmail',
|
||||||
|
|
||||||
'currentChallenge',
|
'currentChallenge',
|
||||||
'challengeMap'
|
'challengeMap'
|
||||||
];
|
];
|
||||||
@ -40,7 +46,11 @@ export default function userServices() {
|
|||||||
{
|
{
|
||||||
entities: {
|
entities: {
|
||||||
user: {
|
user: {
|
||||||
[user.username]: _.pick(user, publicUserProps)
|
[user.username]: {
|
||||||
|
..._.pick(user, publicUserProps),
|
||||||
|
isTwitter: !!user.twitter,
|
||||||
|
isLinkedIn: !!user.linkedIn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
result: user.username
|
result: user.username
|
||||||
|
Reference in New Issue
Block a user