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

Merge branch 'master' of bitbucket.org:ascribe/onion

This commit is contained in:
Tim Daubenschütz 2015-06-17 15:40:26 +02:00
commit 3538585448
16 changed files with 90 additions and 43 deletions

View File

@ -5,17 +5,19 @@ import Router from 'react-router';
import promise from 'es6-promise'; import promise from 'es6-promise';
promise.polyfill(); promise.polyfill();
import fetch from 'isomorphic-fetch';
//require('isomorphic-fetch');
import ApiUrls from './constants/api_urls'; import ApiUrls from './constants/api_urls';
import routes from './routes'; import routes from './routes';
import fetch from './utils/fetch'; import requests from './utils/requests';
let headers = { let headers = {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}; };
fetch.defaults({ requests.defaults({
urlMap: ApiUrls, urlMap: ApiUrls,
http: { http: {
headers: headers, headers: headers,

View File

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import fetch from '../../utils/fetch'; import requests from '../../utils/requests';
import ApiUrls from '../../constants/api_urls'; import ApiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin'; import FormMixin from '../../mixins/form_mixin';
@ -11,7 +11,7 @@ let EditionDeleteForm = React.createClass({
mixins: [FormMixin], mixins: [FormMixin],
url() { url() {
return fetch.prepareUrl(ApiUrls.edition_delete, {edition_id: this.getBitcoinIds().join()}); return requests.prepareUrl(ApiUrls.edition_delete, {edition_id: this.getBitcoinIds().join()});
}, },
httpVerb(){ httpVerb(){
return 'delete'; return 'delete';

View File

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import fetch from '../../utils/fetch'; import requests from '../../utils/requests';
import apiUrls from '../../constants/api_urls'; import apiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin'; import FormMixin from '../../mixins/form_mixin';
@ -14,7 +14,7 @@ let PieceExtraDataForm = React.createClass({
mixins: [FormMixin], mixins: [FormMixin],
url() { url() {
return fetch.prepareUrl(apiUrls.piece_extradata, {piece_id: this.props.editions[0].bitcoin_id}); return requests.prepareUrl(apiUrls.piece_extradata, {piece_id: this.props.editions[0].bitcoin_id});
}, },
getFormData() { getFormData() {
@ -27,16 +27,19 @@ let PieceExtraDataForm = React.createClass({
}, },
renderForm() { renderForm() {
let defaultValue = this.props.editions[0].extra_data[this.props.name] || '';
if (defaultValue.length === 0 && ~this.props.editable){
return null;
}
return ( return (
<form role="form" key={this.props.name}> <form role="form" key={this.props.name}>
<h5>{this.props.title}</h5> <h5>{this.props.title}</h5>
<InputTextAreaToggable <InputTextAreaToggable
ref={this.props.name} ref={this.props.name}
className="form-control" className="form-control"
defaultValue={this.props.editions[0].extra_data[this.props.name]} defaultValue={defaultValue}
rows={3} rows={3}
editable={true} editable={this.props.editable}
required="" required=""
onSubmit={this.submit} onSubmit={this.submit}
/> />

View File

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import fetch from '../../utils/fetch'; import requests from '../../utils/requests';
import apiUrls from '../../constants/api_urls'; import apiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin'; import FormMixin from '../../mixins/form_mixin';
@ -11,7 +11,7 @@ let EditionRemoveFromCollectionForm = React.createClass({
mixins: [FormMixin], mixins: [FormMixin],
url() { url() {
return fetch.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()}); return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
}, },
httpVerb(){ httpVerb(){
return 'delete'; return 'delete';

View File

@ -3,6 +3,7 @@
import React from 'react'; import React from 'react';
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin'; import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
import Panel from 'react-bootstrap/lib/Panel'; import Panel from 'react-bootstrap/lib/Panel';
import AppConstants from '../../constants/application_constants.js';
/** /**
* This is the component that implements display-specific functionality. * This is the component that implements display-specific functionality.
@ -43,11 +44,11 @@ let Image = React.createClass({
mixins: [InjectInHeadMixin], mixins: [InjectInHeadMixin],
componentDidMount() { componentDidMount() {
this.inject('http://code.jquery.com/jquery-2.1.4.min.js') this.inject('https://code.jquery.com/jquery-2.1.4.min.js')
.then(() => .then(() =>
Promise.all([ Promise.all([
this.inject('/static/thirdparty/shmui/shmui.css'), this.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/shmui.css'),
this.inject('/static/thirdparty/shmui/jquery.shmui.js') this.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/jquery.shmui.js')
]).then(() => { window.jQuery('.shmui-ascribe').shmui(); })); ]).then(() => { window.jQuery('.shmui-ascribe').shmui(); }));
}, },
@ -72,7 +73,7 @@ let Video = React.createClass({
}, },
componentDidMount() { componentDidMount() {
this.inject('http://code.jquery.com/jquery-2.1.4.min.js') this.inject('https://code.jquery.com/jquery-2.1.4.min.js')
.then(() => .then(() =>
Promise.all([ Promise.all([
this.inject('https://cdnjs.cloudflare.com/ajax/libs/mediaelement/2.17.0/mediaelement-and-player.min.js'), this.inject('https://cdnjs.cloudflare.com/ajax/libs/mediaelement/2.17.0/mediaelement-and-player.min.js'),

View File

@ -2,6 +2,9 @@
import React from 'react'; import React from 'react';
import UserActions from '../actions/user_actions';
import UserStore from '../stores/user_store';
import MediaPlayer from './ascribe_media/media_player'; import MediaPlayer from './ascribe_media/media_player';
import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin'; import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
@ -31,6 +34,23 @@ let Edition = React.createClass({
loadEdition: React.PropTypes.func loadEdition: React.PropTypes.func
}, },
getInitialState() {
return UserStore.getState();
},
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
},
componentWillUnmount() {
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() { render() {
let thumbnail = this.props.edition.thumbnail; let thumbnail = this.props.edition.thumbnail;
let mimetype = this.props.edition.digital_work.mime; let mimetype = this.props.edition.digital_work.mime;
@ -71,8 +91,10 @@ let Edition = React.createClass({
edition={this.props.edition} /> edition={this.props.edition} />
<CollapsibleEditionDetails <CollapsibleEditionDetails
title="Personal Note" title="Personal Note"
show={this.state.currentUser && true || false}
iconName="pencil"> iconName="pencil">
<EditionPersonalNote <EditionPersonalNote
currentUser={this.state.currentUser}
handleSuccess={this.props.loadEdition} handleSuccess={this.props.loadEdition}
edition={this.props.edition}/> edition={this.props.edition}/>
</CollapsibleEditionDetails> </CollapsibleEditionDetails>
@ -160,7 +182,7 @@ let EditionSummary = React.createClass({
status = <EditionDetailProperty label="STATUS" value={ this.props.edition.status.join().replace(/_/, ' ') } />; status = <EditionDetailProperty label="STATUS" value={ this.props.edition.status.join().replace(/_/, ' ') } />;
} }
let actions = null; let actions = null;
if (this.props.edition.request_action){ if (this.props.edition.request_action && this.props.edition.request_action.length > 0){
actions = ( actions = (
<RequestActionForm <RequestActionForm
editions={ [this.props.edition] } editions={ [this.props.edition] }
@ -372,6 +394,7 @@ let EditionFurtherDetails = React.createClass({
}, },
render() { render() {
let editable = this.props.edition.acl.indexOf('edit') > -1;
return ( return (
<Row> <Row>
<Col md={12} className="ascribe-edition-personal-note"> <Col md={12} className="ascribe-edition-personal-note">
@ -379,16 +402,19 @@ let EditionFurtherDetails = React.createClass({
name='artist_contact_info' name='artist_contact_info'
title='Artist Contact Info' title='Artist Contact Info'
handleSuccess={this.showNotification} handleSuccess={this.showNotification}
editable={editable}
editions={[this.props.edition]} /> editions={[this.props.edition]} />
<PieceExtraDataForm <PieceExtraDataForm
name='display_instructions' name='display_instructions'
title='Display Instructions' title='Display Instructions'
handleSuccess={this.showNotification} handleSuccess={this.showNotification}
editable={editable}
editions={[this.props.edition]} /> editions={[this.props.edition]} />
<PieceExtraDataForm <PieceExtraDataForm
name='technology_details' name='technology_details'
title='Technology Details' title='Technology Details'
handleSuccess={this.showNotification} handleSuccess={this.showNotification}
editable={editable}
editions={[this.props.edition]} /> editions={[this.props.edition]} />
</Col> </Col>
</Row> </Row>

View File

@ -24,6 +24,7 @@ import { getLangText } from '../utils/lang_utils';
let Link = Router.Link; let Link = Router.Link;
let Header = React.createClass({ let Header = React.createClass({
mixins: [Router.Navigation],
getInitialState() { getInitialState() {
return UserStore.getState(); return UserStore.getState();
@ -43,8 +44,7 @@ let Header = React.createClass({
}, },
refreshData(){ refreshData(){
UserActions.fetchCurrentUser(); location.reload();
PieceListActions.fetchPieceList(1, 10);
}, },
render() { render() {
let account = null; let account = null;

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
let EditionFetcher = { let EditionFetcher = {
/** /**
@ -8,7 +8,7 @@ let EditionFetcher = {
* If no arg is supplied, load the current user * If no arg is supplied, load the current user
*/ */
fetchOne(editionId) { fetchOne(editionId) {
return fetch.get('edition', {'bitcoin_id': editionId}); return requests.get('edition', {'bitcoin_id': editionId});
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import { generateOrderingQueryParams } from '../utils/fetch_api_utils';
@ -11,7 +11,7 @@ let EditionListFetcher = {
*/ */
fetch(pieceId, orderBy, orderAsc) { fetch(pieceId, orderBy, orderAsc) {
let ordering = generateOrderingQueryParams(orderBy, orderAsc); let ordering = generateOrderingQueryParams(orderBy, orderAsc);
return fetch.get('editions_list', { 'piece_id': pieceId, ordering }); return requests.get('editions_list', { 'piece_id': pieceId, ordering });
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
let PieceFetcher = { let PieceFetcher = {
@ -9,7 +9,7 @@ let PieceFetcher = {
* If no arg is supplied, load the current user * If no arg is supplied, load the current user
*/ */
fetchOne() { fetchOne() {
return fetch.get('piece'); return requests.get('piece');
} }
}; };

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import { generateOrderingQueryParams } from '../utils/fetch_api_utils';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
let PieceListFetcher = { let PieceListFetcher = {
@ -11,7 +11,7 @@ let PieceListFetcher = {
*/ */
fetch(page, pageSize, search, orderBy, orderAsc) { fetch(page, pageSize, search, orderBy, orderAsc) {
let ordering = generateOrderingQueryParams(orderBy, orderAsc); let ordering = generateOrderingQueryParams(orderBy, orderAsc);
return fetch.get('pieces_list', { page, pageSize, search, ordering }); return requests.get('pieces_list', { page, pageSize, search, ordering });
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
let UserFetcher = { let UserFetcher = {
@ -9,7 +9,7 @@ let UserFetcher = {
* If no arg is supplied, load the current user * If no arg is supplied, load the current user
*/ */
fetchOne() { fetchOne() {
return fetch.get('user'); return requests.get('user');
} }
}; };

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import fetch from '../utils/fetch'; import requests from '../utils/requests';
import React from 'react'; import React from 'react';
import AlertDismissable from '../components/ascribe_forms/alert'; import AlertDismissable from '../components/ascribe_forms/alert';
@ -29,14 +29,14 @@ export const FormMixin = {
}, },
post(e){ post(e){
fetch requests
.post(this.url(e), { body: this.getFormData() }) .post(this.url(e), { body: this.getFormData() })
.then(this.handleSuccess) .then(this.handleSuccess)
.catch(this.handleError); .catch(this.handleError);
}, },
delete(e){ delete(e){
fetch requests
.delete(this.url(e)) .delete(this.url(e))
.then(this.handleSuccess) .then(this.handleSuccess)
.catch(this.handleError); .catch(this.handleError);

View File

@ -62,3 +62,11 @@ export function status(response) {
} }
throw new Error(response.json()); throw new Error(response.json());
} }
export function getCookie(name) {
let value = '; ' + document.cookie;
let parts = value.split('; ' + name + '=');
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
}

View File

@ -1,8 +1,6 @@
'use strict'; 'use strict';
import { default as _fetch } from 'isomorphic-fetch'; import { argsToQueryParams, getCookie } from '../utils/fetch_api_utils';
import { argsToQueryParams } from '../utils/fetch_api_utils';
class UrlMapError extends Error {} class UrlMapError extends Error {}
@ -10,7 +8,7 @@ class ServerError extends Error {}
class APIError extends Error {} class APIError extends Error {}
class Fetch { class Requests {
_merge(defaults, options) { _merge(defaults, options) {
let merged = {}; let merged = {};
for (let key in defaults) { for (let key in defaults) {
@ -78,8 +76,12 @@ class Fetch {
request(verb, url, options) { request(verb, url, options) {
options = options || {}; options = options || {};
let merged = this._merge(this.httpOptions, options); let merged = this._merge(this.httpOptions, options);
let csrftoken = getCookie('csrftoken');
if (csrftoken) {
merged.headers['X-CSRFToken'] = csrftoken;
}
merged.method = verb; merged.method = verb;
return _fetch(url, merged) return fetch(url, merged)
.then(this.unpackResponse) .then(this.unpackResponse)
.then(JSON.parse) .then(JSON.parse)
.catch(this.handleFatalError.bind(this)) .catch(this.handleFatalError.bind(this))
@ -117,6 +119,6 @@ class Fetch {
} }
let fetch = new Fetch(); let requests = new Requests();
export default fetch; export default requests;

View File

@ -12,14 +12,19 @@ app.use(baseUrl + 'static/js', express.static(__dirname + '/build/js'));
app.use(baseUrl + 'static/img', express.static(__dirname + '/build/img')); app.use(baseUrl + 'static/img', express.static(__dirname + '/build/img'));
app.use(baseUrl + 'static/css', express.static(__dirname + '/build/css')); app.use(baseUrl + 'static/css', express.static(__dirname + '/build/css'));
app.use(baseUrl + 'static/fonts', express.static(__dirname + '/build/fonts')); app.use(baseUrl + 'static/fonts', express.static(__dirname + '/build/fonts'));
app.use(baseUrl + 'static/thirdparty/', express.static(__dirname + '/node_modules')); app.use(baseUrl + 'static/thirdparty', express.static(__dirname + '/node_modules'));
app.get(/.*/, function(req, res) { app.get(/.*/, function(req, res) {
console.log('%s %s', req.method, req.path);
res.sendFile(__dirname + '/build/index.html'); res.sendFile(__dirname + '/build/index.html');
}); });
if (require.main === module) { if (require.main === module) {
app.listen(process.env.PORT || 4000); var port = process.env.PORT || 4000;
console.log('Starting Onion server on port', port,
'baseUrl is set to', baseUrl);
app.listen(port);
} }
module.exports.app = app; module.exports.app = app;