1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-23 01:39:36 +01:00

refactor bulk acls for backend adjustment

This commit is contained in:
Tim Daubenschütz 2015-07-13 21:19:45 +02:00
parent f225ee4232
commit 60600a72d4
10 changed files with 82 additions and 42 deletions

View File

@ -19,8 +19,11 @@ import apiUrls from '../../constants/api_urls';
let AclButton = React.createClass({ let AclButton = React.createClass({
propTypes: { propTypes: {
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
availableAcls: React.PropTypes.array.isRequired, availableAcls: React.PropTypes.object.isRequired,
pieceOrEditions: React.PropTypes.object.isRequired, pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
currentUser: React.PropTypes.object, currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func.isRequired, handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string className: React.PropTypes.string
@ -29,8 +32,9 @@ let AclButton = React.createClass({
isPiece(){ isPiece(){
return !(this.props.pieceOrEditions.constructor === Array); return !(this.props.pieceOrEditions.constructor === Array);
}, },
actionProperties(){ actionProperties(){
if (this.props.action === 'consign'){ if (this.props.action === 'acl_consign'){
return { return {
title: getLangText('Consign artwork'), title: getLangText('Consign artwork'),
tooltip: getLangText('Have someone else sell the artwork'), tooltip: getLangText('Have someone else sell the artwork'),
@ -38,14 +42,14 @@ let AclButton = React.createClass({
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
} }
if (this.props.action === 'unconsign'){ if (this.props.action === 'acl_unconsign'){
return { return {
title: getLangText('Unconsign artwork'), title: getLangText('Unconsign artwork'),
tooltip: getLangText('Have the owner manage his sales again'), tooltip: getLangText('Have the owner manage his sales again'),
form: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>, form: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
}else if (this.props.action === 'transfer') { }else if (this.props.action === 'acl_transfer') {
return { return {
title: getLangText('Transfer artwork'), title: getLangText('Transfer artwork'),
tooltip: getLangText('Transfer the ownership of the artwork'), tooltip: getLangText('Transfer the ownership of the artwork'),
@ -53,7 +57,7 @@ let AclButton = React.createClass({
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
} }
else if (this.props.action === 'loan'){ else if (this.props.action === 'acl_loan'){
return { return {
title: getLangText('Loan artwork'), title: getLangText('Loan artwork'),
tooltip: getLangText('Loan your artwork for a limited period of time'), tooltip: getLangText('Loan your artwork for a limited period of time'),
@ -61,7 +65,7 @@ let AclButton = React.createClass({
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
} }
else if (this.props.action === 'share'){ else if (this.props.action === 'acl_share'){
return { return {
title: getLangText('Share artwork'), title: getLangText('Share artwork'),
tooltip: getLangText('Share the artwork'), tooltip: getLangText('Share the artwork'),
@ -73,6 +77,8 @@ let AclButton = React.createClass({
), ),
handleSuccess: this.showNotification 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); GlobalNotificationActions.appendGlobalNotification(notification);
}, },
// plz move to share form
getTitlesString(){ getTitlesString(){
if (this.isPiece()){ if (this.isPiece()){
return '\"' + this.props.pieceOrEditions.title + '\"'; return '\"' + this.props.pieceOrEditions.title + '\"';
@ -105,6 +112,7 @@ let AclButton = React.createClass({
} }
}, },
// plz move to share form
getShareMessage(){ getShareMessage(){
return ( 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() { render() {
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; let shouldDisplay = this.props.availableAcls[this.props.action];
let aclProps = this.actionProperties(); let aclProps = this.actionProperties();
return ( return (
<ModalWrapper <ModalWrapper
button={ button={
<button className={shouldDisplay ? 'btn btn-default btn-sm ' : 'hidden'}> <button className={shouldDisplay ? 'btn btn-default btn-sm ' : 'hidden'}>
{this.props.action.toUpperCase()} {this.sanitizeAction()}
</button> </button>
} }
handleSuccess={ aclProps.handleSuccess } handleSuccess={ aclProps.handleSuccess }

View File

@ -15,7 +15,7 @@ let AclButtonList = React.createClass({
React.PropTypes.object, React.PropTypes.object,
React.PropTypes.array React.PropTypes.array
]), ]),
availableAcls: React.PropTypes.array, availableAcls: React.PropTypes.object,
handleSuccess: React.PropTypes.func, handleSuccess: React.PropTypes.func,
children: React.PropTypes.oneOfType([ children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.arrayOf(React.PropTypes.element),
@ -45,31 +45,31 @@ let AclButtonList = React.createClass({
<div className={this.props.className}> <div className={this.props.className}>
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="transfer" action="acl_transfer"
pieceOrEditions={this.props.editions} pieceOrEditions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess}/> handleSuccess={this.props.handleSuccess}/>
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="consign" action="acl_consign"
pieceOrEditions={this.props.editions} pieceOrEditions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="unconsign" action="acl_unconsign"
pieceOrEditions={this.props.editions} pieceOrEditions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="loan" action="acl_loan"
pieceOrEditions={this.props.editions} pieceOrEditions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="share" action="acl_share"
pieceOrEditions={this.props.editions} pieceOrEditions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />

View File

@ -13,7 +13,7 @@ import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions'; import GlobalNotificationActions from '../../actions/global_notification_actions';
import { getAvailableAcls } from '../../utils/acl_utils'; 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'; import EditionListActions from '../../actions/edition_list_actions';
@ -41,11 +41,11 @@ let DeleteButton = React.createClass({
let btnDelete = null; let btnDelete = null;
let content = null; let content = null;
if (availableAcls.indexOf('delete') > -1) { if (availableAcls.acl_delete) {
content = <EditionDeleteForm editions={ this.props.editions }/>; content = <EditionDeleteForm editions={ this.props.editions }/>;
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>; btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>;
} }
else if (availableAcls.indexOf('del_from_collection') > -1){ else if (availableAcls.unshare){
content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>; content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>;
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('REMOVE FROM COLLECTION')}</Button>; btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('REMOVE FROM COLLECTION')}</Button>;
} }

View File

@ -16,7 +16,7 @@ import { getLangText } from '../../utils/lang_utils.js';
let ShareForm = React.createClass({ let ShareForm = React.createClass({
propTypes: { propTypes: {
url: React.PropTypes.string, url: React.PropTypes.string,
id: React.PropTypes.string, id: React.PropTypes.object,
message: React.PropTypes.string, message: React.PropTypes.string,
editions: React.PropTypes.array, editions: React.PropTypes.array,
currentUser: React.PropTypes.object, currentUser: React.PropTypes.object,

View File

@ -15,7 +15,7 @@ import AclButtonList from '../ascribe_buttons/acl_button_list';
import { getAvailableAcls } from '../../utils/acl_utils'; import { getAvailableAcls } from '../../utils/acl_utils';
import { getLangText } from '../../utils/lang_utils.js' import { getLangText } from '../../utils/lang_utils.js';
let PieceListBulkModal = React.createClass({ let PieceListBulkModal = React.createClass({
propTypes: { propTypes: {
@ -84,7 +84,7 @@ let PieceListBulkModal = React.createClass({
let selectedEditions = this.fetchSelectedEditionList(); let selectedEditions = this.fetchSelectedEditionList();
let availableAcls = getAvailableAcls(selectedEditions); let availableAcls = getAvailableAcls(selectedEditions);
if(availableAcls.length > 0) { if(Object.keys(availableAcls).length > 0) {
return ( return (
<div className={this.props.className}> <div className={this.props.className}>
<div className="row no-margin"> <div className="row no-margin">

View File

@ -5,7 +5,7 @@ import React from 'react';
let TableItemAclFiltered = React.createClass({ let TableItemAclFiltered = React.createClass({
propTypes: { propTypes: {
content: React.PropTypes.array.isRequired content: React.PropTypes.object.isRequired
}, },
render() { render() {

View File

@ -9,11 +9,10 @@ let constants = {
'apiEndpoint': window.API_ENDPOINT, 'apiEndpoint': window.API_ENDPOINT,
'serverUrl': window.SERVER_URL, 'serverUrl': window.SERVER_URL,
'baseUrl': window.BASE_URL, 'baseUrl': window.BASE_URL,
'aclList': ['edit', 'consign', 'consign_request', 'unconsign', 'unconsign_request', 'transfer', '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'],
'loan', 'loan_request', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'],
// in case of whitelabel cusomization, we store stuff here // in case of whitelabel cusomization, we store stuff here
'whitelabel': {} 'whitelabel': {}
}; };
export default constants; export default constants;

0
js/getAvailableAcls Normal file
View File

View File

@ -1,23 +1,50 @@
'use strict'; 'use strict';
import { sanitize } from './general_utils';
function intersectAcls(a, b) {
return a.filter((val) => b.indexOf(val) > -1);
}
export function getAvailableAcls(editions) { export function getAvailableAcls(editions) {
let availableAcls = []; 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 no edition has been selected, availableActions is empty
// If only one edition has been selected, their actions are available // 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 more than one editions have been selected, their acl properties are intersected
if(editions.length >= 1) { if(editionsCopy.length >= 1) {
availableAcls = editions[0].acl; availableAcls = editionsCopy[0].acl;
} }
if(editions.length >= 2) { if(editionsCopy.length >= 2) {
for(let i = 1; i < editions.length; i++) { for(let i = 1; i < editionsCopy.length; i++) {
availableAcls = intersectAcls(availableAcls, editions[i].acl); 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;
} }

View File

@ -3,21 +3,22 @@
/** /**
* Takes an object and deletes all keys that are * Takes an object and deletes all keys that are
* *
* - empty strings; or * tagged as false by the passed in filter function
* - null; or
* - undefined
*
* *
* @param {object} obj regular javascript object * @param {object} obj regular javascript object
* @return {object} regular javascript object without null values or empty strings * @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 Object
.keys(obj) .keys(obj)
.map((key) => { .map((key) => {
// By matching null with a double equal, we can match undefined and null if(filterFn(obj[key])) {
// http://stackoverflow.com/a/15992131
if(obj[key] == null || obj[key] === '') {
delete obj[key]; delete obj[key];
} }
}); });