From c2cff6a63a8d69cd2096e8716a3cdce0dab6807c Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 24 Jun 2015 17:44:05 +0200 Subject: [PATCH 01/11] removed src fixed emails in notification instead of username --- gulpfile.js | 3 ++- js/components/register_piece.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index e570c2ff..d7106b19 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -91,7 +91,8 @@ gulp.task('browser-sync', function() { browserSync({ files: config.filesToWatch, proxy: 'http://localhost:4000', - port: 3000 + port: 3000, + browser: "chromium-browser" }); }); diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 384f0d23..693c43be 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -40,7 +40,7 @@ let RegisterPiece = React.createClass( { return data; }, handleChange(){ - this.setState({digital_work_key: this.refs.uploader.refs.fineuploader.state.filesToUpload[0].key}) + this.setState({digital_work_key: this.refs.uploader.refs.fineuploader.state.filesToUpload[0].key}); }, render() { From fba30a565bc97b555b9f011714b07c192dbb7b3f Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 14:39:39 +0200 Subject: [PATCH 02/11] coa renders per page verify --- js/actions/coa_actions.js | 36 +++++++++ js/components/coa_verify_container.js | 101 ++++++++++++++++++++++++++ js/components/edition.js | 64 +++++++++++++++- js/components/signup_container.js | 2 +- js/constants/api_urls.js | 3 + js/fetchers/coa_fetcher.js | 19 +++++ js/routes.js | 3 + js/stores/coa_store.js | 18 +++++ sass/ascribe_edition.scss | 16 ++++ sass/ascribe_textarea.scss | 3 +- 10 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 js/actions/coa_actions.js create mode 100644 js/components/coa_verify_container.js create mode 100644 js/fetchers/coa_fetcher.js create mode 100644 js/stores/coa_store.js diff --git a/js/actions/coa_actions.js b/js/actions/coa_actions.js new file mode 100644 index 00000000..b475aeb7 --- /dev/null +++ b/js/actions/coa_actions.js @@ -0,0 +1,36 @@ +'use strict'; + +import alt from '../alt'; +import CoaFetcher from '../fetchers/coa_fetcher'; + + +class CoaActions { + constructor() { + this.generateActions( + 'updateCoa' + ); + } + + fetchOne(id) { + CoaFetcher.fetchOne(id) + .then((res) => { + this.actions.updateCoa(res.coa); + console.log(res.coa); + }) + .catch((err) => { + console.log(err); + }); + } + create(edition) { + CoaFetcher.create(edition.bitcoin_id) + .then((res) => { + this.actions.updateCoa(res.coa); + console.log(res.coa); + }) + .catch((err) => { + console.log(err); + }); + } +} + +export default alt.createActions(CoaActions); diff --git a/js/components/coa_verify_container.js b/js/components/coa_verify_container.js new file mode 100644 index 00000000..b1721999 --- /dev/null +++ b/js/components/coa_verify_container.js @@ -0,0 +1,101 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import GlobalNotificationModel from '../models/global_notification_model'; +import GlobalNotificationActions from '../actions/global_notification_actions'; + +import Form from './ascribe_forms/form'; +import Property from './ascribe_forms/property'; +import InputTextAreaToggable from './ascribe_forms/input_textarea_toggable'; + +import apiUrls from '../constants/api_urls'; + + +let CoaVerifyContainer = React.createClass({ + mixins: [Router.Navigation], + + render() { + return ( +
+
+
+ Verify your Certificate of Authenticity +
+ + +
+
+ ascribe is using the following public key for verification: +
+
+                -----BEGIN PUBLIC KEY-----
+                MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDddadqY31kKPFYk8PQA8BWSTbm
+                gaGf9KEYBALp2nWAJcwq80qBzGF+gfi0Z+yb4ooeKHl27GnuxZYValE1Z5ZujfeJ
+                TgO4li59ZMYiah8oXZp/OysrBwCvWw0PtWd8/D9Nc4PqyOz5gzEh6kFah5VsuAke
+                Znu2w7KmeLZ85SmwEQIDAQAB
+                -----END PUBLIC KEY-----
+                
+
+ ); + } +}); + + +let CoaVerifyForm = React.createClass({ + mixins: [Router.Navigation], + + handleSuccess(response){ + let notification = null; + if (response.verdict){ + notification = new GlobalNotificationModel('Certificate of Authenticity successfully verified', 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + } + }, + + render() { + return ( +
+
+ Verify your Certificate of Authenticity + } + spinner={ + + }> + + + + + + +
+
+
+ ); + } +}); + + +export default CoaVerifyContainer; \ No newline at end of file diff --git a/js/components/edition.js b/js/components/edition.js index 34975699..68febdd7 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -6,9 +6,12 @@ import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; import Button from 'react-bootstrap/lib/Button'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import Panel from 'react-bootstrap/lib/Panel'; import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; +import CoaActions from '../actions/coa_actions'; +import CoaStore from '../stores/coa_store'; import MediaPlayer from './ascribe_media/media_player'; @@ -29,6 +32,7 @@ import GlobalNotificationActions from '../actions/global_notification_actions'; import requests from '../utils/requests'; import apiUrls from '../constants/api_urls'; +import AppConstants from '../constants/application_constants'; /** * This is the component that implements display-specific functionality @@ -109,13 +113,20 @@ let Edition = React.createClass({ -1 || Object.keys(this.props.edition.extra_data).length > 0}> + -1}> + + + 0}> @@ -421,4 +432,55 @@ let EditionFurtherDetails = React.createClass({ } }); +let CoaDetails = React.createClass({ + propTypes: { + edition: React.PropTypes.object + }, + + getInitialState() { + return CoaStore.getState(); + }, + + componentDidMount() { + CoaStore.listen(this.onChange); + if (this.props.edition.coa) { + CoaActions.fetchOne(this.props.edition.coa); + } + else{ + console.log('create coa'); + CoaActions.create(this.props.edition); + } + }, + + componentWillUnmount() { + CoaStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + if (this.state.coa.url_safe) { + return ( +
+

+ + +

+
+ ); + } + return ( +
+ +
); + + } +}); + export default Edition; diff --git a/js/components/signup_container.js b/js/components/signup_container.js index b8849669..65dfe217 100644 --- a/js/components/signup_container.js +++ b/js/components/signup_container.js @@ -115,7 +115,7 @@ let SignupForm = React.createClass({ name='promo_code' label="Promocode">
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index 608893e1..e6bbd3af 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -6,6 +6,9 @@ let apiUrls = { 'applications': AppConstants.apiEndpoint + 'applications/', 'application_token_refresh': AppConstants.apiEndpoint + 'applications/refresh_token/', 'blob_digitalworks': AppConstants.apiEndpoint + 'blob/digitalworks/', + 'coa': AppConstants.apiEndpoint + 'coa/${id}/', + 'coa_create': AppConstants.apiEndpoint + 'coa/', + 'coa_verify': AppConstants.apiEndpoint + 'coa/verify_coa/', 'edition': AppConstants.apiEndpoint + 'editions/${bitcoin_id}/', 'edition_delete': AppConstants.apiEndpoint + 'editions/${edition_id}/', 'edition_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/${edition_id}/', diff --git a/js/fetchers/coa_fetcher.js b/js/fetchers/coa_fetcher.js new file mode 100644 index 00000000..48ee9e73 --- /dev/null +++ b/js/fetchers/coa_fetcher.js @@ -0,0 +1,19 @@ +'use strict'; + +import requests from '../utils/requests'; + +let CoaFetcher = { + /** + * Fetch one user from the API. + * If no arg is supplied, load the current user + */ + fetchOne(id) { + return requests.get('coa', {'id': id}); + }, + create(bitcoinId) { + console.log(bitcoinId); + return requests.post('coa_create', {body: {'bitcoin_id': bitcoinId}}); + } +}; + +export default CoaFetcher; diff --git a/js/routes.js b/js/routes.js index 02ed27c5..7dc34687 100644 --- a/js/routes.js +++ b/js/routes.js @@ -12,6 +12,8 @@ import SignupContainer from './components/signup_container'; import PasswordResetContainer from './components/password_reset_container'; import SettingsContainer from './components/settings_container'; +import CoaVerifyContainer from './components/coa_verify_container'; + import AppConstants from './constants/application_constants'; import RegisterPiece from './components/register_piece'; @@ -28,6 +30,7 @@ let routes = ( + diff --git a/js/stores/coa_store.js b/js/stores/coa_store.js new file mode 100644 index 00000000..1aa762f3 --- /dev/null +++ b/js/stores/coa_store.js @@ -0,0 +1,18 @@ +'use strict'; + +import alt from '../alt'; +import CoaActions from '../actions/coa_actions'; + + +class CoaStore { + constructor() { + this.coa = {}; + this.bindActions(CoaActions); + } + + onUpdateCoa(coa) { + this.coa = coa; + } +} + +export default alt.createStore(CoaStore, 'CoaStore'); diff --git a/sass/ascribe_edition.scss b/sass/ascribe_edition.scss index acf4b529..f1af95d2 100644 --- a/sass/ascribe_edition.scss +++ b/sass/ascribe_edition.scss @@ -28,4 +28,20 @@ width:100%; margin-top: 1em; +} + +.coa-file-wrapper{ + display: table; + height: 200px; + overflow: hidden; + margin: 0 auto; + width: 100%; + padding: 1em; +} + +.coa-file { + display: table-cell; + vertical-align: middle; + border: 1px solid #CCC; + background-color: #F8F8F8; } \ No newline at end of file diff --git a/sass/ascribe_textarea.scss b/sass/ascribe_textarea.scss index 8d52ca64..2d368dbf 100644 --- a/sass/ascribe_textarea.scss +++ b/sass/ascribe_textarea.scss @@ -5,7 +5,8 @@ } .ascribe-textarea-editable:hover { - border: 1px solid #AAA; + //border: 1px solid #AAA;; + border: none; } .ascribe-pre{ From ddabedfb73802c30194da163a415254139c25e2a Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 14:47:29 +0200 Subject: [PATCH 03/11] browserify-shim --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e79cf8b..dbf65f45 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "devDependencies": { "babel-eslint": "^3.1.11", "babel-jest": "^5.2.0", - "browserify-shim": "^3.8.9", "jest-cli": "^0.4.0" }, "dependencies": { @@ -44,6 +43,7 @@ "bootstrap-sass": "^3.3.4", "browser-sync": "^2.7.5", "browserify": "^9.0.8", + "browserify-shim": "^3.8.9", "classnames": "^1.2.2", "compression": "^1.4.4", "envify": "^3.4.0", From d980ef7949fe0ee8ca446d735a4c5279c783b3f2 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 15:23:10 +0200 Subject: [PATCH 04/11] verify button link --- js/components/edition.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index 68febdd7..cb5f0dbb 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,12 +1,12 @@ 'use strict'; import React from 'react'; +import Router from 'react-router'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; import Button from 'react-bootstrap/lib/Button'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; -import Panel from 'react-bootstrap/lib/Panel'; import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; @@ -30,10 +30,10 @@ import AclButtonList from './ascribe_buttons/acl_button_list'; import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationActions from '../actions/global_notification_actions'; -import requests from '../utils/requests'; import apiUrls from '../constants/api_urls'; import AppConstants from '../constants/application_constants'; +let Link = Router.Link; /** * This is the component that implements display-specific functionality */ @@ -468,9 +468,12 @@ let CoaDetails = React.createClass({ - + + + +

); From 93c1b2e826c870e3c2b3e469e33d4f2a5311f2da Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 15:25:34 +0200 Subject: [PATCH 05/11] login location with baseurl --- js/components/login_container.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/components/login_container.js b/js/components/login_container.js index 8c149d8c..d4085540 100644 --- a/js/components/login_container.js +++ b/js/components/login_container.js @@ -10,6 +10,7 @@ import Form from './ascribe_forms/form'; import Property from './ascribe_forms/property'; import apiUrls from '../constants/api_urls'; +import AppConstants from '../constants/application_constants'; let LoginContainer = React.createClass({ @@ -45,7 +46,7 @@ let LoginForm = React.createClass({ Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future. Until then, we redirect the HARD way, but reloading the whole page using window.location */ - window.location = '/collection'; + window.location = AppConstants.baseUrl + '/collection'; }, render() { From 64017f604c034ad8173d1321cb1cc11c9d5dd4c8 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 15:30:47 +0200 Subject: [PATCH 06/11] login location with baseurl --- js/components/login_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/login_container.js b/js/components/login_container.js index d4085540..4363971f 100644 --- a/js/components/login_container.js +++ b/js/components/login_container.js @@ -46,7 +46,7 @@ let LoginForm = React.createClass({ Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future. Until then, we redirect the HARD way, but reloading the whole page using window.location */ - window.location = AppConstants.baseUrl + '/collection'; + window.location = AppConstants.baseUrl + 'collection'; }, render() { From b1ad4cc36f37ea8f7365da72b7a0fb62a259a9fd Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 25 Jun 2015 23:25:03 +0200 Subject: [PATCH 07/11] withdraw transfer part one --- js/components/edition.js | 489 ------------------------------- js/components/login_container.js | 2 +- sass/main.scss | 6 + 3 files changed, 7 insertions(+), 490 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index cb5f0dbb..e69de29b 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,489 +0,0 @@ -'use strict'; - -import React from 'react'; -import Router from 'react-router'; - -import Row from 'react-bootstrap/lib/Row'; -import Col from 'react-bootstrap/lib/Col'; -import Button from 'react-bootstrap/lib/Button'; -import Glyphicon from 'react-bootstrap/lib/Glyphicon'; - -import UserActions from '../actions/user_actions'; -import UserStore from '../stores/user_store'; -import CoaActions from '../actions/coa_actions'; -import CoaStore from '../stores/coa_store'; - -import MediaPlayer from './ascribe_media/media_player'; - -import CollapsibleParagraph from './ascribe_collapsible/collapsible_paragraph'; - -import Form from './ascribe_forms/form'; -import Property from './ascribe_forms/property'; -import InputTextAreaToggable from './ascribe_forms/input_textarea_toggable'; - -import PieceExtraDataForm from './ascribe_forms/form_piece_extradata'; -import RequestActionForm from './ascribe_forms/form_request_action'; - -import EditionActions from '../actions/edition_actions'; -import AclButtonList from './ascribe_buttons/acl_button_list'; - -import GlobalNotificationModel from '../models/global_notification_model'; -import GlobalNotificationActions from '../actions/global_notification_actions'; - -import apiUrls from '../constants/api_urls'; -import AppConstants from '../constants/application_constants'; - -let Link = Router.Link; -/** - * This is the component that implements display-specific functionality - */ -let Edition = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - 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() { - let thumbnail = this.props.edition.thumbnail; - let mimetype = this.props.edition.digital_work.mime; - let extraData = null; - - if (this.props.edition.digital_work.encoding_urls) { - extraData = this.props.edition.digital_work.encoding_urls.map(e => { return { url: e.url, type: e.label }; }); - } - - let bitcoinIdValue = ( - {this.props.edition.bitcoin_id} - ); - - let hashOfArtwork = ( - {this.props.edition.hash_as_address} - ); - - let ownerAddress = ( - {this.props.edition.btc_owner_address_noprefix} - ); - - return ( - - - -

- -

- - - - - - -1 || this.props.edition.public_note)}> - - - - - -1 || Object.keys(this.props.edition.extra_data).length > 0}> - - - - -1}> - - - - 0}> - - - - 0}> - - - - 0}> - - - - -
- -
{bitcoinIdValue}
-
- -
{hashOfArtwork}
-
- -
{ownerAddress}
-
-
-
-
- -
- ); - } -}); - -let EditionHeader = React.createClass({ - propTypes: { - edition: React.PropTypes.object - }, - - render() { - var titleHtml =
{this.props.edition.title}
; - return ( -
- - - -
-
- ); - } -}); - - -let EditionSummary = React.createClass({ - propTypes: { - edition: React.PropTypes.object - }, - - handleSuccess(){ - EditionActions.fetchOne(this.props.edition.id); - }, - showNotification(response){ - this.handleSuccess(); - let notification = new GlobalNotificationModel(response.notification, 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - render() { - let status = null; - if (this.props.edition.status.length > 0){ - status = ; - } - let actions = null; - if (this.props.edition.request_action && this.props.edition.request_action.length > 0){ - actions = ( - ); - } - else { - actions = ( - - - - - ); - } - - return ( -
- - - - {status} -
- {actions} -
-
- ); - - } -}); - - -let EditionDetailProperty = React.createClass({ - propTypes: { - label: React.PropTypes.string, - value: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.element - ]), - separator: React.PropTypes.string, - labelClassName: React.PropTypes.string, - valueClassName: React.PropTypes.string - }, - - getDefaultProps() { - return { - separator: ':', - labelClassName: 'col-xs-5 col-sm-4 col-md-3 col-lg-3', - valueClassName: 'col-xs-7 col-sm-8 col-md-9 col-lg-9' - }; - }, - - render() { - return ( -
-
-
-
{ this.props.label + this.props.separator}
-
-
-
{ this.props.value }
-
-
-
- ); - } -}); - -let EditionDetailHistoryIterator = React.createClass({ - propTypes: { - history: React.PropTypes.array - }, - - render() { - return ( -
- {this.props.history.map((historicalEvent, i) => { - return ( - - ); - })} -
- ); - } -}); - -let EditionPersonalNote = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - currentUser: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - showNotification(){ - this.props.handleSuccess(); - let notification = new GlobalNotificationModel('Private note saved', 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - render() { - if (this.props.currentUser.username && true || false) { - return ( -
- - - - -
-
- ); - } - return null; - } -}); - -let EditionPublicEditionNote = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - showNotification(){ - this.props.handleSuccess(); - let notification = new GlobalNotificationModel('Public note saved', 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - render() { - let isEditable = this.props.edition.acl.indexOf('edit') > -1; - if (this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note){ - return ( -
- - - - -
-
- ); - } - return null; - } -}); - - -let EditionFurtherDetails = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - showNotification(){ - this.props.handleSuccess(); - let notification = new GlobalNotificationModel('Details updated', 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - render() { - let editable = this.props.edition.acl.indexOf('edit') > -1; - return ( - - - - - - - - ); - } -}); - -let CoaDetails = React.createClass({ - propTypes: { - edition: React.PropTypes.object - }, - - getInitialState() { - return CoaStore.getState(); - }, - - componentDidMount() { - CoaStore.listen(this.onChange); - if (this.props.edition.coa) { - CoaActions.fetchOne(this.props.edition.coa); - } - else{ - console.log('create coa'); - CoaActions.create(this.props.edition); - } - }, - - componentWillUnmount() { - CoaStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - render() { - if (this.state.coa.url_safe) { - return ( -
-

- - - - - -

-
- ); - } - return ( -
- -
); - - } -}); - -export default Edition; diff --git a/js/components/login_container.js b/js/components/login_container.js index 4363971f..24b63ce7 100644 --- a/js/components/login_container.js +++ b/js/components/login_container.js @@ -40,7 +40,7 @@ let LoginForm = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); /*Taken from http://stackoverflow.com/a/14916411 */ - /* + /* We actually have to trick the Browser into showing the "save password" dialog as Chrome expects the login page to be reloaded after the login. Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future. diff --git a/sass/main.scss b/sass/main.scss index 0fa799ab..7b2a7494 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -33,6 +33,12 @@ body { display: none; } +.no-margin{ + margin: 0; +} +.no-padding{ + padding: 0; +} .navbar-default { border: none; border-left:0; From 7e115e26ad665c42c8728e8f69ce436dedd0cc22 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 26 Jun 2015 00:38:40 +0200 Subject: [PATCH 08/11] withdraw transfer part one --- js/components/edition.js | 525 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 525 insertions(+) diff --git a/js/components/edition.js b/js/components/edition.js index e69de29b..682e0c9b 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -0,0 +1,525 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import Row from 'react-bootstrap/lib/Row'; +import Col from 'react-bootstrap/lib/Col'; +import Button from 'react-bootstrap/lib/Button'; +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; + +import UserActions from '../actions/user_actions'; +import UserStore from '../stores/user_store'; +import CoaActions from '../actions/coa_actions'; +import CoaStore from '../stores/coa_store'; + +import MediaPlayer from './ascribe_media/media_player'; + +import CollapsibleParagraph from './ascribe_collapsible/collapsible_paragraph'; + +import Form from './ascribe_forms/form'; +import Property from './ascribe_forms/property'; +import InputTextAreaToggable from './ascribe_forms/input_textarea_toggable'; + +import PieceExtraDataForm from './ascribe_forms/form_piece_extradata'; +import RequestActionForm from './ascribe_forms/form_request_action'; + +import EditionActions from '../actions/edition_actions'; +import AclButtonList from './ascribe_buttons/acl_button_list'; + +import GlobalNotificationModel from '../models/global_notification_model'; +import GlobalNotificationActions from '../actions/global_notification_actions'; + +import apiUrls from '../constants/api_urls'; +import AppConstants from '../constants/application_constants'; + +let Link = Router.Link; +/** + * This is the component that implements display-specific functionality + */ +let Edition = React.createClass({ + propTypes: { + edition: React.PropTypes.object, + 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() { + let thumbnail = this.props.edition.thumbnail; + let mimetype = this.props.edition.digital_work.mime; + let extraData = null; + + if (this.props.edition.digital_work.encoding_urls) { + extraData = this.props.edition.digital_work.encoding_urls.map(e => { return { url: e.url, type: e.label }; }); + } + + let bitcoinIdValue = ( + {this.props.edition.bitcoin_id} + ); + + let hashOfArtwork = ( + {this.props.edition.hash_as_address} + ); + + let ownerAddress = ( + {this.props.edition.btc_owner_address_noprefix} + ); + + return ( + + + +

+ +

+ + + + + + -1 || this.props.edition.public_note)}> + + + + + -1 || Object.keys(this.props.edition.extra_data).length > 0}> + + + + -1}> + + + + 0}> + + + + 0}> + + + + 0}> + + + + +
+ +
{bitcoinIdValue}
+
+ +
{hashOfArtwork}
+
+ +
{ownerAddress}
+
+
+
+
+ +
+ ); + } +}); + +let EditionHeader = React.createClass({ + propTypes: { + edition: React.PropTypes.object + }, + + render() { + var titleHtml =
{this.props.edition.title}
; + return ( +
+ + + +
+
+ ); + } +}); + + +let EditionSummary = React.createClass({ + propTypes: { + edition: React.PropTypes.object + }, + + handleSuccess(){ + EditionActions.fetchOne(this.props.edition.id); + }, + showNotification(response){ + this.handleSuccess(); + let notification = new GlobalNotificationModel(response.notification, 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + render() { + let status = null; + if (this.props.edition.status.length > 0){ + let statusStr = this.props.edition.status.join().replace(/_/, ' '); + let statusAction = null; + if (this.props.edition.pending_new_owner && this.props.edition.acl.indexOf('withdraw_transfer') > -1){ + statusAction = ( + + ); + } + status =( + + {statusAction} + ); + } + let actions = null; + if (this.props.edition.request_action && this.props.edition.request_action.length > 0){ + actions = ( + ); + } + else { + actions = ( + + + + + ); + } + + return ( +
+ + + + {status} +
+ {actions} +
+
+ ); + + } +}); + + +let EditionDetailProperty = React.createClass({ + propTypes: { + label: React.PropTypes.string, + value: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.element + ]), + separator: React.PropTypes.string, + labelClassName: React.PropTypes.string, + valueClassName: React.PropTypes.string + }, + + getDefaultProps() { + return { + separator: ':', + labelClassName: 'col-xs-5 col-sm-4 col-md-3 col-lg-3', + valueClassName: 'col-xs-7 col-sm-8 col-md-9 col-lg-9' + }; + }, + + render() { + let value = this.props.value; + if (this.props.children){ + value = ( +
+
+ { this.props.value } +
+
+ { this.props.children } +
+
); + } + return ( +
+
+
+
{ this.props.label + this.props.separator}
+
+
+ {value} +
+
+
+ ); + } +}); + +let EditionDetailHistoryIterator = React.createClass({ + propTypes: { + history: React.PropTypes.array + }, + + render() { + return ( +
+ {this.props.history.map((historicalEvent, i) => { + //return ( + // + //); + return( + +
{ historicalEvent[1] }
+
+ ) + })} +
+ + ); + } +}); + +let EditionPersonalNote = React.createClass({ + propTypes: { + edition: React.PropTypes.object, + currentUser: React.PropTypes.object, + handleSuccess: React.PropTypes.func + }, + showNotification(){ + this.props.handleSuccess(); + let notification = new GlobalNotificationModel('Private note saved', 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { + if (this.props.currentUser.username && true || false) { + return ( +
+ + + + +
+
+ ); + } + return null; + } +}); + +let EditionPublicEditionNote = React.createClass({ + propTypes: { + edition: React.PropTypes.object, + handleSuccess: React.PropTypes.func + }, + showNotification(){ + this.props.handleSuccess(); + let notification = new GlobalNotificationModel('Public note saved', 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + render() { + let isEditable = this.props.edition.acl.indexOf('edit') > -1; + if (this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note){ + return ( +
+ + + + +
+
+ ); + } + return null; + } +}); + + +let EditionFurtherDetails = React.createClass({ + propTypes: { + edition: React.PropTypes.object, + handleSuccess: React.PropTypes.func + }, + showNotification(){ + this.props.handleSuccess(); + let notification = new GlobalNotificationModel('Details updated', 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { + let editable = this.props.edition.acl.indexOf('edit') > -1; + return ( + + + + + + + + ); + } +}); + +let CoaDetails = React.createClass({ + propTypes: { + edition: React.PropTypes.object + }, + + getInitialState() { + return CoaStore.getState(); + }, + + componentDidMount() { + CoaStore.listen(this.onChange); + if (this.props.edition.coa) { + CoaActions.fetchOne(this.props.edition.coa); + } + else{ + console.log('create coa'); + CoaActions.create(this.props.edition); + } + }, + + componentWillUnmount() { + CoaStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + if (this.state.coa.url_safe) { + return ( +
+

+ + + + + +

+
+ ); + } + return ( +
+ +
); + + } +}); + +export default Edition; From 99d6dd278c85a9365d69a214ab8d54b65dcc9e80 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 26 Jun 2015 01:05:20 +0200 Subject: [PATCH 09/11] withdraw fix --- js/components/edition.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index 682e0c9b..e583273d 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -224,7 +224,7 @@ let EditionSummary = React.createClass({ ); } - status =( + status = ( {statusAction} ); @@ -323,16 +323,7 @@ let EditionDetailHistoryIterator = React.createClass({ return (
{this.props.history.map((historicalEvent, i) => { - //return ( - // - //); - return( + return (
{ historicalEvent[1] }
- ) + ); })}
From eff25a980157d37ef659c4e9a268a91864615038 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 26 Jun 2015 11:44:35 +0200 Subject: [PATCH 10/11] withdraw transfer with delete of transfer record --- js/components/edition.js | 27 +++++++++++++++++---------- js/constants/api_urls.js | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index e583273d..b3af22f7 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -203,6 +203,9 @@ let EditionSummary = React.createClass({ edition: React.PropTypes.object }, + getTransferWithdrawData(){ + return {'bitcoin_id': this.props.edition.bitcoin_id}; + }, handleSuccess(){ EditionActions.fetchOne(this.props.edition.id); }, @@ -215,19 +218,23 @@ let EditionSummary = React.createClass({ let status = null; if (this.props.edition.status.length > 0){ let statusStr = this.props.edition.status.join().replace(/_/, ' '); - let statusAction = null; + status = ; if (this.props.edition.pending_new_owner && this.props.edition.acl.indexOf('withdraw_transfer') > -1){ - statusAction = ( - + status = ( +
+ + + +
); } - status = ( - - {statusAction} - ); } let actions = null; if (this.props.edition.request_action && this.props.edition.request_action.length > 0){ diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index e6bbd3af..e1e5d15e 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -23,6 +23,7 @@ let apiUrls = { 'ownership_loans_deny': AppConstants.apiEndpoint + 'ownership/loans/deny/', 'ownership_shares': AppConstants.apiEndpoint + 'ownership/shares/', 'ownership_transfers': AppConstants.apiEndpoint + 'ownership/transfers/', + 'ownership_transfers_withdraw': AppConstants.apiEndpoint + 'ownership/transfers/withdraw/', 'ownership_unconsigns': AppConstants.apiEndpoint + 'ownership/unconsigns/', 'ownership_unconsigns_deny': AppConstants.apiEndpoint + 'ownership/unconsigns/deny/', 'ownership_unconsigns_request': AppConstants.apiEndpoint + 'ownership/unconsigns/request/', From 5916c27c455ad6a787f3530dd098bd2b39eb4bb4 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 29 Jun 2015 10:00:26 +0200 Subject: [PATCH 11/11] uploader defaultprops --- .../react_s3_fine_uploader.js | 69 +++++++++++++++++-- js/components/edition.js | 31 +++++++++ js/components/register_piece.js | 53 +------------- 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 985e5d90..c2842e3c 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -6,6 +6,8 @@ import promise from 'es6-promise'; promise.polyfill(); import fetch from 'isomorphic-fetch'; +import AppConstants from '../../constants/application_constants'; + import fineUploader from 'fineUploader'; import FileDragAndDrop from './file_drag_and_drop'; @@ -18,7 +20,8 @@ var ReactS3FineUploader = React.createClass({ propTypes: { keyRoutine: React.PropTypes.shape({ url: React.PropTypes.string, - fileClass: React.PropTypes.string + fileClass: React.PropTypes.string, + bitcoinId: React.PropTypes.string }), createBlobRoutine: React.PropTypes.shape({ url: React.PropTypes.string @@ -84,7 +87,64 @@ var ReactS3FineUploader = React.createClass({ uploader: new fineUploader.s3.FineUploaderBasic(this.propsToConfig()) }; }, - + getDefaultProps() { + return { + autoUpload: true, + debug: false, + objectProperties: { + acl: 'public-read', + bucket: 'ascribe0' + }, + request: { + endpoint: 'https://ascribe0.s3.amazonaws.com', + accessKey: 'AKIAIVCZJ33WSCBQ3QDA' + }, + uploadSuccess: { + params: { + isBrowserPreviewCapable: fineUploader.supportedFeatures.imagePreviews + } + }, + signature: { + endpoint: AppConstants.serverUrl + 's3/signature/' + //customHeaders: { + // 'Authorization': 'OAuth ' + getCookie('sessionid') + //} + }, + deleteFile: { + enabled: true, + method: 'DELETE', + endpoint: AppConstants.serverUrl + 's3/delete' + //customHeaders: { + // 'X-CSRFToken': getCookie('csrftoken') + //} + }, + cors: { + expected: true + }, + chunking: { + enabled: true + }, + resume: { + enabled: true + }, + retry: { + enableAuto: false + }, + session: { + endpoint: null + }, + messages: { + unsupportedBrowser: '

Upload is not functional in IE7 as IE7 has no support for CORS!

' + }, + formatFileName: function(name){// fix maybe + if (name !== undefined && name.length > 26) { + name = name.slice(0, 15) + '...' + name.slice(-15); + } + return name; + }, + multiple: false + }; + }, propsToConfig() { let objectProperties = this.props.objectProperties; objectProperties.key = this.requestKey; @@ -140,7 +200,8 @@ var ReactS3FineUploader = React.createClass({ credentials: 'include', body: JSON.stringify({ 'filename': filename, - 'file_class': 'digitalwork' + 'file_class': this.props.keyRoutine.fileClass, + 'bitcoin_id': this.props.keyRoutine.bitcoinId }) }) .then((res) => { @@ -326,7 +387,7 @@ var ReactS3FineUploader = React.createClass({ onDrop={this.handleUploadFile} filesToUpload={this.state.filesToUpload} handleDeleteFile={this.handleDeleteFile} - multiple={this.props.multiple} + multiple={this.props.multiple} dropzoneInactive={!this.props.multiple && this.state.filesToUpload.length > 0} /> ); } diff --git a/js/components/edition.js b/js/components/edition.js index b3af22f7..78f36628 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -27,6 +27,9 @@ import RequestActionForm from './ascribe_forms/form_request_action'; import EditionActions from '../actions/edition_actions'; import AclButtonList from './ascribe_buttons/acl_button_list'; +import fineUploader from 'fineUploader'; +import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader'; + import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationActions from '../actions/global_notification_actions'; @@ -460,12 +463,40 @@ let EditionFurtherDetails = React.createClass({ handleSuccess={this.showNotification} editable={editable} edition={this.props.edition} /> + ); } }); +let FileUploader = React.createClass( { + handleChange(){ + this.setState({other_data_key: this.refs.fineuploader.state.filesToUpload[0].key}); + }, + render() { + return ( + + ); + } +}); + let CoaDetails = React.createClass({ propTypes: { edition: React.PropTypes.object diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 5ed7b0ba..a73fc2ea 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -2,8 +2,8 @@ import React from 'react'; +import { getCookie } from '../utils/fetch_api_utils'; import AppConstants from '../constants/application_constants'; -import fineUploader from 'fineUploader'; import Router from 'react-router'; @@ -19,6 +19,7 @@ import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader'; import DatePicker from 'react-datepicker/dist/react-datepicker'; + let RegisterPiece = React.createClass( { mixins: [Router.Navigation], @@ -128,58 +129,10 @@ let FileUploader = React.createClass( { url: apiUrls.blob_digitalworks }} handleChange={this.props.handleChange} - autoUpload={true} - debug={false} - objectProperties={{ - acl: 'public-read', - bucket: 'ascribe0' - }} - request={{ - endpoint: 'https://ascribe0.s3.amazonaws.com', - accessKey: 'AKIAIVCZJ33WSCBQ3QDA' - }} - signature={{ - endpoint: AppConstants.serverUrl + 's3/signature/' - }} - uploadSuccess={{ - params: { - isBrowserPreviewCapable: fineUploader.supportedFeatures.imagePreviews - } - }} - cors={{ - expected: true - }} - chunking={{ - enabled: true - }} - resume={{ - enabled: true - }} - retry={{ - enableAuto: false - }} - deleteFile={{ - enabled: true, - method: 'DELETE', - endpoint: AppConstants.serverUrl + 's3/delete' - }} validation={{ itemLimit: 100000, sizeLimit: '25000000000' - }} - session={{ - endpoint: null - }} - messages={{ - unsupportedBrowser: '

Upload is not functional in IE7 as IE7 has no support for CORS!

' - }} - formatFileName={(name) => {// fix maybe - if (name !== undefined && name.length > 26) { - name = name.slice(0, 15) + '...' + name.slice(-15); - } - return name; - }} - multiple={true}/> + }}/> ); } });