diff --git a/package-lock.json b/package-lock.json
index 0062fb4..ad8f4ff 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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
}
}
},
diff --git a/package.json b/package.json
index e1948a3..e3510fa 100755
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/account-settings/AccountSettingsPage.jsx b/src/account-settings/AccountSettingsPage.jsx
index fd0ed70..1a0f46e 100644
--- a/src/account-settings/AccountSettingsPage.jsx
+++ b/src/account-settings/AccountSettingsPage.jsx
@@ -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 (
+
+
+ {this.props.profileDataManager},
+ support: (
+
+
+
+ ),
+ }}
+ />
+
+
+ );
+ }
+
renderContent() {
const editableFieldProps = {
onChange: this.handleEditableFieldChange,
@@ -72,6 +106,7 @@ class AccountSettingsPage extends React.Component {
{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}
{this.props.intl.formatMessage(messages['account.settings.section.account.information.description'])}
+ {this.renderManagedProfileMessage()}
@@ -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: [],
};
diff --git a/src/account-settings/actions.js b/src/account-settings/actions.js
index 4fa8c82..b8d3193 100644
--- a/src/account-settings/actions.js
+++ b/src/account-settings/actions.js
@@ -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 => ({
diff --git a/src/account-settings/reducers.js b/src/account-settings/reducers.js
index 90964de..cb726e1 100644
--- a/src/account-settings/reducers.js
+++ b/src/account-settings/reducers.js
@@ -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,
diff --git a/src/account-settings/sagas.js b/src/account-settings/sagas.js
index ee35bdf..c660975 100644
--- a/src/account-settings/sagas.js
+++ b/src/account-settings/sagas.js
@@ -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));
diff --git a/src/account-settings/selectors.js b/src/account-settings/selectors.js
index 3f28ec1..5a3f34a 100644
--- a/src/account-settings/selectors.js
+++ b/src/account-settings/selectors.js
@@ -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,
}),
);
diff --git a/src/account-settings/service.js b/src/account-settings/service.js
index 5a437e3..2d75873 100644
--- a/src/account-settings/service.js
+++ b/src/account-settings/service.js
@@ -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],
};
}