From 60600a72d4b638cddaea9e337f1800e376e62aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 13 Jul 2015 21:19:45 +0200 Subject: [PATCH] refactor bulk acls for backend adjustment --- js/components/ascribe_buttons/acl_button.js | 31 +++++++++---- .../ascribe_buttons/acl_button_list.js | 12 ++--- .../ascribe_buttons/delete_button.js | 6 +-- .../ascribe_forms/form_share_email.js | 2 +- .../piece_list_bulk_modal.js | 4 +- .../ascribe_table/table_item_acl_filtered.js | 2 +- js/constants/application_constants.js | 5 +-- js/getAvailableAcls | 0 js/utils/acl_utils.js | 45 +++++++++++++++---- js/utils/general_utils.js | 17 +++---- 10 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 js/getAvailableAcls diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index e9d2aa2a..5f1cb3a0 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -19,8 +19,11 @@ import apiUrls from '../../constants/api_urls'; let AclButton = React.createClass({ propTypes: { action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, - availableAcls: React.PropTypes.array.isRequired, - pieceOrEditions: React.PropTypes.object.isRequired, + availableAcls: React.PropTypes.object.isRequired, + pieceOrEditions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]).isRequired, currentUser: React.PropTypes.object, handleSuccess: React.PropTypes.func.isRequired, className: React.PropTypes.string @@ -29,8 +32,9 @@ let AclButton = React.createClass({ isPiece(){ return !(this.props.pieceOrEditions.constructor === Array); }, + actionProperties(){ - if (this.props.action === 'consign'){ + if (this.props.action === 'acl_consign'){ return { title: getLangText('Consign artwork'), tooltip: getLangText('Have someone else sell the artwork'), @@ -38,14 +42,14 @@ let AclButton = React.createClass({ handleSuccess: this.showNotification }; } - if (this.props.action === 'unconsign'){ + if (this.props.action === 'acl_unconsign'){ return { title: getLangText('Unconsign artwork'), tooltip: getLangText('Have the owner manage his sales again'), form: , handleSuccess: this.showNotification }; - }else if (this.props.action === 'transfer') { + }else if (this.props.action === 'acl_transfer') { return { title: getLangText('Transfer artwork'), tooltip: getLangText('Transfer the ownership of the artwork'), @@ -53,7 +57,7 @@ let AclButton = React.createClass({ handleSuccess: this.showNotification }; } - else if (this.props.action === 'loan'){ + else if (this.props.action === 'acl_loan'){ return { title: getLangText('Loan artwork'), tooltip: getLangText('Loan your artwork for a limited period of time'), @@ -61,7 +65,7 @@ let AclButton = React.createClass({ handleSuccess: this.showNotification }; } - else if (this.props.action === 'share'){ + else if (this.props.action === 'acl_share'){ return { title: getLangText('Share artwork'), tooltip: getLangText('Share the artwork'), @@ -73,6 +77,8 @@ let AclButton = React.createClass({ ), handleSuccess: this.showNotification }; + } else { + throw new Error('Your specified action did not match a form.'); } }, @@ -82,6 +88,7 @@ let AclButton = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); }, + // plz move to share form getTitlesString(){ if (this.isPiece()){ return '\"' + this.props.pieceOrEditions.title + '\"'; @@ -105,6 +112,7 @@ let AclButton = React.createClass({ } }, +// plz move to share form getShareMessage(){ return ( ` @@ -119,14 +127,19 @@ ${this.props.currentUser.username} ); }, + // Removes the acl_ prefix and converts to upper case + sanitizeAction() { + return this.props.action.split('acl_')[1].toUpperCase(); + }, + render() { - let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; + let shouldDisplay = this.props.availableAcls[this.props.action]; let aclProps = this.actionProperties(); return ( - {this.props.action.toUpperCase()} + {this.sanitizeAction()} } handleSuccess={ aclProps.handleSuccess } diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index 5fb3b224..1a694712 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -15,7 +15,7 @@ let AclButtonList = React.createClass({ React.PropTypes.object, React.PropTypes.array ]), - availableAcls: React.PropTypes.array, + availableAcls: React.PropTypes.object, handleSuccess: React.PropTypes.func, children: React.PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.element), @@ -45,31 +45,31 @@ let AclButtonList = React.createClass({
diff --git a/js/components/ascribe_buttons/delete_button.js b/js/components/ascribe_buttons/delete_button.js index 0c9ef154..3f2713e0 100644 --- a/js/components/ascribe_buttons/delete_button.js +++ b/js/components/ascribe_buttons/delete_button.js @@ -13,7 +13,7 @@ import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils.js' +import { getLangText } from '../../utils/lang_utils.js'; import EditionListActions from '../../actions/edition_list_actions'; @@ -41,11 +41,11 @@ let DeleteButton = React.createClass({ let btnDelete = null; let content = null; - if (availableAcls.indexOf('delete') > -1) { + if (availableAcls.acl_delete) { content = ; btnDelete = ; } - else if (availableAcls.indexOf('del_from_collection') > -1){ + else if (availableAcls.unshare){ content = ; btnDelete = ; } diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index cfdce452..881c9683 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -16,7 +16,7 @@ import { getLangText } from '../../utils/lang_utils.js'; let ShareForm = React.createClass({ propTypes: { url: React.PropTypes.string, - id: React.PropTypes.string, + id: React.PropTypes.object, message: React.PropTypes.string, editions: React.PropTypes.array, currentUser: React.PropTypes.object, diff --git a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js index a02dca9c..acf12665 100644 --- a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js @@ -15,7 +15,7 @@ import AclButtonList from '../ascribe_buttons/acl_button_list'; import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils.js' +import { getLangText } from '../../utils/lang_utils.js'; let PieceListBulkModal = React.createClass({ propTypes: { @@ -84,7 +84,7 @@ let PieceListBulkModal = React.createClass({ let selectedEditions = this.fetchSelectedEditionList(); let availableAcls = getAvailableAcls(selectedEditions); - if(availableAcls.length > 0) { + if(Object.keys(availableAcls).length > 0) { return (
diff --git a/js/components/ascribe_table/table_item_acl_filtered.js b/js/components/ascribe_table/table_item_acl_filtered.js index 46ac4d08..b3a6adb7 100644 --- a/js/components/ascribe_table/table_item_acl_filtered.js +++ b/js/components/ascribe_table/table_item_acl_filtered.js @@ -5,7 +5,7 @@ import React from 'react'; let TableItemAclFiltered = React.createClass({ propTypes: { - content: React.PropTypes.array.isRequired + content: React.PropTypes.object.isRequired }, render() { diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 61955469..2a8e0807 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -9,11 +9,10 @@ let constants = { 'apiEndpoint': window.API_ENDPOINT, 'serverUrl': window.SERVER_URL, 'baseUrl': window.BASE_URL, - 'aclList': ['edit', 'consign', 'consign_request', 'unconsign', 'unconsign_request', 'transfer', - 'loan', 'loan_request', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'], + 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_editions', 'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', 'acl_withdraw_transfer'], // in case of whitelabel cusomization, we store stuff here 'whitelabel': {} }; -export default constants; +export default constants; \ No newline at end of file diff --git a/js/getAvailableAcls b/js/getAvailableAcls new file mode 100644 index 00000000..e69de29b diff --git a/js/utils/acl_utils.js b/js/utils/acl_utils.js index a29aa7bf..4f287c96 100644 --- a/js/utils/acl_utils.js +++ b/js/utils/acl_utils.js @@ -1,23 +1,50 @@ 'use strict'; +import { sanitize } from './general_utils'; + +function intersectAcls(a, b) { + return a.filter((val) => b.indexOf(val) > -1); +} + export function getAvailableAcls(editions) { let availableAcls = []; + // if you copy a javascript array of objects using slice, then + // the object reference is still there. + // Therefore we need to do this ugly copying + let editionsCopy = JSON.parse(JSON.stringify(editions)); + + // sanitize object acls in editions + // so that they don't contain any falsy key-value pairs anymore + editionsCopy = editionsCopy.map((edition) => { + // acl also returns the piece id and the edition id + // therefore, we're going to remove it + edition.acl.edition = false; + edition.acl.piece = false; + + edition.acl = sanitize(edition.acl, (val) => !val); + edition.acl = Object.keys(edition.acl); + return edition; + }); + // If no edition has been selected, availableActions is empty // If only one edition has been selected, their actions are available // If more than one editions have been selected, their acl properties are intersected - if(editions.length >= 1) { - availableAcls = editions[0].acl; + if(editionsCopy.length >= 1) { + availableAcls = editionsCopy[0].acl; } - if(editions.length >= 2) { - for(let i = 1; i < editions.length; i++) { - availableAcls = intersectAcls(availableAcls, editions[i].acl); + if(editionsCopy.length >= 2) { + for(let i = 1; i < editionsCopy.length; i++) { + availableAcls = intersectAcls(availableAcls, editionsCopy[i].acl); } } - return availableAcls; -} + // convert acls back to key-value object + let availableAclsObj = {}; + for(let i = 0; i < availableAcls.length; i++) { + availableAclsObj[availableAcls[i]] = true; + } -export function intersectAcls(a, b) { - return a.filter((val) => b.indexOf(val) > -1); + + return availableAclsObj; } \ No newline at end of file diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 0bddb765..5e5d9298 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -3,21 +3,22 @@ /** * Takes an object and deletes all keys that are * - * - empty strings; or - * - null; or - * - undefined - * + * tagged as false by the passed in filter function * * @param {object} obj regular javascript object * @return {object} regular javascript object without null values or empty strings */ -export function sanitize(obj) { +export function sanitize(obj, filterFn) { + if(!filterFn) { + // By matching null with a double equal, we can match undefined and null + // http://stackoverflow.com/a/15992131 + filterFn = (val) => val == null || val === ''; + } + Object .keys(obj) .map((key) => { - // By matching null with a double equal, we can match undefined and null - // http://stackoverflow.com/a/15992131 - if(obj[key] == null || obj[key] === '') { + if(filterFn(obj[key])) { delete obj[key]; } });