Make certain field uneditable for enterprise learners. (#23)
Make certain field uneditable for enterprise learners.
This commit is contained in:
47
package-lock.json
generated
47
package-lock.json
generated
@@ -1026,9 +1026,9 @@
|
||||
}
|
||||
},
|
||||
"@edx/frontend-auth": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-auth/-/frontend-auth-5.2.0.tgz",
|
||||
"integrity": "sha512-/S5IMEIQXXUzXEQThZczWh4jRCyTvMB/oWFjMTbYr0WseyRhH2DWpy2X6WRgWObwnyiFRvYLzktIpcGoHLFA9A==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-auth/-/frontend-auth-5.3.0.tgz",
|
||||
"integrity": "sha512-HiuwVlgePsBgQYlw47Z/lEKcmFrRbwYactOHMPXUgxaHKPXZwdVDvqBbf21/J/wPX0t1Kzmn0U5qfMd838hvYg==",
|
||||
"requires": {
|
||||
"@edx/frontend-logging": "^2.0.1",
|
||||
"axios": "^0.18.0",
|
||||
@@ -8582,7 +8582,8 @@
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -8603,12 +8604,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -8623,17 +8626,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -8750,7 +8756,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -8762,6 +8769,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -8776,6 +8784,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -8783,12 +8792,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -8807,6 +8818,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -8887,7 +8899,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -8899,6 +8912,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -8984,7 +8998,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -9020,6 +9035,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -9039,6 +9055,7 @@
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -9082,12 +9099,14 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"@cospired/i18n-iso-languages": "^2.0.2",
|
||||
"@edx/edx-bootstrap": "^2.1.0",
|
||||
"@edx/frontend-analytics": "^1.0.0",
|
||||
"@edx/frontend-auth": "^5.2.0",
|
||||
"@edx/frontend-auth": "^5.3.0",
|
||||
"@edx/frontend-component-footer": "^2.0.3",
|
||||
"@edx/frontend-component-site-header": "^2.1.4",
|
||||
"@edx/frontend-logging": "^2.0.0",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Hyperlink } from '@edx/paragon';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import {
|
||||
injectIntl,
|
||||
intlShape,
|
||||
@@ -8,10 +10,12 @@ import {
|
||||
|
||||
import messages from './AccountSettingsPage.messages';
|
||||
|
||||
import { configuration } from '../environment';
|
||||
import { fetchSettings, saveSettings, updateDraft } from './actions';
|
||||
import { accountSettingsPageSelector } from './selectors';
|
||||
|
||||
import { PageLoading } from '../common';
|
||||
import Alert from './components/Alert';
|
||||
import EditableField from './components/EditableField';
|
||||
import PasswordReset from './components/PasswordReset';
|
||||
import ThirdPartyAuth from './components/ThirdPartyAuth';
|
||||
@@ -58,6 +62,36 @@ class AccountSettingsPage extends React.Component {
|
||||
this.props.saveSettings(formId, values);
|
||||
}
|
||||
|
||||
renderManagedProfileMessage() {
|
||||
if (!this.props.profileDataManager) {
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Alert className="alert alert-primary" role="alert">
|
||||
<FormattedMessage
|
||||
id="account.settings.message.managed.settings"
|
||||
defaultMessage="Your profile settings are managed by {managerTitle}. Contact your administrator or {support} for help."
|
||||
description="alert message informing the user their account data is managed by a third party"
|
||||
values={{
|
||||
managerTitle: <b>{this.props.profileDataManager}</b>,
|
||||
support: (
|
||||
<Hyperlink href={configuration.SUPPORT_URL} target="_blank">
|
||||
<FormattedMessage
|
||||
id="account.settings.message.managed.settings.support"
|
||||
defaultMessage="support"
|
||||
description="website support"
|
||||
/>
|
||||
</Hyperlink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const editableFieldProps = {
|
||||
onChange: this.handleEditableFieldChange,
|
||||
@@ -72,6 +106,7 @@ class AccountSettingsPage extends React.Component {
|
||||
|
||||
<h2 className="h4">{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}</h2>
|
||||
<p>{this.props.intl.formatMessage(messages['account.settings.section.account.information.description'])}</p>
|
||||
{this.renderManagedProfileMessage()}
|
||||
|
||||
<EditableField
|
||||
name="username"
|
||||
@@ -88,6 +123,7 @@ class AccountSettingsPage extends React.Component {
|
||||
value={this.props.formValues.name}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.full.name'])}
|
||||
helpText={this.props.intl.formatMessage(messages['account.settings.field.full.name.help.text'])}
|
||||
isEditable={!this.props.staticFields.includes('name')}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EmailField
|
||||
@@ -96,6 +132,7 @@ class AccountSettingsPage extends React.Component {
|
||||
value={this.props.formValues.email}
|
||||
confirmationMessageDefinition={messages['account.settings.field.email.confirmation']}
|
||||
helpText={this.props.intl.formatMessage(messages['account.settings.field.email.help.text'])}
|
||||
isEditable={!this.props.staticFields.includes('email')}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<PasswordReset />
|
||||
@@ -113,6 +150,7 @@ class AccountSettingsPage extends React.Component {
|
||||
value={this.props.formValues.country}
|
||||
options={this.props.countryOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.country'])}
|
||||
isEditable={!this.props.staticFields.includes('country')}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
|
||||
@@ -277,6 +315,8 @@ AccountSettingsPage.propTypes = {
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
})),
|
||||
profileDataManager: PropTypes.string,
|
||||
staticFields: PropTypes.arrayOf(PropTypes.string),
|
||||
|
||||
fetchSiteLanguages: PropTypes.func.isRequired,
|
||||
updateDraft: PropTypes.func.isRequired,
|
||||
@@ -292,6 +332,8 @@ AccountSettingsPage.defaultProps = {
|
||||
siteLanguageOptions: [],
|
||||
countryOptions: [],
|
||||
languageProficiencyOptions: [],
|
||||
profileDataManager: null,
|
||||
staticFields: [],
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ export const fetchSettingsBegin = () => ({
|
||||
type: FETCH_SETTINGS.BEGIN,
|
||||
});
|
||||
|
||||
export const fetchSettingsSuccess = ({ values, thirdPartyAuthProviders }) => ({
|
||||
export const fetchSettingsSuccess = ({ values, thirdPartyAuthProviders, profileDataManager }) => ({
|
||||
type: FETCH_SETTINGS.SUCCESS,
|
||||
payload: { values, thirdPartyAuthProviders },
|
||||
payload: { values, thirdPartyAuthProviders, profileDataManager },
|
||||
});
|
||||
|
||||
export const fetchSettingsFailure = error => ({
|
||||
|
||||
@@ -37,6 +37,7 @@ const accountSettingsReducer = (state = defaultState, action) => {
|
||||
...state,
|
||||
values: Object.assign({}, state.values, action.payload.values),
|
||||
authProviders: action.payload.thirdPartyAuthProviders,
|
||||
profileDataManager: action.payload.profileDataManager,
|
||||
loading: false,
|
||||
loaded: true,
|
||||
loadingError: null,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
resetPasswordBegin,
|
||||
resetPasswordSuccess,
|
||||
} from './actions';
|
||||
import { usernameSelector } from './selectors';
|
||||
import { usernameSelector, userRolesSelector } from './selectors';
|
||||
|
||||
// Services
|
||||
import * as ApiService from './service';
|
||||
@@ -29,10 +29,15 @@ export function* handleFetchSettings() {
|
||||
try {
|
||||
yield put(fetchSettingsBegin());
|
||||
const username = yield select(usernameSelector);
|
||||
const userRoles = yield select(userRolesSelector);
|
||||
|
||||
const { thirdPartyAuthProviders, ...values } = yield call(ApiService.getSettings, username);
|
||||
const {
|
||||
thirdPartyAuthProviders,
|
||||
profileDataManager,
|
||||
...values
|
||||
} = yield call(ApiService.getSettings, username, userRoles);
|
||||
|
||||
yield put(fetchSettingsSuccess({ values, thirdPartyAuthProviders }));
|
||||
yield put(fetchSettingsSuccess({ values, thirdPartyAuthProviders, profileDataManager }));
|
||||
} catch (e) {
|
||||
logAPIErrorResponse(e);
|
||||
yield put(fetchSettingsFailure(e.message));
|
||||
|
||||
@@ -12,6 +12,8 @@ export const storeName = 'accountSettings';
|
||||
|
||||
export const usernameSelector = state => state.authentication.username;
|
||||
|
||||
export const userRolesSelector = state => state.authentication.roles || [];
|
||||
|
||||
export const accountSettingsSelector = state => ({ ...state[storeName] });
|
||||
|
||||
const editableFieldNameSelector = (state, props) => props.name;
|
||||
@@ -74,6 +76,16 @@ export const thirdPartyAuthSelector = createSelector(
|
||||
}),
|
||||
);
|
||||
|
||||
export const profileDataManagerSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
accountSettings => accountSettings.profileDataManager,
|
||||
);
|
||||
|
||||
export const staticFieldsSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
accountSettings => (accountSettings.profileDataManager ? ['name', 'email', 'country'] : []),
|
||||
);
|
||||
|
||||
/**
|
||||
* If there's no draft present at all (undefined), use the original committed value.
|
||||
*/
|
||||
@@ -123,6 +135,8 @@ export const accountSettingsPageSelector = createSelector(
|
||||
languageProficiencyOptionsSelector,
|
||||
formValuesSelector,
|
||||
siteLanguageSelector,
|
||||
profileDataManagerSelector,
|
||||
staticFieldsSelector,
|
||||
(
|
||||
accountSettings,
|
||||
siteLanguageOptions,
|
||||
@@ -130,6 +144,8 @@ export const accountSettingsPageSelector = createSelector(
|
||||
languageProficiencyOptions,
|
||||
formValues,
|
||||
siteLanguage,
|
||||
profileDataManager,
|
||||
staticFields,
|
||||
) => ({
|
||||
siteLanguageOptions,
|
||||
countryOptions,
|
||||
@@ -139,5 +155,7 @@ export const accountSettingsPageSelector = createSelector(
|
||||
loaded: accountSettings.loaded,
|
||||
loadingError: accountSettings.loadingError,
|
||||
formValues,
|
||||
profileDataManager,
|
||||
staticFields,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -128,21 +128,46 @@ export async function getThirdPartyAuthProviders() {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user's profile data is managed by a third-party identity provider.
|
||||
*/
|
||||
export async function getProfileDataManager(username, userRoles) {
|
||||
const userRoleNames = userRoles.map(role => role.split(':')[0]);
|
||||
|
||||
if (userRoleNames.includes('enterprise_learner')) {
|
||||
const url = `${config.LMS_BASE_URL}/enterprise/api/v1/enterprise-learner/?username=${username}`;
|
||||
const { data } = await apiClient.get(url).catch(handleRequestError);
|
||||
|
||||
if ('results' in data) {
|
||||
for (let i = 0; i < data.results.length; i += 1) {
|
||||
const enterprise = data.results[i].enterprise_customer;
|
||||
if (enterprise.sync_learner_profile_data) {
|
||||
return enterprise.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single function to GET everything considered a setting.
|
||||
* Currently encapsulates Account, Preferences, and ThirdPartyAuth
|
||||
*/
|
||||
export async function getSettings(username) {
|
||||
export async function getSettings(username, userRoles) {
|
||||
const results = await Promise.all([
|
||||
getAccount(username),
|
||||
getPreferences(username),
|
||||
getThirdPartyAuthProviders(),
|
||||
getProfileDataManager(username, userRoles),
|
||||
]);
|
||||
|
||||
return {
|
||||
...results[0],
|
||||
...results[1],
|
||||
thirdPartyAuthProviders: results[2],
|
||||
profileDataManager: results[3],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user