Break out utils functions and move preferences api calls to profileapiservice

This commit is contained in:
Adam Butterworth
2019-02-21 11:55:00 -05:00
committed by Adam Butterworth
parent 64c8a78c65
commit a3b7999627
5 changed files with 121 additions and 81 deletions

View File

@@ -1,9 +1,7 @@
import _ from 'lodash';
import { getAuthenticatedAPIClient } from '@edx/frontend-auth';
import { configuration } from '../config';
const lmsBaseUrl = process.env.LMS_BASE_URL;
const apiClient = getAuthenticatedAPIClient({
appBaseUrl: configuration.BASE_URL,
@@ -16,78 +14,5 @@ const apiClient = getAuthenticatedAPIClient({
csrfCookieName: configuration.CSRF_COOKIE_NAME,
});
const clientServerKeyMap = {
bio: 'bio',
socialLinks: 'social_links',
country: 'country',
education: 'level_of_education',
fullName: 'name',
username: 'username',
profileImage: 'profile_image',
dateJoined: 'date_joined',
languageProficiencies: 'language_proficiencies',
accountPrivacy: 'account_privacy',
};
const serverClientKeyMap = _.invert(clientServerKeyMap);
export function getPreferences(username) {
const url = `${lmsBaseUrl}/api/user/v1/preferences/${username}`;
return new Promise((resolve, reject) => {
apiClient.get(url)
.then(({ data }) => {
// Unflatten server response
// visibility.social_links: 'value' becomes { visibility: { socialLinks: 'value' }}
const preferences = {};
Object.entries(data).forEach(([key, value]) => {
_.set(
preferences,
key.split('.').map(pathKey => serverClientKeyMap[pathKey] || pathKey),
value,
);
});
resolve(preferences);
})
.catch((error) => {
reject(error);
});
});
}
export function savePreferences(username, preferences) {
const url = `${lmsBaseUrl}/api/user/v1/preferences/${username}`;
// Flatten object for server
// { visibility: { socialLinks: 'value' }} becomes visibility.social_links: 'value'
const data = {};
const flattenAndTransformKeys = (prevKeys, currentValue) => {
if (typeof currentValue !== 'object') {
const serverKey = prevKeys.map(key => serverClientKeyMap[key] || key).join('.');
data[serverKey] = currentValue;
return;
}
Object.keys(currentValue).forEach((key) => {
flattenAndTransformKeys(prevKeys.concat(key), currentValue[key]);
});
};
flattenAndTransformKeys([], preferences);
return new Promise((resolve, reject) => {
apiClient.patch(
url,
data,
{ headers: { 'Content-Type': 'application/merge-patch+json' } },
)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
}
export default apiClient;

View File

@@ -39,7 +39,6 @@ import {
} from '../actions/preferences';
import * as ProfileApiService from '../services/ProfileApiService';
import { getPreferences, savePreferences } from '../data/apiClient';
const PROP_TO_STATE_MAP = {
@@ -139,7 +138,7 @@ export function* handleFetchPreferences(action) {
const { username } = action.payload;
try {
yield put(fetchPreferencesBegin());
const userPreferences = yield call(getPreferences, username);
const userPreferences = yield call(ProfileApiService.getPreferences, username);
yield put(fetchPreferencesSuccess(userPreferences));
yield put(fetchPreferencesReset());
} catch (e) {
@@ -151,7 +150,7 @@ export function* handleSavePreferences(action) {
const { username, preferences } = action.payload;
try {
yield put(savePreferencesBegin());
yield call(savePreferences, username, preferences);
yield call(ProfileApiService.savePreferences, username, preferences);
yield put(savePreferencesSuccess(preferences));
yield put(savePreferencesReset());
} catch (e) {

View File

@@ -1,11 +1,27 @@
import camelcaseKeys from 'camelcase-keys';
import snakecaseKeys from 'snakecase-keys';
import _ from 'lodash';
import apiClient from '../data/apiClient';
import { configuration } from '../config';
import { unflattenAndTransformKeys, flattenAndTransformKeys } from './utils';
const accountsApiBaseUrl = `${configuration.LMS_BASE_URL}/api/user/v1/accounts`;
const preferencesApiBaseUrl = `${configuration.LMS_BASE_URL}/api/user/v1/preferences`;
const clientServerKeyMap = {
bio: 'bio',
socialLinks: 'social_links',
country: 'country',
education: 'level_of_education',
fullName: 'name',
username: 'username',
profileImage: 'profile_image',
dateJoined: 'date_joined',
languageProficiencies: 'language_proficiencies',
accountPrivacy: 'account_privacy',
};
const serverClientKeyMap = _.invert(clientServerKeyMap);
export function getProfile(username) {
return new Promise((resolve, reject) => {
@@ -72,9 +88,35 @@ export function deleteProfilePhoto(username) {
return apiClient.delete(`${accountsApiBaseUrl}/${username}/image`);
}
export function getUserPreference(username, preferenceKey) {
export function getPreferences(username) {
const url = `${preferencesApiBaseUrl}/${username}`;
return new Promise((resolve, reject) => {
apiClient.get(`${preferencesApiBaseUrl}/${username}/${preferenceKey}`)
apiClient.get(url)
.then(({ data }) => {
// Unflatten server response
// visibility.social_links: 'value' becomes { visibility: { socialLinks: 'value' }}
resolve(unflattenAndTransformKeys(data, key => serverClientKeyMap[key] || key));
})
.catch((error) => {
reject(error);
});
});
}
export function savePreferences(username, preferences) {
const url = `${preferencesApiBaseUrl}/${username}`;
// Flatten object for server
// { visibility: { socialLinks: 'value' }} becomes visibility.social_links: 'value'
const data = flattenAndTransformKeys(preferences, key => clientServerKeyMap[key] || key);
return new Promise((resolve, reject) => {
apiClient.patch(
url,
data,
{ headers: { 'Content-Type': 'application/merge-patch+json' } },
)
.then((response) => {
resolve(response.data);
})
@@ -83,4 +125,3 @@ export function getUserPreference(username, preferenceKey) {
});
});
}

28
src/services/utils.js Normal file
View File

@@ -0,0 +1,28 @@
import _ from 'lodash';
export function unflattenAndTransformKeys(obj, transformer) {
const newObj = {};
Object.entries(obj).forEach(([key, value]) => {
_.set(newObj, key.split('.').map(transformer), value);
});
return newObj;
}
export function flattenAndTransformKeys(srcObj, transformer = key => key) {
const flatten = (obj, prevKeys = []) => (Object.entries(obj).reduce((acc, [key, value]) => {
const tKey = transformer(key);
const keys = prevKeys.concat(tKey);
if (value && typeof value === 'object') {
Object.assign(acc, flatten(value, keys));
} else {
acc[keys.join('.')] = value;
}
return acc;
}, {}));
return flatten(srcObj);
}

View File

@@ -0,0 +1,47 @@
import { flattenAndTransformKeys, unflattenAndTransformKeys } from './utils';
describe('unflattenAndTransformKeys', () => {
it('should unflatten objects and transform keys', () => {
const sourceObject = {
userlocation: 'US',
'visibility.sociallinks': 'private',
'visibility.education': 'private',
'visibility.bio': 'private',
};
const result = unflattenAndTransformKeys(sourceObject, key => key.toUpperCase());
expect(result).toEqual({
USERLOCATION: 'US',
VISIBILITY: {
SOCIALLINKS: 'private',
EDUCATION: 'private',
BIO: 'private',
},
});
});
});
describe('flattenAndTransformKeys', () => {
it('should flatten objects and transform keys', () => {
const sourceObject = {
USERLOCATION: 'US',
VISIBILITY: {
SOCIALLINKS: 'private',
EDUCATION: 'private',
BIO: 'private',
},
};
const result = flattenAndTransformKeys(sourceObject, key => key.toLowerCase());
expect(result).toEqual({
userlocation: 'US',
'visibility.sociallinks': 'private',
'visibility.education': 'private',
'visibility.bio': 'private',
});
});
});