diff --git a/blueprints/api.py b/blueprints/api.py index f2a359a..d93a88d 100644 --- a/blueprints/api.py +++ b/blueprints/api.py @@ -13,17 +13,18 @@ sys.path.insert(0,'..') # Hack to work around ascii encode error # TODO: Figure out which dependency tries to encode input to ascii reload(sys) -sys.setdefaultencoding("utf-8") +sys.setdefaultencoding('utf-8') s3 = boto3.client('s3') def create_presigned_post(): bucket_name = config.JOYCE_S3_BUCKET - key_name = str(uuid.uuid4()) + key_name = 'images/' + str(uuid.uuid4()) response = s3.generate_presigned_post( bucket_name, key_name, - ExpiresIn = 3600 + ExpiresIn = 3600, + Conditions = [[ 'eq', '$acl', 'public-read' ]], ) return response @@ -158,19 +159,19 @@ def es_search_text(body): 'from': 0, 'size': 10, 'query': { - "nested": { - "path": "search_text", - "query": { - "bool": { - "must": [ - { "match": { "search_text.text": body}} + 'nested': { + 'path': 'search_text', + 'query': { + 'bool': { + 'must': [ + { 'match': { 'search_text.text': body}} ] } }, - "inner_hits": { - "highlight": { - "fields": { - "search_text.text": {} + 'inner_hits': { + 'highlight': { + 'fields': { + 'search_text.text': {} } } } diff --git a/src/actions/userActions.js b/src/actions/userActions.js index 5797939..aa93b48 100644 --- a/src/actions/userActions.js +++ b/src/actions/userActions.js @@ -128,7 +128,11 @@ const userActions = { ({ type: 'UPLOAD_MEDIA_SUBMIT', data: input - }) + }), + clearLoadedMedia: () => + ({ + type: 'CLEAR_LOADED_MEDIA' + }), } export default userActions \ No newline at end of file diff --git a/src/components/editorOptionBlock.js b/src/components/editorOptionBlock.js index bb2e0a6..0f179ce 100644 --- a/src/components/editorOptionBlock.js +++ b/src/components/editorOptionBlock.js @@ -29,7 +29,7 @@ export const EditorEditModeRichTextOptions = ({editorState, onToolButtonClick, d export const EditorSubmitOptions = ({cancelEdit, onSubmitClick}) => -
+
cancelEdit()}/>
@@ -46,4 +46,4 @@ export const EditorAnnotateOptions = ({onNewAnnotationClick, onRemoveAnnotationC
-
\ No newline at end of file +
\ No newline at end of file diff --git a/src/components/noteMediaPicker.js b/src/components/noteMediaPicker.js new file mode 100644 index 0000000..7136a33 --- /dev/null +++ b/src/components/noteMediaPicker.js @@ -0,0 +1,24 @@ +import React from 'react' + +import { MediaList } from './list' + +const NoteMediaPicker = ({media}) => +
+
+
+ +
+ {media.map(media => +
+ +
{media.title}
+
+ )} +
+
+
+
+ +export default NoteMediaPicker \ No newline at end of file diff --git a/src/containers/editorEditModeContainer.js b/src/containers/editorEditModeContainer.js index 0dec22c..9cdc66b 100644 --- a/src/containers/editorEditModeContainer.js +++ b/src/containers/editorEditModeContainer.js @@ -8,10 +8,12 @@ import actions from '../actions' import DocumentTitle from '../components/documentTitle' import DocumentTitleInput from '../components/documentTitleInput' import TagColorPicker from '../components/tagColorPicker' +import NoteMediaPicker from '../components/noteMediaPicker' import MediaUploadInput from '../components/mediaUploadInput' import LoadingSpinner from '../components/loadingSpinner' const EditorEditMode = ({ + media, currentDocument, docType, editorState, @@ -22,6 +24,7 @@ const EditorEditMode = ({ onDocumentTitleChange, onColorPickerInputChange, onColorSwatchClick, + onClearLoadedMedia, onMediaInputChange, onMediaUpload, cancelEdit, @@ -50,6 +53,9 @@ const EditorEditMode = ({ /> + {docType === 'notes' && + + } {docType === 'tags' && } {docType === 'media' && inputs.s3Path && -

File uploaded!

+
+
File uploaded!
+
+ +
+
} {docType === 'media' && !inputs.s3Path && @@ -79,6 +92,7 @@ const EditorEditMode = ({ const mapStateToProps = (state, props) => { return { + media: state.media, currentDocument: state.currentDocument, docType: state.docType, editorState: state.editorState, @@ -107,6 +121,9 @@ const mapDispatchToProps = dispatch => { onMediaUpload: input => { dispatch(actions.uploadMediaInput(input)) }, + onClearLoadedMedia: () => { + dispatch(actions.clearLoadedMedia()) + }, cancelEdit: () => { dispatch(actions.cancelEdit()) }, diff --git a/src/middleware/joyceAPI.js b/src/middleware/joyceAPI.js index e528b89..428d9c1 100644 --- a/src/middleware/joyceAPI.js +++ b/src/middleware/joyceAPI.js @@ -54,8 +54,9 @@ const joyceAPI = store => next => action => { case 'UPLOAD_TO_S3_REQUEST': const formData = new FormData() const url = action.signed_post.url - formData.append('AWSAccessKeyId', action.signed_post.fields.AWSAccessKeyId) formData.append('key', action.signed_post.fields.key) + formData.append('AWSAccessKeyId', action.signed_post.fields.AWSAccessKeyId) + formData.append('acl', 'public-read') formData.append('policy', action.signed_post.fields.policy) formData.append('signature', action.signed_post.fields.signature) formData.append('file', action.file) diff --git a/src/modules/api.js b/src/modules/api.js index 0828c68..b9b9fdb 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -52,7 +52,7 @@ const api = { return {status: 'error', data: error} }), HTTPPostMedia: (url, formData) => - axios.post(url, formData, {headers: {'Content-Type': 'image/*', 'ACL': 'public-read'}}).then(res=> { + axios.post(url, formData, {headers: {'Content-Type': formData.get('file').type}}).then(res=> { return {status: 'success', url: url + formData.get('key')} }).catch(error => { return {status: 'error', data: error} diff --git a/src/modules/validation.js b/src/modules/validation.js index 7cb3a61..20ec516 100644 --- a/src/modules/validation.js +++ b/src/modules/validation.js @@ -9,6 +9,11 @@ export const validateSubmittedDocument = (docType, inputs) => { errors.push('Please select a valid hex code color.') } } + if (docType === 'media') { + if (inputs.s3Path === undefined) { + errors.push('Please upload an image first.') + } + } if (inputs.documentTitle.length < 1) { errors.push('Please enter a title.') } diff --git a/src/reducers/inputs.js b/src/reducers/inputs.js index 345f295..53e1a56 100644 --- a/src/reducers/inputs.js +++ b/src/reducers/inputs.js @@ -2,6 +2,7 @@ const initialState = { documentTitle: '', search: '', colorPicker: '', + noteMediaSelection: [], uploadFile: undefined, s3Path: undefined } @@ -10,9 +11,6 @@ const inputs = (state=initialState, action) => { switch(action.type) { // Document Title case 'GET_DOCUMENT_TEXT': - console.log('state', action.state) - console.log('status', action.status) - console.log('docType', action.docType) if (action.status === 'success' && action.state === 'currentDocument' && ['tags', 'media'].indexOf(action.docType) <= 0 ) { return { ...state, @@ -76,8 +74,6 @@ const inputs = (state=initialState, action) => { ...state, uploadFile: action.data } - default: - return state // S3 File case 'UPLOAD_TO_S3_RESPONSE': if (action.status === 'success') { @@ -86,6 +82,13 @@ const inputs = (state=initialState, action) => { s3Path: action.url } } else { return state } + case 'CLEAR_LOADED_MEDIA': + return { + ...state, + s3Path: undefined + } + default: + return state } } diff --git a/src/stylesheets/_editor.scss b/src/stylesheets/_editor.scss index 1d74ab7..9639bc1 100644 --- a/src/stylesheets/_editor.scss +++ b/src/stylesheets/_editor.scss @@ -13,6 +13,15 @@ font-size: 0.8em; } +#note_media_picker { + div { + width: 100%; + } + button { + width: 100%; + } +} + #editor_top_bar_block { button { width: 100%;