diff --git a/app/jsx/course_settings/actions.jsx b/app/jsx/course_settings/actions.jsx
index e2105d6b9c4..f1987c9e818 100644
--- a/app/jsx/course_settings/actions.jsx
+++ b/app/jsx/course_settings/actions.jsx
@@ -76,9 +76,37 @@ define ([
};
},
- prepareSetImage (imageUrl, imageId, ajaxLib = axios) {
+ putImageData(courseId, imageUrl, imageId = null, ajaxLib = axios) {
+ const data = imageId ? {"course[image_id]": imageId} :
+ {"course[image_url]": imageUrl};
+
+ return (dispatch, getState) => {
+ this.ajaxPutFormData(`/api/v1/courses/${courseId}`, data, ajaxLib)
+ .then((response)=> {
+ dispatch(imageId ? this.setCourseImageId(imageUrl, imageId) :
+ this.setCourseImageUrl(imageUrl));
+ })
+ .catch((response) => {
+ this.errorUploadingImage();
+ })
+ }
+ },
+
+ putRemoveImage(courseId, ajaxLib = axios) {
+ return (dispatch, getState) => {
+ this.ajaxPutFormData(`/api/v1/courses/${courseId}`, {"course[remove_image]": true}, ajaxLib)
+ .then((response)=> {
+ dispatch(this.removeImage());
+ })
+ .catch((response) => {
+ $.flashError(I18n.t("Error removing image"));
+ })
+ }
+ },
+
+ prepareSetImage (imageUrl, imageId, courseId, ajaxLib = axios) {
if (imageUrl) {
- return this.setCourseImageId(imageUrl, imageId);
+ return this.putImageData(courseId, imageUrl, imageId, ajaxLib);
} else {
// In this case the url field was blank so we could either
// recreate it or hit the API to get it. We hit the api
@@ -86,7 +114,7 @@ define ([
return (dispatch, getState) => {
ajaxLib.get(`/api/v1/files/${imageId}`)
.then((response) => {
- dispatch(this.setCourseImageId(response.data.url, imageId));
+ dispatch(this.putImageData(courseId, response.data.url, imageId, ajaxLib));
})
.catch((response) => {
this.errorUploadingImage();
@@ -119,7 +147,7 @@ define ([
formData.append('file', file);
ajaxLib.post(response.data.upload_url, formData)
.then((response) => {
- dispatch(this.prepareSetImage(response.data.url, response.data.id));
+ dispatch(this.prepareSetImage(response.data.url, response.data.id, courseId, ajaxLib));
})
.catch((response) => {
this.errorUploadingImage();
@@ -133,6 +161,22 @@ define ([
$.flashWarning(I18n.t("'%{type}' is not a valid image type (try jpg, png, or gif)", {type}));
}
};
+ },
+
+ ajaxPutFormData(path, data, ajaxLib = axios) {
+ return (
+ ajaxLib.put(path, data,
+ {
+ // TODO: this is a naive implementation,
+ // upgrading to axios@0.12.0 will make it unnecessary
+ // by using URLSearchParams.
+ transformRequest: function (data, headers) {
+ return Object.keys(data).reduce((prev, key) => {
+ return prev + (prev ? '&' : '') + `${key}=${data[key]}`;
+ }, '');
+ }
+ })
+ );
}
};
diff --git a/app/jsx/course_settings/components/CourseImageSelector.jsx b/app/jsx/course_settings/components/CourseImageSelector.jsx
index 9e3e9542764..49f3d5704e4 100644
--- a/app/jsx/course_settings/components/CourseImageSelector.jsx
+++ b/app/jsx/course_settings/components/CourseImageSelector.jsx
@@ -52,7 +52,7 @@ define([
}
removeImage() {
- this.props.store.dispatch(Actions.removeImage());
+ this.props.store.dispatch(Actions.putRemoveImage(this.props.courseId));
}
imageControls () {
@@ -130,16 +130,8 @@ define([
backgroundImage: `url(${this.state.imageUrl})`
};
- var value = this.state.removeImage ? true : this.state.courseImage;
-
return (
-
this.props.store.dispatch(Actions.uploadFile(e, courseId))}
- handleFlickrUrlUpload={(flickrUrl) => this.props.store.dispatch(Actions.setCourseImageUrl(flickrUrl))}
+ handleFlickrUrlUpload={(flickrUrl) => this.props.store.dispatch(Actions.putImageData(this.props.courseId, flickrUrl))}
/>
diff --git a/app/jsx/course_settings/reducer.jsx b/app/jsx/course_settings/reducer.jsx
index 84b5c222f60..5702655ba6b 100644
--- a/app/jsx/course_settings/reducer.jsx
+++ b/app/jsx/course_settings/reducer.jsx
@@ -19,23 +19,17 @@ define([
state.imageUrl = action.payload.imageUrl;
state.courseImage = action.payload.imageId;
state.showModal = false;
- state.removeImage = false;
- state.hiddenInputName = "course[image_id]"
return state;
},
SET_COURSE_IMAGE_URL (state, action) {
state.imageUrl = action.payload.imageUrl;
state.courseImage = action.payload.imageUrl;
state.showModal = false;
- state.removeImage = false;
- state.hiddenInputName = "course[image_url]";
return state;
},
REMOVE_IMAGE (state) {
state.imageUrl = '';
state.courseImage = 'abc';
- state.removeImage = true;
- state.hiddenInputName = "course[remove_image]";
return state;
}
};
diff --git a/app/jsx/course_settings/store/initialState.jsx b/app/jsx/course_settings/store/initialState.jsx
index a4d3a850296..40f4d3b767d 100644
--- a/app/jsx/course_settings/store/initialState.jsx
+++ b/app/jsx/course_settings/store/initialState.jsx
@@ -5,8 +5,6 @@ define([], () => {
imageUrl: '',
showModal: false,
gettingImage: false,
- removeImage: false,
- hiddenInputName: ''
};
return initialState;
diff --git a/spec/javascripts/jsx/course_settings/actionsSpec.jsx b/spec/javascripts/jsx/course_settings/actionsSpec.jsx
index 0f44ebea0e9..7ba645e03ff 100644
--- a/spec/javascripts/jsx/course_settings/actionsSpec.jsx
+++ b/spec/javascripts/jsx/course_settings/actionsSpec.jsx
@@ -77,10 +77,11 @@ define([
deepEqual(actual, expected, 'the objects match');
});
- test('prepareSetImage with a imageUrl calls setCourseImageId', () => {
- sinon.spy(Actions, 'setCourseImageId');
- Actions.prepareSetImage('http://imageUrl', 12);
- ok(Actions.setCourseImageId.called, 'setCourseImageId was called');
+ test('prepareSetImage with a imageUrl calls putImageData', () => {
+ sinon.spy(Actions, 'putImageData');
+ Actions.prepareSetImage('http://imageUrl', 12, 0);
+ ok(Actions.putImageData.called, 'putImageData was called');
+ Actions.putImageData.restore();
});
asyncTest('prepareSetImage without a imageUrl calls the API to get the url', () => {
@@ -98,17 +99,12 @@ define([
}
};
- const expectedAction = {
- type: 'SET_COURSE_IMAGE_ID',
- payload: {
- imageUrl: 'http://imageUrl',
- imageId: 1
- }
- };
+ sinon.spy(Actions, 'putImageData');
- Actions.prepareSetImage(null, 1, fakeAjaxLib)((dispatched) => {
+ Actions.prepareSetImage(null, 1, 0, fakeAjaxLib)((dispatched) => {
start();
- deepEqual(dispatched, expectedAction, 'the proper action was dispatched');
+ ok(Actions.putImageData.called, 'putImageData was called indicating successfully hit API');
+ Actions.putImageData.restore();
});
});
@@ -177,17 +173,12 @@ define([
preventDefault: () => {}
};
- const expectedAction = {
- type: 'SET_COURSE_IMAGE_ID',
- payload: {
- imageUrl: 'http://fileDownloadUrl',
- imageId: 1
- }
- };
+ sinon.spy(Actions, 'prepareSetImage');
Actions.uploadFile(fakeDragonDropEvent, 1, fakeAjaxLib)((dispatched) => {
start();
- deepEqual(dispatched, expectedAction, 'the SET_COURSE_IMAGE_ID action was fired');
+ ok(Actions.prepareSetImage.called, 'prepareSetImage was called');
+ Actions.prepareSetImage.restore();
});
})
diff --git a/spec/javascripts/jsx/course_settings/components/CourseImageSelectorSpec.jsx b/spec/javascripts/jsx/course_settings/components/CourseImageSelectorSpec.jsx
index a4bdca5aa63..1ce6a0fa71d 100644
--- a/spec/javascripts/jsx/course_settings/components/CourseImageSelectorSpec.jsx
+++ b/spec/javascripts/jsx/course_settings/components/CourseImageSelectorSpec.jsx
@@ -23,13 +23,6 @@ define([
ok(component);
});
- test('the hidden input reflects the state value of the selector', () => {
- const component = TestUtils.renderIntoDocument(
-
- );
- equal(React.findDOMNode(component.refs.hiddenInput).value, initialState.courseImage, 'the input matches');
- });
-
test('it sets the background image style properly', () => {
const dispatchStub = sinon.stub(fakeStore, 'getState').returns(Object.assign(initialState, {
imageUrl: 'http://coolUrl'
diff --git a/spec/javascripts/jsx/course_settings/reducersSpec.jsx b/spec/javascripts/jsx/course_settings/reducersSpec.jsx
index 07e6514a5dd..cab4a74129e 100644
--- a/spec/javascripts/jsx/course_settings/reducersSpec.jsx
+++ b/spec/javascripts/jsx/course_settings/reducersSpec.jsx
@@ -64,34 +64,12 @@ define(['jsx/course_settings/reducer'], (reducer) => {
imageUrl: '',
courseImage: '',
showModal: true,
- hiddenInputName: ''
};
const newState = reducer(initialState, action);
equal(newState.imageUrl, 'http://imageUrl', 'image url gets set');
equal(newState.courseImage, '42', 'image id gets set');
equal(newState.showModal, false, 'modal gets closed');
- equal(newState.hiddenInputName, 'course[image_id]', 'input name is set properly');
});
-
- test('REMOVE_IMAGE', () => {
- const action = {
- type: 'REMOVE_IMAGE'
- };
-
- const initialState = {
- imageUrl: 'http://imageUrl',
- courseImage: '42',
- removeImage: false,
- hiddenInputName: ''
- };
-
- const newState = reducer(initialState, action);
- equal(newState.imageUrl, '', 'image url gets set');
- equal(newState.courseImage, 'abc', 'image id gets set');
- equal(newState.removeImage, true, 'remove image is set');
- equal(newState.hiddenInputName, 'course[remove_image]', 'input name is set properly');
- });
-
-
+
});
\ No newline at end of file