mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merged in AD-419-decouple-piece-registration-from- (pull request #7)
Ad 419 decouple piece registration from
This commit is contained in:
commit
927c89f342
@ -80,7 +80,7 @@ let AccordionListItem = React.createClass({
|
||||
render() {
|
||||
let linkData;
|
||||
|
||||
if(this.props.content.num_editions < 1) {
|
||||
if(this.props.content.num_editions < 1 || !this.props.content.first_edition) {
|
||||
linkData = {
|
||||
to: 'piece',
|
||||
params: {
|
||||
@ -91,7 +91,7 @@ let AccordionListItem = React.createClass({
|
||||
linkData = {
|
||||
to: 'edition',
|
||||
params: {
|
||||
editionId: this.props.content.first_edition ? this.props.content.first_edition.bitcoin_id : 0
|
||||
editionId: this.props.content.first_edition.bitcoin_id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -73,31 +73,28 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
let numEditions = piece.num_editions;
|
||||
|
||||
if(numEditions <= 0) {
|
||||
return (
|
||||
<CreateEditionsButton
|
||||
label={getLangText('Create editions')}
|
||||
className="btn-xs pull-right"
|
||||
piece={piece}
|
||||
toggleCreateEditionsDialog={this.props.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.props.onPollingSuccess}/>
|
||||
);
|
||||
} else if(numEditions === 1) {
|
||||
let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : '';
|
||||
if (piece.acl.acl_editions){
|
||||
return (
|
||||
<CreateEditionsButton
|
||||
label={getLangText('Create editions')}
|
||||
className="btn-xs pull-right"
|
||||
piece={piece}
|
||||
toggleCreateEditionsDialog={this.props.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.props.onPollingSuccess}/>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
} else {
|
||||
let editionMapping = piece && piece.first_edition ? piece.first_edition.num_editions_available + '/' + piece.num_editions : '';
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={this.toggleTable}
|
||||
className={classNames('btn', 'btn-default', 'btn-xs', 'ascribe-accordion-list-item-edition-widget', this.props.className)}>
|
||||
{editionMapping + ' ' + getLangText('Edition')} {this.getGlyphicon()}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<button
|
||||
onClick={this.toggleTable}
|
||||
className={classNames('btn', 'btn-default', 'btn-xs', 'ascribe-accordion-list-item-edition-widget', this.props.className)}>
|
||||
{numEditions + ' ' + getLangText('Editions')} {this.getGlyphicon()}
|
||||
{editionMapping + ' ' + getLangText('Editions')} {this.getGlyphicon()}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
@ -162,8 +162,7 @@ let AccordionListItemTableEditions = React.createClass({
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
let content = item.acl;
|
||||
if (item.request_action){
|
||||
// TODO should request be translated?
|
||||
if (item.request_action) {
|
||||
content = [item.request_action + ' request'];
|
||||
}
|
||||
return {
|
||||
|
@ -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: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
|
||||
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,6 +127,11 @@ ${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[this.props.action];
|
||||
let aclProps = this.actionProperties();
|
||||
@ -126,7 +139,7 @@ ${this.props.currentUser.username}
|
||||
<ModalWrapper
|
||||
button={
|
||||
<button className={shouldDisplay ? 'btn btn-default btn-sm ' : 'hidden'}>
|
||||
{this.props.action.toUpperCase()}
|
||||
{this.sanitizeAction()}
|
||||
</button>
|
||||
}
|
||||
handleSuccess={ aclProps.handleSuccess }
|
||||
|
@ -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({
|
||||
<div className={this.props.className}>
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="transfer"
|
||||
action="acl_transfer"
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="consign"
|
||||
action="acl_consign"
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="unconsign"
|
||||
action="acl_unconsign"
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="loan"
|
||||
action="acl_loan"
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="share"
|
||||
action="acl_share"
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
|
@ -67,7 +67,7 @@ let CreateEditionsButton = React.createClass({
|
||||
|
||||
let availableAcls = getAvailableAcls(piece);
|
||||
|
||||
if (availableAcls.editions || piece.num_editions > 0){
|
||||
if (!piece.acl.acl_editions || piece.num_editions > 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -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.delete) {
|
||||
if (availableAcls.acl_delete) {
|
||||
content = <EditionDeleteForm editions={ this.props.editions }/>;
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>;
|
||||
}
|
||||
else if (availableAcls.unshare){
|
||||
else if (availableAcls.acl_unshare || (this.props.editions.constructor !== Array && this.props.editions.acl.acl_unshare)){
|
||||
content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>;
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('REMOVE FROM COLLECTION')}</Button>;
|
||||
}
|
||||
|
@ -113,7 +113,8 @@ let Piece = React.createClass({
|
||||
<AclButtonList
|
||||
className="text-center ascribe-button-list"
|
||||
availableAcls={this.props.piece.acl}
|
||||
editions={this.props.piece}>
|
||||
editions={this.props.piece}
|
||||
handleSuccess={this.props.loadPiece}>
|
||||
<CreateEditionsButton
|
||||
label={getLangText('CREATE EDITIONS')}
|
||||
className="btn-sm"
|
||||
|
@ -24,8 +24,9 @@ let EditionDeleteForm = React.createClass({
|
||||
<p>{getLangText('Are you sure you would like to permanently delete this edition')}?</p>
|
||||
<p>{getLangText('This is an irrevocable action%s', '.')}</p>
|
||||
<div className="modal-footer">
|
||||
<button type="submit" className="btn btn-ascribe-inv" onClick={this.submit}>{getLangText('YES, DELETE')}</button>
|
||||
<button className="btn btn-ascribe" onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
<button type="submit" className="btn btn-danger btn-delete btn-sm ascribe-margin-1px" onClick={this.submit}>{getLangText('YES, DELETE')}</button>
|
||||
<button className="btn btn-default btn-sm ascribe-margin-1px" style={{marginLeft: '0'}}
|
||||
onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
import requests from '../../utils/requests';
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
@ -12,7 +12,12 @@ let EditionRemoveFromCollectionForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
|
||||
if (this.props.editions.constructor === Array) {
|
||||
return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
|
||||
}
|
||||
else {
|
||||
return requests.prepareUrl(apiUrls.piece_remove_from_collection, {piece_id: this.editions.piece_id});
|
||||
}
|
||||
},
|
||||
httpVerb(){
|
||||
return 'delete';
|
||||
|
@ -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,
|
||||
|
@ -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 (
|
||||
<div className={this.props.className}>
|
||||
<div className="row no-margin">
|
||||
|
@ -5,16 +5,18 @@ import React from 'react';
|
||||
|
||||
let TableItemAclFiltered = React.createClass({
|
||||
propTypes: {
|
||||
content: React.PropTypes.array.isRequired
|
||||
content: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
var availableAcls = ['consign', 'loan', 'transfer', 'view', 'consign request', 'unconsign request', 'loan request'];
|
||||
var availableAcls = ['acl_consign', 'acl_loan', 'acl_transfer', 'acl_view', 'acl_share', 'acl_unshare'];
|
||||
|
||||
let filteredAcls = this.props.content.filter((v) => {
|
||||
return availableAcls.indexOf(v) > -1;
|
||||
let filteredAcls = Object.keys(this.props.content).filter((key) => {
|
||||
return availableAcls.indexOf(key) > -1 && this.props.content[key];
|
||||
});
|
||||
|
||||
filteredAcls = filteredAcls.map((acl) => acl.split('acl_')[1]);
|
||||
|
||||
return (
|
||||
<span>
|
||||
{filteredAcls.join('/')}
|
||||
|
@ -37,6 +37,7 @@ let apiUrls = {
|
||||
'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/',
|
||||
'pieces_list': AppConstants.apiEndpoint + 'pieces/',
|
||||
'pieces_list_request_actions': AppConstants.apiEndpoint + 'pieces/request_actions/',
|
||||
'piece_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/pieces/${piece_id}/',
|
||||
'user': AppConstants.apiEndpoint + 'users/',
|
||||
'users_login': AppConstants.apiEndpoint + 'users/login/',
|
||||
'users_logout': AppConstants.apiEndpoint + 'users/logout/',
|
||||
|
@ -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;
|
@ -1,23 +1,52 @@
|
||||
'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 (editions.constructor !== Array){
|
||||
return [];
|
||||
}
|
||||
// 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;
|
||||
}
|
@ -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];
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user