Merge branch 'master' into AD-350-integrate-localization

This commit is contained in:
Tim Daubenschütz 2015-06-02 13:10:12 +02:00
commit a19ea989ef
15 changed files with 178 additions and 84 deletions

View File

@ -14,6 +14,7 @@ class PieceListActions {
PieceListFetcher
.fetch(page, pageSize, search, orderBy, orderAsc)
.then((res) => {
console.log(res);
this.actions.updatePieceList({
page,
pageSize,
@ -23,9 +24,6 @@ class PieceListActions {
'pieceList': res.pieces,
'pieceListCount': res.count
});
})
.catch((err) => {
console.log(err);
});
}

View File

@ -2,12 +2,34 @@
import React from 'react';
import Router from 'react-router';
import promise from 'es6-promise';
promise.polyfill();
import AscribeApp from './components/ascribe_app';
import AppConstants from './constants/application_constants';
import ApiUrls from './constants/api_urls';
import routes from './routes';
import alt from './alt';
import fetch from './utils/fetch';
import AlertDismissable from './components/ascribe_forms/alert';
fetch.defaults({
urlMap: ApiUrls,
http: {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
},
fatalErrorHandler: (err) => {
console.log(err);
//alert('Something went wrong, please reload the page');
}
});
Router.run(routes, Router.HashLocation, (AscribeApp) => {
React.render(
<AscribeApp />,

View File

@ -28,4 +28,4 @@ let AlertDismissable = React.createClass({
}
});
export default AlertDismissable;
export default AlertDismissable;

View File

@ -1,5 +1,4 @@
import React from 'react';
import ImageViewer from './ascribe_media/image_viewer';
import TransferModalButton from './ascribe_modal/modal_transfer';
import ShareModalButton from './ascribe_modal/modal_share';

View File

View File

@ -2,7 +2,15 @@ import AppConstants from './application_constants';
let apiUrls = {
'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/',
'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/'
'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/',
'user': AppConstants.baseUrl + 'users/',
'pieces_list': AppConstants.baseUrl + 'pieces/',
'piece': AppConstants.baseUrl + 'pieces/${piece_id}',
'edition': AppConstants.baseUrl + 'editions/${bitcoin_id}/',
'editions_list': AppConstants.baseUrl + 'pieces/${piece_id}/editions/'
};
export default apiUrls;
export default apiUrls;

View File

@ -5,4 +5,4 @@ let constants = {
'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection']
};
export default constants;
export default constants;

View File

@ -1,4 +1,4 @@
import fetch from 'isomorphic-fetch';
import fetch from '../utils/fetch';
import AppConstants from '../constants/application_constants';
import FetchApiUtils from '../utils/fetch_api_utils';
@ -11,13 +11,7 @@ let EditionFetcher = {
*
*/
fetchOne(editionId) {
return fetch(AppConstants.baseUrl + 'editions/' + editionId + '/', {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
}
}).then(
(res) => res.json()
);
return fetch.get('edition', {'bitcoin_id': editionId});
}
};

View File

@ -1,4 +1,4 @@
import fetch from 'isomorphic-fetch';
import fetch from '../utils/fetch';
import AppConstants from '../constants/application_constants';
@ -8,13 +8,8 @@ let EditionListFetcher = {
* Fetches a list of editions from the API.
*/
fetch(pieceId) {
return fetch(AppConstants.baseUrl + 'pieces/' + pieceId + '/editions/', {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
}
}).then((res) => res.json());
return fetch.get('editions_list', { 'piece_id': pieceId });
}
};
export default EditionListFetcher;
export default EditionListFetcher;

View File

@ -1,7 +1,6 @@
import fetch from 'isomorphic-fetch';
import fetch from '../utils/fetch';
import AppConstants from '../constants/application_constants';
import FetchApiUtils from '../utils/fetch_api_utils';
let PieceFetcher = {
@ -11,11 +10,7 @@ let PieceFetcher = {
*
*/
fetchOne(pieceId) {
return fetch(AppConstants.baseUrl + 'pieces/' + pieceId + '/', {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
}
}).then((res) => res.json());
return fetch.get('piece');
}
};

View File

@ -1,7 +1,6 @@
import fetch from 'isomorphic-fetch';
import AppConstants from '../constants/application_constants';
import FetchApiUtils from '../utils/fetch_api_utils';
import fetch from '../utils/fetch';
let PieceListFetcher = {
@ -10,21 +9,8 @@ let PieceListFetcher = {
* Can be called with all supplied queryparams the API.
*/
fetch(page, pageSize, search, orderBy, orderAsc) {
let ordering = FetchApiUtils.generateOrderingQueryParams(orderBy, orderAsc);
let params = FetchApiUtils.argsToQueryParams({
page,
pageSize,
search,
ordering
});
return fetch(AppConstants.baseUrl + 'pieces/' + params, {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
}
}).then((res) => res.json());
return fetch.get('pieces_list', { page, pageSize, search, ordering });
}
};

