Notify Unsplash when image is chosen for Course Card

fixes ADMIN-2658

Test plan
- Verify you can select an image for course cards
  with the Unsplash plugin turned off
- Verify you can select an image for course cards
  with the Unsplash plugin turned on
- Theoretically if you choose and image from
  Unsplash, you'll be able to see the downloads
  number increment, but it takes forever

Change-Id: I8cc1933f913e87d7879f782ff293a6ef0d35fd06
Reviewed-on: https://gerrit.instructure.com/194483
Tested-by: Jenkins
Reviewed-by: Carl Kibler <ckibler@instructure.com>
QA-Review: Carl Kibler <ckibler@instructure.com>
Product-Review: Mysti Lilla <mysti@instructure.com>
This commit is contained in:
Mysti Lilla 2019-05-20 17:36:47 -06:00
parent 619918b3fa
commit ea7196589e
6 changed files with 35 additions and 16 deletions

View File

@ -18,6 +18,7 @@
import axios from 'axios'
import $ from 'jquery'
import qs from 'qs'
import I18n from 'i18n!actions'
import Helpers from './helpers'
import {uploadFile as rawUploadFile} from '../shared/upload_file'
@ -164,13 +165,21 @@ const Actions = {
}
},
uploadImageSearchUrl(imageUrl, courseId, ajaxLib = axios) {
uploadImageSearchUrl(imageUrl, courseId, confirmationId = null, ajaxLib = axios) {
return dispatch => {
dispatch(this.uploadingImage())
dispatch(this.putImageData(courseId, imageUrl, null, ajaxLib))
if (confirmationId != null) {
this.confirmImageSelection(confirmationId, ajaxLib)
}
}
},
confirmImageSelection(confirmationId, ajaxLib = axios) {
// We don't need to wait for this response to come back. This is best effort for Unsplash's benefit.
return ajaxLib.post(`/api/v1/image_selection/${confirmationId}`)
},
uploadFile(event, courseId, ajaxLib = axios) {
event.preventDefault()
return dispatch => {
@ -202,17 +211,7 @@ const Actions = {
},
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(data) {
return Object.keys(data).reduce(
(prev, key) => `${prev + (prev ? '&' : '')}${key}=${data[key]}`,
''
)
}
})
return ajaxLib.put(path, qs.stringify(data))
}
}

View File

@ -99,7 +99,9 @@ export default class CourseImagePicker extends React.Component {
/>
{ENV.use_unsplash_image_search ? (
<ImageSearch
selectImage={imageUrl => this.props.handleImageSearchUrlUpload(imageUrl)}
selectImage={(imageUrl, confirmationId) =>
this.props.handleImageSearchUrlUpload(imageUrl, confirmationId)
}
/>
) : (
<FlickrSearch

View File

@ -88,9 +88,9 @@ export default class CourseImageSelector extends React.Component {
handleFileUpload={(e, courseId) =>
this.props.store.dispatch(Actions.uploadFile(e, courseId))
}
handleImageSearchUrlUpload={imageUrl =>
handleImageSearchUrlUpload={(imageUrl, confirmationId = null) =>
this.props.store.dispatch(
Actions.uploadImageSearchUrl(imageUrl, this.props.courseId)
Actions.uploadImageSearchUrl(imageUrl, this.props.courseId, confirmationId)
)
}
uploadingImage={this.state.uploadingImage}

View File

@ -134,6 +134,7 @@ export default class ImageSearch extends React.Component {
photos.map(photo => (
<ImageSearchItem
key={photo.id}
confirmationId={photo.id}
src={photo.small_url}
description={photo.description ? photo.description : this.state.searchTerm}
selectImage={this.props.selectImage}

View File

@ -23,11 +23,12 @@ class ImageSearchItem extends React.Component {
static propTypes = {
description: PropTypes.string,
src: PropTypes.string,
confirmationId: PropTypes.string,
selectImage: PropTypes.func
}
handleClick = () => {
this.props.selectImage(this.props.src);
this.props.selectImage(this.props.src, this.props.confirmationId);
}
render () {

View File

@ -38,6 +38,8 @@ test('calling setModalVisibility produces the proper object', () => {
showModal: false
}
};
deepEqual(actual, expected)
});
test('calling gotCourseImage produces the proper object', () => {
@ -126,6 +128,20 @@ test('prepareSetImage without a imageUrl calls the API to get the url', assert =
});
});
test('uploadImageSearchUrl without a confirmationId should not call confirmImageSelection', () => {
sinon.spy(Actions, 'confirmImageSelection');
Actions.uploadImageSearchUrl('http://imageUrl', 1)(() => {});
notOk(Actions.confirmImageSelection.called);
Actions.confirmImageSelection.restore();
});
test('uploadImageSearchUrl with a confirmationId calls confirmImageSelection', () => {
sinon.spy(Actions, 'confirmImageSelection');
Actions.uploadImageSearchUrl('http://imageUrl', 1, 'id')(() => {});
ok(Actions.confirmImageSelection.called);
Actions.confirmImageSelection.restore();
});
test('uploadFile returns false when image is not valid', assert => {
const done = assert.async()
const fakeDragonDropEvent = {