1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 17:33:14 +01:00

Rewrite requests module using js-utility-belt's request

This commit is contained in:
Brett Sun 2016-06-14 16:53:18 +02:00
parent 136213856b
commit 2309e21571
27 changed files with 314 additions and 324 deletions

View File

@ -11,10 +11,10 @@ import AlertDismissable from './alert';
import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions'; import GlobalNotificationActions from '../../actions/global_notification_actions';
import requests from '../../utils/requests';
import { sanitize } from '../../utils/general'; import { sanitize } from '../../utils/general';
import { getLangText } from '../../utils/lang'; import { getLangText } from '../../utils/lang';
import request from '../../utils/request';
let Form = React.createClass({ let Form = React.createClass({
@ -95,32 +95,29 @@ let Form = React.createClass({
} }
}, },
post() { request(method) {
requests request(this.props.url, {
.post(this.props.url, { body: this.getFormData() }) method,
jsonBody: this.getFormData()
})
.then(this.handleSuccess) .then(this.handleSuccess)
.catch(this.handleError); .catch(this.handleError);
}, },
post() {
this.request('POST');
},
put() { put() {
requests this.request('PUT');
.put(this.props.url, { body: this.getFormData() })
.then(this.handleSuccess)
.catch(this.handleError);
}, },
patch() { patch() {
requests this.request('PATCH');
.patch(this.props.url, { body: this.getFormData() })
.then(this.handleSuccess)
.catch(this.handleError);
}, },
delete() { delete() {
requests this.request('DELETE');
.delete(this.props.url, this.getFormData())
.then(this.handleSuccess)
.catch(this.handleError);
}, },
getFormData() { getFormData() {

View File

@ -9,6 +9,7 @@ import AclInformation from '../ascribe_buttons/acl_information';
import AscribeSpinner from '../ascribe_spinner'; import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang'; import { getLangText } from '../../utils/lang';
import { formatText } from '../../utils/text';
import { resolveUrl } from '../../utils/url_resolver'; import { resolveUrl } from '../../utils/url_resolver';
@ -22,25 +23,22 @@ let EditionDeleteForm = React.createClass({
}, },
getBitcoinIds() { getBitcoinIds() {
return this.props.editions.map(function(edition){ return this.props.editions.map((edition) => edition.bitcoin_id);
return edition.bitcoin_id; },
getUrl() {
return formatText(resolveUrl('edition_delete'), {
// Since this form can be used for either deleting a single edition or multiple we need
// to call getBitcoinIds to get the value of edition_id
editionId: this.getBitcoinIds().join(',')
}); });
}, },
// Since this form can be used for either deleting a single edition or multiple render() {
// we need to call getBitcoinIds to get the value of edition_id
getFormData() {
return {
edition_id: this.getBitcoinIds().join(',')
};
},
render () {
return ( return (
<Form <Form
ref='form' ref='form'
url={resolveUrl('edition_delete')} url={this.getUrl()}
getFormData={this.getFormData}
method="delete" method="delete"
handleSuccess={this.props.handleSuccess} handleSuccess={this.props.handleSuccess}
buttons={ buttons={

View File

@ -9,6 +9,7 @@ import AclInformation from '../ascribe_buttons/acl_information';
import AscribeSpinner from '../ascribe_spinner'; import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang'; import { getLangText } from '../../utils/lang';
import { formatText } from '../../utils/text';
import { resolveUrl } from '../../utils/url_resolver'; import { resolveUrl } from '../../utils/url_resolver';
@ -20,18 +21,17 @@ let PieceDeleteForm = React.createClass({
handleSuccess: React.PropTypes.func handleSuccess: React.PropTypes.func
}, },
getFormData() { getUrl() {
return { return formatText(resolveUrl('piece'), {
piece_id: this.props.pieceId pieceId: this.props.pieceId
}; });
}, },
render() { render() {
return ( return (
<Form <Form
ref='form' ref='form'
url={resolveUrl('piece')} url={this.getUrl()}
getFormData={this.getFormData}
method="delete" method="delete"
handleSuccess={this.props.handleSuccess} handleSuccess={this.props.handleSuccess}
buttons={ buttons={

View File

@ -6,8 +6,8 @@ import Form from './form';
import Property from './property'; import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable'; import InputTextAreaToggable from './input_textarea_toggable';
import requests from '../../utils/requests';
import { getLangText } from '../../utils/lang.js'; import { getLangText } from '../../utils/lang.js';
import { formatText } from '../../utils/text';
import { resolveUrl } from '../../utils/url_resolver'; import { resolveUrl } from '../../utils/url_resolver';
@ -24,16 +24,24 @@ let PieceExtraDataForm = React.createClass({
}, },
getFormData() { getFormData() {
const { name, pieceId } = this.props;
return { return {
extradata: { extradata: {
[this.props.name]: this.refs.form.refs[this.props.name].state.value [name]: this.refs.form.refs[name].state.value
}, },
piece_id: this.props.pieceId piece_id: pieceId
}; };
}, },
getUrl() {
return formatText(resolveUrl('piece_extradata'), {
pieceId: this.props.pieceId
});
},
render() { render() {
const { convertLinks, editable, extraData, handleSuccess, name, pieceId, title } = this.props; const { convertLinks, editable, extraData, handleSuccess, name, title } = this.props;
const defaultValue = (extraData && extraData[name]) || null; const defaultValue = (extraData && extraData[name]) || null;
if (!defaultValue && !editable) { if (!defaultValue && !editable) {
@ -46,7 +54,7 @@ let PieceExtraDataForm = React.createClass({
disabled={!editable} disabled={!editable}
getFormData={this.getFormData} getFormData={this.getFormData}
handleSuccess={handleSuccess} handleSuccess={handleSuccess}
url={requests.prepareUrl(resolveUrl('piece_extradata'), { piece_id: pieceId })}> url={this.getUrl()}>
<Property <Property
name={name} name={name}
label={title}> label={title}>

View File

@ -7,6 +7,7 @@ import Form from './form';
import AscribeSpinner from '../ascribe_spinner'; import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang'; import { getLangText } from '../../utils/lang';
import { formatText } from '../../utils/text';
import { resolveUrl } from '../../utils/url_resolver'; import { resolveUrl } from '../../utils/url_resolver';
let EditionRemoveFromCollectionForm = React.createClass({ let EditionRemoveFromCollectionForm = React.createClass({
@ -18,25 +19,22 @@ let EditionRemoveFromCollectionForm = React.createClass({
}, },
getBitcoinIds() { getBitcoinIds() {
return this.props.editions.map(function(edition){ return this.props.editions.map((edition) => edition.bitcoin_id);
return edition.bitcoin_id;
});
}, },
// Since this form can be used for either removing a single edition or multiple getUrl() {
// we need to call getBitcoinIds to get the value of edition_id return formatText(resolveUrl('edition_remove_from_collection'), {
getFormData() { // Since this form can be used for either deleting a single edition or multiple we need
return { // to call getBitcoinIds to get the value of edition_id
edition_id: this.getBitcoinIds().join(',') editionId: this.getBitcoinIds().join(',')
}; });
}, },
render() { render() {
return ( return (
<Form <Form
ref='form' ref='form'
url={resolveUrl('edition_remove_from_collection')} url={this.getUrl()}
getFormData={this.getFormData}
method="delete" method="delete"
handleSuccess={this.props.handleSuccess} handleSuccess={this.props.handleSuccess}
buttons={ buttons={

View File

@ -18,18 +18,17 @@ let PieceRemoveFromCollectionForm = React.createClass({
handleSuccess: React.PropTypes.func handleSuccess: React.PropTypes.func
}, },
getFormData() { getUrl() {
return { return formatText(resolveUrl('piece_remove_from_collection'), {
piece_id: this.props.pieceId pieceId: this.props.pieceId
}; });
}, },
render () { render () {
return ( return (
<Form <Form
ref='form' ref='form'
url={resolveUrl('piece_remove_from_collection')} url={this.getUrl()}
getFormData={this.getFormData}
method="delete" method="delete"
handleSuccess={this.props.handleSuccess} handleSuccess={this.props.handleSuccess}
buttons={ buttons={

View File

@ -16,7 +16,7 @@ import AscribeSpinner from '../../../../../ascribe_spinner';
import { getLangText } from '../../../../../../utils/lang'; import { getLangText } from '../../../../../../utils/lang';
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils'; import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
import requests from '../../../../../../utils/requests'; import { formatText } from '../../../../../../utils/text';
import { resolveUrl } from '../../../../../../utils/url_resolver'; import { resolveUrl } from '../../../../../../utils/url_resolver';
@ -58,10 +58,15 @@ let CylandAdditionalDataForm = React.createClass({
}); });
return { return {
extradata: extradata, extradata,
piece_id: this.props.piece.id piece_id: this.props.piece.id
}; };
},
getUrl() {
return formatText(resolveUrl('piece_extradata'), {
pieceId: this.props.piece.id
});
}, },
setIsUploadReady(isReady) { setIsUploadReady(isReady) {
@ -112,7 +117,7 @@ let CylandAdditionalDataForm = React.createClass({
disabled={disabled} disabled={disabled}
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref='form' ref='form'
url={requests.prepareUrl(resolveUrl('piece_extradata'), { piece_id: piece.id })} url={this.getUrl()}
handleSuccess={handleSuccess || this.handleSuccess} handleSuccess={handleSuccess || this.handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}
buttons={buttons} buttons={buttons}

View File

@ -13,7 +13,7 @@ import GlobalNotificationActions from '../../../../../../actions/global_notifica
import AscribeSpinner from '../../../../../ascribe_spinner'; import AscribeSpinner from '../../../../../ascribe_spinner';
import { getLangText } from '../../../../../../utils/lang'; import { getLangText } from '../../../../../../utils/lang';
import requests from '../../../../../../utils/requests'; import { formatText } from '../../../../../../utils/text';
import { resolveUrl } from '../../../../../../utils/url_resolver'; import { resolveUrl } from '../../../../../../utils/url_resolver';
@ -44,10 +44,15 @@ let IkonotvArtistDetailsForm = React.createClass({
}); });
return { return {
extradata: extradata, extradata,
piece_id: this.props.piece.id piece_id: this.props.piece.id
}; };
},
getUrl() {
return formatText(resolveUrl('piece_extradata'), {
pieceId: this.props.piece.id
});
}, },
handleSuccess() { handleSuccess() {
@ -97,7 +102,7 @@ let IkonotvArtistDetailsForm = React.createClass({
disabled={disabled} disabled={disabled}
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref='form' ref='form'
url={requests.prepareUrl(resolveUrl('piece_extradata'), { piece_id: piece.id })} url={this.getUrl()}
handleSuccess={handleSuccess || this.handleSuccess} handleSuccess={handleSuccess || this.handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}
buttons={buttons} buttons={buttons}

View File

@ -13,7 +13,7 @@ import GlobalNotificationActions from '../../../../../../actions/global_notifica
import AscribeSpinner from '../../../../../ascribe_spinner'; import AscribeSpinner from '../../../../../ascribe_spinner';
import { getLangText } from '../../../../../../utils/lang'; import { getLangText } from '../../../../../../utils/lang';
import requests from '../../../../../../utils/requests'; import { formatText } from '../../../../../../utils/text';
import { resolveUrl } from '../../../../../../utils/url_resolver'; import { resolveUrl } from '../../../../../../utils/url_resolver';
@ -44,10 +44,15 @@ let IkonotvArtworkDetailsForm = React.createClass({
}); });
return { return {
extradata: extradata, extradata,
piece_id: this.props.piece.id piece_id: this.props.piece.id
}; };
},
getUrl() {
return formatText(resolveUrl('piece_extradata'), {
pieceId: this.props.piece.id
});
}, },
handleSuccess() { handleSuccess() {
@ -97,7 +102,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
disabled={disabled} disabled={disabled}
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref='form' ref='form'
url={requests.prepareUrl(resolveUrl('piece_extradata'), { piece_id: piece.id })} url={this.getUrl()}
handleSuccess={handleSuccess || this.handleSuccess} handleSuccess={handleSuccess || this.handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}
buttons={buttons} buttons={buttons}

View File

@ -17,7 +17,7 @@ import { validationParts, validationTypes } from '../../../../../../constants/up
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils'; import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
import { getLangText } from '../../../../../../utils/lang'; import { getLangText } from '../../../../../../utils/lang';
import requests from '../../../../../../utils/requests'; import { formatText } from '../../../../../../utils/text';
import { resolveUrl } from '../../../../../../utils/url_resolver'; import { resolveUrl } from '../../../../../../utils/url_resolver';
@ -80,11 +80,17 @@ let MarketAdditionalDataForm = React.createClass({
}); });
return { return {
extradata: extradata, extradata,
piece_id: this.props.pieceId piece_id: this.props.pieceId
}; };
}, },
getUrl() {
return formatText(resolveUrl('piece_extradata'), {
pieceId: this.props.pieceId
});
},
isUploadReadyOnChange() { isUploadReadyOnChange() {
return this.props.otherData && this.props.otherData.length; return this.props.otherData && this.props.otherData.length;
}, },
@ -152,7 +158,7 @@ let MarketAdditionalDataForm = React.createClass({
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref='form' ref='form'
key={this.state.forceUpdateKey} key={this.state.forceUpdateKey}
url={requests.prepareUrl(resolveUrl('piece_extradata'), { piece_id: pieceId })} url={this.getUrl()}
handleSuccess={showNotification ? this.handleSuccessWithNotification : handleSuccess} handleSuccess={showNotification ? this.handleSuccessWithNotification : handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}
buttons={buttons} buttons={buttons}

View File

@ -7,25 +7,25 @@ function getWalletApiUrls(subdomain) {
if (subdomain === 'cyland') { if (subdomain === 'cyland') {
return { return {
'pieces_list': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/', 'pieces_list': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${piece_id}/', 'piece': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${pieceId}/',
'piece_extradata': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${piece_id}/extradata/', 'piece_extradata': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${pieceId}/extradata/',
'user': walletConstants.walletApiEndpoint + '/' + subdomain + '/users/' 'user': walletConstants.walletApiEndpoint + '/' + subdomain + '/users/'
}; };
} else if (subdomain === 'ikonotv') { } else if (subdomain === 'ikonotv') {
return { return {
'pieces_list': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/', 'pieces_list': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${piece_id}/', 'piece': walletConstants.walletApiEndpoint + '/' + subdomain + '/pieces/${pieceId}/',
'user': walletConstants.walletApiEndpoint + '/' + subdomain + '/users/' 'user': walletConstants.walletApiEndpoint + '/' + subdomain + '/users/'
}; };
} else if (subdomain === 'lumenus' || subdomain === '23vivi' || } else if (subdomain === 'lumenus' || subdomain === '23vivi' ||
subdomain === 'polline' || subdomain === 'artcity' || subdomain === 'polline' || subdomain === 'artcity' ||
subdomain === 'demo' || subdomain === 'liquidgallery') { subdomain === 'demo' || subdomain === 'liquidgallery') {
return { return {
'editions_list': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${piece_id}/editions/', 'editions_list': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${pieceId}/editions/',
'edition': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/editions/${bitcoin_id}/', 'edition': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/editions/${bitcoinId}/',
'pieces_list': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/', 'pieces_list': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${piece_id}/', 'piece': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${pieceId}/',
'piece_extradata': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${piece_id}/extradata/', 'piece_extradata': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/pieces/${pieceId}/extradata/',
'user': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/users/' 'user': walletConstants.walletApiEndpoint + '/markets/' + subdomain + '/users/'
}; };
} }

View File

@ -11,24 +11,24 @@ const ApiUrls = {
'coa': AppConstants.apiEndpoint + '/coa/${id}/', 'coa': AppConstants.apiEndpoint + '/coa/${id}/',
'coa_create': AppConstants.apiEndpoint + '/coa/', 'coa_create': AppConstants.apiEndpoint + '/coa/',
'coa_verify': AppConstants.apiEndpoint + '/coa/verify_coa/', 'coa_verify': AppConstants.apiEndpoint + '/coa/verify_coa/',
'edition': AppConstants.apiEndpoint + '/editions/${bitcoin_id}/', 'edition': AppConstants.apiEndpoint + '/editions/${bitcoinId}/',
'edition_delete': AppConstants.apiEndpoint + '/editions/${edition_id}/', 'edition_delete': AppConstants.apiEndpoint + '/editions/${editionId}/',
'edition_remove_from_collection': AppConstants.apiEndpoint + '/ownership/shares/editions/${edition_id}/', 'edition_remove_from_collection': AppConstants.apiEndpoint + '/ownership/shares/editions/${editionId}/',
'editions': AppConstants.apiEndpoint + '/editions/', // this should be moved to the one below 'editions': AppConstants.apiEndpoint + '/editions/', // this should be moved to the one below
'editions_list': AppConstants.apiEndpoint + '/pieces/${piece_id}/editions/', 'editions_list': AppConstants.apiEndpoint + '/pieces/${pieceId}/editions/',
'licenses': AppConstants.apiEndpoint + '/ownership/licenses/', 'licenses': AppConstants.apiEndpoint + '/ownership/licenses/',
'note_private_edition': AppConstants.apiEndpoint + '/note/private/editions/', 'note_private_edition': AppConstants.apiEndpoint + '/note/private/editions/',
'note_private_piece': AppConstants.apiEndpoint + '/note/private/pieces/', 'note_private_piece': AppConstants.apiEndpoint + '/note/private/pieces/',
'note_public_edition': AppConstants.apiEndpoint + '/note/public/editions/', 'note_public_edition': AppConstants.apiEndpoint + '/note/public/editions/',
'note_public_piece': AppConstants.apiEndpoint + '/note/public/pieces/', 'note_public_piece': AppConstants.apiEndpoint + '/note/public/pieces/',
'notification_piecelist': AppConstants.apiEndpoint + '/notifications/pieces/', 'notification_piecelist': AppConstants.apiEndpoint + '/notifications/pieces/',
'notification_piece': AppConstants.apiEndpoint + '/notifications/pieces/${piece_id}/', 'notification_piece': AppConstants.apiEndpoint + '/notifications/pieces/${pieceId}/',
'notification_editionlist': AppConstants.apiEndpoint + '/notifications/editions/', 'notification_editionlist': AppConstants.apiEndpoint + '/notifications/editions/',
'notification_edition': AppConstants.apiEndpoint + '/notifications/editions/${edition_id}/', 'notification_edition': AppConstants.apiEndpoint + '/notifications/editions/${editionId}/',
'notification_contractagreementlist': AppConstants.apiEndpoint + '/notifications/contract_agreements/', 'notification_contract_agreement_list': AppConstants.apiEndpoint + '/notifications/contract_agreements/',
'ownership_contract_agreements': AppConstants.apiEndpoint + '/ownership/contract_agreements/', 'ownership_contract_agreements': AppConstants.apiEndpoint + '/ownership/contract_agreements/',
'ownership_contract_agreements_confirm': AppConstants.apiEndpoint + '/ownership/contract_agreements/${contract_agreement_id}/accept/', 'ownership_contract_agreements_confirm': AppConstants.apiEndpoint + '/ownership/contract_agreements/${contractAgreementId}/accept/',
'ownership_contract_agreements_deny': AppConstants.apiEndpoint + '/ownership/contract_agreements/${contract_agreement_id}/reject/', 'ownership_contract_agreements_deny': AppConstants.apiEndpoint + '/ownership/contract_agreements/${contractAgreementId}/reject/',
'ownership_consigns': AppConstants.apiEndpoint + '/ownership/consigns/', 'ownership_consigns': AppConstants.apiEndpoint + '/ownership/consigns/',
'ownership_consigns_confirm': AppConstants.apiEndpoint + '/ownership/consigns/confirm/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + '/ownership/consigns/confirm/',
'ownership_consigns_deny': AppConstants.apiEndpoint + '/ownership/consigns/deny/', 'ownership_consigns_deny': AppConstants.apiEndpoint + '/ownership/consigns/deny/',
@ -49,12 +49,12 @@ const ApiUrls = {
'ownership_unconsigns': AppConstants.apiEndpoint + '/ownership/unconsigns/', 'ownership_unconsigns': AppConstants.apiEndpoint + '/ownership/unconsigns/',
'ownership_unconsigns_deny': AppConstants.apiEndpoint + '/ownership/unconsigns/deny/', 'ownership_unconsigns_deny': AppConstants.apiEndpoint + '/ownership/unconsigns/deny/',
'ownership_unconsigns_request': AppConstants.apiEndpoint + '/ownership/unconsigns/request/', 'ownership_unconsigns_request': AppConstants.apiEndpoint + '/ownership/unconsigns/request/',
'ownership_contract': AppConstants.apiEndpoint + '/ownership/contracts/${contract_id}/', 'ownership_contract': AppConstants.apiEndpoint + '/ownership/contracts/${contractId}/',
'ownership_contract_list': AppConstants.apiEndpoint + '/ownership/contracts/', 'ownership_contract_list': AppConstants.apiEndpoint + '/ownership/contracts/',
'piece': AppConstants.apiEndpoint + '/pieces/${piece_id}/', 'piece': AppConstants.apiEndpoint + '/pieces/${pieceId}/',
'piece_extradata': AppConstants.apiEndpoint + '/pieces/${piece_id}/extradata/', 'piece_extradata': AppConstants.apiEndpoint + '/pieces/${pieceId}/extradata/',
'pieces_list': AppConstants.apiEndpoint + '/pieces/', 'pieces_list': AppConstants.apiEndpoint + '/pieces/',
'piece_remove_from_collection': AppConstants.apiEndpoint + '/ownership/shares/pieces/${piece_id}/', 'piece_remove_from_collection': AppConstants.apiEndpoint + '/ownership/shares/pieces/${pieceId}/',
'user': AppConstants.apiEndpoint + '/users/', 'user': AppConstants.apiEndpoint + '/users/',
'users_login': AppConstants.apiEndpoint + '/users/login/', 'users_login': AppConstants.apiEndpoint + '/users/login/',
'users_logout': AppConstants.apiEndpoint + '/users/logout/', 'users_logout': AppConstants.apiEndpoint + '/users/logout/',
@ -64,7 +64,7 @@ const ApiUrls = {
'users_username': AppConstants.apiEndpoint + '/users/username/', 'users_username': AppConstants.apiEndpoint + '/users/username/',
'users_profile': AppConstants.apiEndpoint + '/users/profile/', 'users_profile': AppConstants.apiEndpoint + '/users/profile/',
'wallet_settings': AppConstants.apiEndpoint + '/users/wallet_settings/', 'wallet_settings': AppConstants.apiEndpoint + '/users/wallet_settings/',
'webhook': AppConstants.apiEndpoint + '/webhooks/${webhook_id}/', 'webhook': AppConstants.apiEndpoint + '/webhooks/${webhookId}/',
'webhooks': AppConstants.apiEndpoint + '/webhooks/', 'webhooks': AppConstants.apiEndpoint + '/webhooks/',
'webhooks_events': AppConstants.apiEndpoint + '/webhooks/events/', 'webhooks_events': AppConstants.apiEndpoint + '/webhooks/events/',
'whitelabel_settings': AppConstants.apiEndpoint + '/whitelabel/settings/${subdomain}/', 'whitelabel_settings': AppConstants.apiEndpoint + '/whitelabel/settings/${subdomain}/',

View File

@ -1,16 +1,20 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
let ApplicationFetcher = { let ApplicationFetcher = {
/** /**
* Fetch the registered applications of a user from the API. * Fetch the registered applications of a user from the API.
*/ */
fetch() { fetch() {
return requests.get('applications'); return request('applications');
}, },
refreshToken(applicationName) { refreshToken(applicationName) {
return requests.post('application_token_refresh', { body: {'name': applicationName}}); return request('application_token_refresh', {
method: 'POST',
jsonBody: { name: applicationName }
});
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import { safeMerge } from '../utils/general'; import { safeMerge } from '../utils/general';
import { generateOrderingQueryParams } from '../utils/url'; import { generateOrderingQueryParams } from '../utils/url';
@ -11,18 +11,19 @@ let EditionListFetcher = {
*/ */
fetch({ pieceId, page, pageSize, orderBy, orderAsc, filterBy }) { fetch({ pieceId, page, pageSize, orderBy, orderAsc, filterBy }) {
const ordering = generateOrderingQueryParams(orderBy, orderAsc); const ordering = generateOrderingQueryParams(orderBy, orderAsc);
const query = safeMerge(
const queryParams = safeMerge(
{ {
page, page,
pageSize, pageSize,
ordering, ordering
piece_id: pieceId
}, },
filterBy filterBy
); );
return requests.get('editions_list', queryParams); return request('editions_list', {
query,
urlTemplateSpec: { pieceId }
});
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import { getCurrentSubdomain } from '../utils/url'; import { getCurrentSubdomain } from '../utils/url';
@ -10,7 +10,11 @@ let LicenseFetcher = {
* Fetch the available licenses from the API (might be bound to the subdomain e.g. cc.ascribe.io). * Fetch the available licenses from the API (might be bound to the subdomain e.g. cc.ascribe.io).
*/ */
fetch() { fetch() {
return requests.get('licenses', { 'subdomain': getCurrentSubdomain() }); const query = {
subdomain: getCurrentSubdomain()
};
return request('licenses', { query });
} }
}; };

View File

@ -1,28 +1,31 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
let NotificationFetcher = { let NotificationFetcher = {
fetchPieceListNotifications() { fetchPieceListNotifications() {
return requests.get('notification_piecelist'); return request('notification_piecelist');
}, },
fetchPieceNotifications(pieceId) { fetchPieceNotifications(pieceId) {
return requests.get('notification_piece', {'piece_id': pieceId}); return request('notification_piece', {
urlTemplateSpec: { pieceId }
});
}, },
fetchEditionListNotifications() { fetchEditionListNotifications() {
return requests.get('notification_editionlist'); return request('notification_editionlist');
}, },
fetchEditionNotifications(editionId) { fetchEditionNotifications(editionId) {
return requests.get('notification_edition', {'edition_id': editionId}); return request('notification_edition', {
urlTemplateSpec: { editionId }
});
}, },
fetchContractAgreementListNotifications() { fetchContractAgreementListNotifications() {
return requests.get('notification_contractagreementlist'); return request('notification_contract_agreement_list');
} }
}; };

View File

@ -1,27 +1,25 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
// FIXME: fix query string usage
let OwnershipFetcher = { let OwnershipFetcher = {
/** /**
* Fetch the default, public contract of a user from the API. * Fetch the default, public contract of a user from the API.
*/ */
fetchContract(loanee) { fetchContract(loanee) {
return requests.get('blob_contracts', { loanee }); return request('blob_contracts', {
query: { loanee }
});
}, },
/** /**
* Fetch the contracts of the logged-in user from the API. * Fetch the contracts of the logged-in user from the API.
*/ */
fetchContractList(isActive, isPublic, issuer) { fetchContractList(isActive, isPublic, issuer) {
let queryParams = { const query = { isActive, isPublic, issuer };
isActive,
isPublic, return request('ownership_contract_list', { query });
issuer
};
return requests.get('ownership_contract_list', queryParams);
}, },
@ -29,39 +27,61 @@ let OwnershipFetcher = {
* Create a contractagreement between the logged-in user and the email from the API with contract. * Create a contractagreement between the logged-in user and the email from the API with contract.
*/ */
createContractAgreement(signee, contractObj) { createContractAgreement(signee, contractObj) {
return requests.post('ownership_contract_agreements', { body: {signee: signee, contract: contractObj.id }}); return request('ownership_contract_agreements', {
method: 'POST',
jsonBody: {
signee,
contract: contractObj.id
}
});
}, },
/** /**
* Fetch the contractagreement between the logged-in user and the email from the API. * Fetch the contractagreement between the logged-in user and the email from the API.
*/ */
fetchContractAgreementList(issuer, accepted, pending) { fetchContractAgreementList(issuer, accepted, pending) {
let queryParams = { const query = { issuer, accepted, pending };
issuer,
accepted, return request('ownership_contract_agreements', { query });
pending
};
return requests.get('ownership_contract_agreements', queryParams);
}, },
confirmContractAgreement(contractAgreement) { confirmContractAgreement(contractAgreement) {
return requests.put('ownership_contract_agreements_confirm', {contract_agreement_id: contractAgreement.id}); return request('ownership_contract_agreements_confirm', {
method: 'PUT',
urlTemplateSpec: {
contractAgreementId: contractAgreement.id
}
});
}, },
denyContractAgreement(contractAgreement) { denyContractAgreement(contractAgreement) {
return requests.put('ownership_contract_agreements_deny', {contract_agreement_id: contractAgreement.id}); return request('ownership_contract_agreements_deny', {
method: 'PUT',
urlTemplateSpec: {
contractAgreementId: contractAgreement.id
}
});
}, },
fetchLoanPieceRequestList() { fetchLoanPieceRequestList() {
return requests.get('ownership_loans_pieces_request'); return request('ownership_loans_pieces_request');
}, },
changeContract(contractObj) { changeContract(contractObj) {
return requests.put('ownership_contract', { body: contractObj, contract_id: contractObj.id }); return request('ownership_contract', {
method: 'PUT',
jsonBody: contractObj,
urlTemplateSpec: {
contractId: contractObj.id
}
});
}, },
deleteContract(contractObjId) { deleteContract(contractId) {
return requests.delete('ownership_contract', {contract_id: contractObjId}); return request('ownership_contract', {
method: 'DELETE',
urlTemplateSpec: { contractId }
});
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import { safeMerge } from '../utils/general'; import { safeMerge } from '../utils/general';
import { generateOrderingQueryParams } from '../utils/url'; import { generateOrderingQueryParams } from '../utils/url';
@ -15,7 +15,7 @@ let PieceListFetcher = {
// filterBy is an object of acl key-value pairs. // filterBy is an object of acl key-value pairs.
// The values are booleans // The values are booleans
const queryParams = safeMerge( const query = safeMerge(
{ {
page, page,
pageSize, pageSize,
@ -25,11 +25,11 @@ let PieceListFetcher = {
filterBy filterBy
); );
return requests.get('pieces_list', queryParams); return request('pieces_list', { query });
}, },
fetchRequestActions() { fetchRequestActions() {
return requests.get('pieces_list_request_actions'); return request('pieces_list_request_actions');
} }
}; };

View File

@ -1,22 +1,21 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
let S3Fetcher = { let S3Fetcher = {
/** /**
* Fetch the registered applications of a user from the API. * Fetch the registered applications of a user from the API.
*/ */
deleteFile(key, bucket) { deleteFile(key, bucket) {
return requests.delete('delete_s3_file', { return request('delete_s3_file', {
key, method: 'DELETE',
bucket query: { bucket, key }
}); });
}, },
signUrl(key, title, artistName) { signUrl(key, title, artistName) {
return requests.get('sign_url_s3', { return request('sign_url_s3', {
key, query: { artistName, key, title }
title,
'artist_name': artistName
}); });
} }
}; };

View File

@ -1,11 +1,11 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
let WalletSettingsFetcher = { let WalletSettingsFetcher = {
fetchOne() { fetchOne() {
return requests.get('wallet_settings'); return request('wallet_settings');
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import EditionActions from '../actions/edition_actions'; import EditionActions from '../actions/edition_actions';
@ -8,12 +8,14 @@ import EditionActions from '../actions/edition_actions';
const CoaSource = { const CoaSource = {
lookupCoa: { lookupCoa: {
remote(state, coaId) { remote(state, coaId) {
return requests return request('coa', {
.get('coa', { id: coaId }) urlTemplateSpec: {
.then((res) => { id: coaId
}
}).then((res) => (
// If no coa is found here, fake a 404 error so the error action can pick it up // If no coa is found here, fake a 404 error so the error action can pick it up
return (res && res.coa) ? res : Promise.reject({ json: { status: 404 } }); (res && res.coa) ? res : Promise.reject({ json: { status: 404 } })
}); ));
}, },
success: EditionActions.successFetchCoa, success: EditionActions.successFetchCoa,
@ -22,7 +24,10 @@ const CoaSource = {
performCreateCoaForEdition: { performCreateCoaForEdition: {
remote(state, editionId) { remote(state, editionId) {
return requests.post('coa_create', { body: { bitcoin_id: editionId } }); return request('coa_create', {
method: 'POST',
jsonBody: { bitcoin_id: editionId }
});
}, },
success: EditionActions.successFetchCoa, success: EditionActions.successFetchCoa,

View File

@ -1,14 +1,16 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import EditionActions from '../actions/edition_actions'; import EditionActions from '../actions/edition_actions';
const EditionSource = { const EditionSource = {
lookupEdition: { lookupEdition: {
remote(state, editionId) { remote(state, bitcoinId) {
return requests.get('edition', { bitcoin_id: editionId }); return request('edition', {
urlTemplateSpec: { bitcoinId }
});
}, },
success: EditionActions.successFetchEdition, success: EditionActions.successFetchEdition,

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import PieceActions from '../actions/piece_actions'; import PieceActions from '../actions/piece_actions';
@ -8,7 +8,9 @@ import PieceActions from '../actions/piece_actions';
const PieceSource = { const PieceSource = {
lookupPiece: { lookupPiece: {
remote(state, pieceId) { remote(state, pieceId) {
return requests.get('piece', { piece_id: pieceId }); return request('piece', {
urlTemplateSpec: { pieceId }
});
}, },
success: PieceActions.successFetchPiece, success: PieceActions.successFetchPiece,

View File

@ -2,13 +2,13 @@
import UserActions from '../actions/user_actions'; import UserActions from '../actions/user_actions';
import requests from '../utils/requests'; import request from '../utils/request';
const UserSource = { const UserSource = {
lookupCurrentUser: { lookupCurrentUser: {
remote() { remote() {
return requests.get('user'); return request('user');
}, },
local(state) { local(state) {
@ -25,7 +25,7 @@ const UserSource = {
performLogoutCurrentUser: { performLogoutCurrentUser: {
remote() { remote() {
return requests.get('users_logout'); return request('users_logout');
}, },
success: UserActions.successLogoutCurrentUser, success: UserActions.successLogoutCurrentUser,

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import WebhookActions from '../actions/webhook_actions'; import WebhookActions from '../actions/webhook_actions';
@ -8,7 +8,7 @@ import WebhookActions from '../actions/webhook_actions';
const WebhookSource = { const WebhookSource = {
lookupWebhooks: { lookupWebhooks: {
remote() { remote() {
return requests.get('webhooks'); return request('webhooks');
}, },
local(state) { local(state) {
@ -25,7 +25,7 @@ const WebhookSource = {
lookupWebhookEvents: { lookupWebhookEvents: {
remote() { remote() {
return requests.get('webhooks_events'); return request('webhooks_events');
}, },
local(state) { local(state) {
@ -42,7 +42,10 @@ const WebhookSource = {
performRemoveWebhook: { performRemoveWebhook: {
remote(state, webhookId) { remote(state, webhookId) {
return requests.delete('webhook', { 'webhook_id': webhookId }); return request('webhook', {
method: 'DELETE',
urlTemplateSpec: { webhookId }
});
}, },
success: WebhookActions.successRemoveWebhook, success: WebhookActions.successRemoveWebhook,

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import requests from '../utils/requests'; import request from '../utils/request';
import WhitelabelActions from '../actions/whitelabel_actions'; import WhitelabelActions from '../actions/whitelabel_actions';
import { getCurrentSubdomain } from '../utils/url'; import { getCurrentSubdomain } from '../utils/url';
@ -9,7 +9,11 @@ import { getCurrentSubdomain } from '../utils/url';
const WhitelabelSource = { const WhitelabelSource = {
lookupWhitelabel: { lookupWhitelabel: {
remote() { remote() {
return requests.get('whitelabel_settings', { 'subdomain': getCurrentSubdomain() }); return request('whitelabel_settings', {
urlTemplateSpec: {
subdomain: getCurrentSubdomain()
}
});
}, },
local(state) { local(state) {

View File

@ -1,172 +1,94 @@
'use strict'; import { request as baseRequest, sanitize } from 'js-utility-belt/es6';
import Q from 'q'; import { makeCsrfHeader } from './csrf';
import { resolveUrl } from './url_resolver';
import AppConstants from '../constants/application_constants';
import { getCookie } from '../utils/fetch_api';
import { omitFromObject } from '../utils/general';
import { stringifyAsQueryParam } from '../utils/url';
class Requests { const DEFAULT_REQUEST_CONFIG = {
unpackResponse(url) { credentials: 'include',
return (response) => { headers: {
if (response == null) { 'Accept': 'application/json',
throw new Error(`For: ${url} - Server did not respond to the request. (Not even displayed a 500)`); 'Content-Type': 'application/json'
}
};
/**
* Small wrapper around js-utility-belt's request that provides default settings, url mapping, and
* response handling.
*/
export default function request(url, config) {
// Load default fetch configuration and remove any falsy query parameters
const requestConfig = Object.assign({}, DEFAULT_REQUEST_CONFIG, config, config && {
query: config.query && sanitize(config.query)
});
// Add CSRF token
Object.assign(requestConfig.headers, makeCsrfHeader());
// Resolve url and send request
return new Promise((resolve) => {
resolve(resolveUrl(url));
})
.then((apiUrl) => (
baseRequest(apiUrl, requestConfig)
// Catch any errors resulting from baseRequest first
.catch((res) => {
if (res == null) {
throw new Error(`For: ${apiUrl} - Server did not respond to the request. ` +
'(Not even displayed a 500)');
} else {
let err = new Error(`${res.status} - ${res.statusText} - on URL: ${res.url}`);
// Try to parse the response body to see if we added more descriptive errors
// before rejecting with the error above.
return res
.json()
.then((body) => {
if (body && Array.isArray(body.errors) && body.errors.length) {
err = new Error(body.errors.pop());
} }
if (response.status >= 500) { // ES6 promises don't have a .finally() clause so we fake that here
let err = new Error(`${response.status} - ${response.statusText} - on URL: ${response.url}`); // by forcing the .catch() clause to run
return response
.text()
.then((resText) => {
const resJson = JSON.parse(resText);
err = new Error(resJson.errors.pop());
// ES6 promises don't have a .finally() clause so we fake that here by
// forcing the .catch() clause to run
return Promise.reject(); return Promise.reject();
}) })
// If parsing the resText throws, just rethrow the original error we created // If parsing the response body throws, just rethrow the original error
.catch(() => { throw err; }); .catch(() => { throw err; });
} }
})
// Handle successful requests
.then((res) => res
.json()
.then((body) => {
if (body) {
let error;
return Q.Promise((resolve, reject) => { if (body.errors) {
response.text() error = new Error('Form Error');
.then((responseText) => {
// If the responses' body does not contain any data,
// fetch will resolve responseText to the string 'None'.
// If this is the case, we can not try to parse it as JSON.
if (responseText && responseText !== 'None') {
const body = JSON.parse(responseText);
if (body && body.errors) {
const error = new Error('Form Error');
error.json = body; error.json = body;
reject(error); } else if (body.detail) {
} else if (body && body.detail) { error = Error(body.detail);
reject(new Error(body.detail)); } else if ('success' in body && !body.success) {
} else if (body && 'success' in body && !body.success) { const { status, statusText, type, url: resUrl } = res;
const error = new Error('Client Request Error');
error.json = { error = new Error('Client Request Error');
body: body, error.json = { body, status, statusText, type, url: resUrl };
status: response.status, }
statusText: response.statusText,
type: response.type, if (error) {
url: response.url throw error;
};
reject(error);
} else { } else {
resolve(body); return body;
} }
} else if (response.status >= 400) {
reject(new Error(`${response.status} - ${response.statusText} - on URL: ${response.url}`));
} else { } else {
resolve({}); return {};
} }
}).catch(reject); })
}); )
}; ))
} // Log any errors and rethrow
.catch((err) => {
getUrl(url) { console.error(err);
// Handle case, that the url string is not defined at all
if (!url) {
throw new Error('Url was not defined and could therefore not be mapped.');
}
let name = url;
if (!url.match(/^http/)) {
url = this.urlMap[url];
if (!url) {
throw new Error(`Cannot find a mapping for "${name}"`);
}
}
return url;
}
prepareUrl(url, params, attachParamsToQuery) {
let newUrl;
let re = /\${(\w+)}/g;
// catch errors and throw them to react
try {
newUrl = this.getUrl(url);
} catch(err) {
throw err; throw err;
}
newUrl = newUrl.replace(re, (match, key) => {
let val = params[key];
if (!val) {
throw new Error(`Cannot find param ${key}`);
}
delete params[key];
return val;
}); });
if (attachParamsToQuery && params && Object.keys(params).length > 0) {
newUrl += stringifyAsQueryParam(params);
}
return newUrl;
}
request(verb, url, options = {}) {
let merged = Object.assign({}, this.httpOptions, options);
let csrftoken = getCookie(AppConstants.csrftoken);
if (csrftoken) {
merged.headers['X-CSRFToken'] = csrftoken;
}
merged.method = verb;
return fetch(url, merged)
.then(this.unpackResponse(url));
}
get(url, params) {
if (url === undefined) {
throw new Error('Url undefined');
}
let paramsCopy = Object.assign({}, params);
let newUrl = this.prepareUrl(url, paramsCopy, true);
return this.request('get', newUrl);
}
delete(url, params) {
let paramsCopy = Object.assign({}, params);
let newUrl = this.prepareUrl(url, paramsCopy, true);
return this.request('delete', newUrl);
}
_putOrPost(url, paramsAndBody, method) {
let params = omitFromObject(paramsAndBody, ['body']);
let newUrl = this.prepareUrl(url, params);
let body = paramsAndBody && paramsAndBody.body ? JSON.stringify(paramsAndBody.body)
: null;
return this.request(method, newUrl, { body });
}
post(url, params) {
return this._putOrPost(url, params, 'post');
}
put(url, params) {
return this._putOrPost(url, params, 'put');
}
patch(url, params) {
return this._putOrPost(url, params, 'patch');
}
defaults(options) {
this.httpOptions = options.http || {};
this.urlMap = options.urlMap || {};
}
} }
let requests = new Requests();
export default requests;