View File

@ -1,4 +1,4 @@
import fetch from 'isomorphic-fetch';
import fetch from '../utils/fetch';
import AppConstants from '../constants/application_constants';
import FetchApiUtils from '../utils/fetch_api_utils';
@ -11,11 +11,7 @@ let UserFetcher = {
*
*/
fetchOne() {
return fetch(AppConstants.baseUrl + 'users/', {
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
}
}).then((res) => res.json());
return fetch.get('user');
}
};

View File

@ -1,3 +1,4 @@
import fetch from '../utils/fetch';
import React from 'react';
import AppConstants from '../constants/application_constants'
@ -10,45 +11,30 @@ export const FormMixin = {
, status: null
}
},
submit(e) {
e.preventDefault();
this.setState({submitted: true});
fetch(this.url(), {
method: 'post',
headers: {
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(this.getFormData())
})
.then(
(response) => this.handleResponse(response)
);
fetch
.post(this.url(), { body: this.getFormData() })
.then(response => { this.props.onRequestHide(); })
.catch(this.handleError);
},
handleResponse(response){
if (response.status >= 200 && response.status < 300){
this.props.onRequestHide();
}
else if (response.status >= 400 && response.status < 500) {
this.handleError(response);
}
else {
handleError(err){
if (err.json) {
for (var input in errors){
if (this.refs && this.refs[input] && this.refs[input].state) {
this.refs[input].setAlerts(errors[input]);
}
}
this.setState({submitted: false});
} else {
this.setState({submitted: false, status: response.status});
}
},
handleError(response){
response.json().then((response) => this.dispatchErrors(response.errors));
},
dispatchErrors(errors){
for (var input in errors){
if (this.refs && this.refs[input] && this.refs[input].state){
this.refs[input].setAlerts(errors[input]);
}
}
this.setState({submitted: false});
},
render(){
let alert = null;
if (this.state.status >= 500){

113
js/utils/fetch.js Normal file
View File

@ -0,0 +1,113 @@
import { default as _fetch } from 'isomorphic-fetch';
import FetchApiUtils from '../utils/fetch_api_utils';
class UrlMapError extends Error {};
class ServerError extends Error {};
class APIError extends Error {};
class Fetch {
_merge(defaults, options) {
let merged = {};
for (let key in defaults) {
merged[key] = defaults[key];
}
for (let key in options) {
merged[key] = options[key];
}
return merged;
}
unpackResponse(response) {
if (response.status >= 500) {
throw new ServerError();
}
return response.text();
}
handleFatalError(err) {
this.fatalErrorHandler(err);
throw new ServerError(err);
}
handleAPIError(json) {
if (!json['success']) {
let error = new APIError();
error.json = json;
throw error;
}
return json;
}
getUrl(url) {
let name = url;
if (!url.match(/^http/)) {
url = this.urlMap[url];
if (!url) {
throw new UrlMapError(`Cannot find a mapping for "${name}"`);
}
}
return url;
}
prepareUrl(url, params, attachParamsToQuery) {
let newUrl = this.getUrl(url);
let re = /\${(\w+)}/g;
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 += FetchApiUtils.argsToQueryParams(params);
}
return newUrl;
}
request(verb, url, options) {
options = options || {};
let merged = this._merge(this.httpOptions, options);
merged['method'] = verb;
return _fetch(url, merged)
.then(this.unpackResponse)
.then(JSON.parse)
.catch(this.handleFatalError.bind(this))
.then(this.handleAPIError);
}
get(url, params) {
let paramsCopy = this._merge(params);
let newUrl = this.prepareUrl(url, params);
return this.request('get', newUrl, true);
}
post(url, params) {
let paramsCopy = this._merge(params);
let newUrl = this.prepareUrl(url, params);
let body = null;
if (params['body']) {
body = JSON.stringify(params['body'])
}
return this.request('post', url, { body });
}
defaults(options) {
this.httpOptions = options.http || {};
this.urlMap = options.urlMap || {};
this.fatalErrorHandler = options.fatalErrorHandler || (() => {});
}
}
let fetch = new Fetch();
export default fetch;

View File

@ -5,6 +5,7 @@
"main": "js/app.js",
"author": "Ascribe",
"license": "Copyright",
"private": true,
"devDependencies": {
"babel-jest": "^4.0.0",
"babelify": "^6.1.2",
@ -29,6 +30,7 @@
"dependencies": {
"alt": "^0.16.5",
"classnames": "^1.2.2",
"es6-promise": "^2.1.1",
"isomorphic-fetch": "^2.0.2",
"object-assign": "^2.0.0",
"react": "^0.13.2",