From 2cb8fb2dd9e5278611f63d376fd0b703cc164fa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 8 Feb 2016 16:44:27 +0100
Subject: [PATCH 1/6] Replace bootstrap button with proper dl-link
---
js/components/ascribe_detail/media_container.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/js/components/ascribe_detail/media_container.js b/js/components/ascribe_detail/media_container.js
index 1e9ba0a1..e22069e1 100644
--- a/js/components/ascribe_detail/media_container.js
+++ b/js/components/ascribe_detail/media_container.js
@@ -131,9 +131,9 @@ let MediaContainer = React.createClass({
show={['video', 'audio', 'image'].indexOf(mimetype) === -1 || content.acl.acl_download}
aclObject={content.acl}
aclName="acl_download">
-
+
{embed}
From f2c7f02480a00a27a3ce84f9a155c9377dfd5f2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 17 Feb 2016 11:38:01 +0100
Subject: [PATCH 2/6] Add component for signing S3 url
---
.../ascribe_buttons/s3_download_button.js | 91 +++++++++++++++++++
.../ascribe_detail/media_container.js | 19 ++--
js/constants/api_urls.js | 3 +-
js/constants/application_constants.js | 2 +-
js/fetchers/s3_fetcher.js | 7 ++
js/utils/requests.js | 2 +-
6 files changed, 109 insertions(+), 15 deletions(-)
create mode 100644 js/components/ascribe_buttons/s3_download_button.js
diff --git a/js/components/ascribe_buttons/s3_download_button.js b/js/components/ascribe_buttons/s3_download_button.js
new file mode 100644
index 00000000..453bc6a8
--- /dev/null
+++ b/js/components/ascribe_buttons/s3_download_button.js
@@ -0,0 +1,91 @@
+'use strict';
+
+import React from 'react';
+
+import S3Fetcher from '../../fetchers/s3_fetcher';
+
+import Glyphicon from 'react-bootstrap/lib/Glyphicon';
+
+import AppConstants from '../../constants/application_constants';
+
+import { getLangText } from '../../utils/lang_utils';
+import { queryParamsToArgs } from '../../utils/url_utils';
+
+
+const { string } = React.PropTypes;
+
+const S3DownloadButton = React.createClass({
+ propTypes: {
+ url: string,
+ title: string,
+ artistName: string,
+ fileExtension: string
+ },
+
+ getInitialState() {
+ return {
+ downloadUrl: null
+ };
+ },
+
+ componentDidMount() {
+ /**
+ * Initially, we request a signed url from
+ * the backend
+ */
+ this.signUrl();
+ },
+
+ transformS3UrlToS3Key(url) {
+ return url.replace(`https://${AppConstants.cloudfrontDomain}/`, '');
+ },
+
+ signUrl(next) {
+ const { url, title, artistName } = this.props;
+
+ S3Fetcher
+ .signUrl(this.transformS3UrlToS3Key(url), title, artistName)
+ .then(({ signed_url: downloadUrl }) => this.setState({ downloadUrl }, next))
+ .catch(console.logGlobal);
+ },
+
+ reSignUrl(event) {
+ /**
+ * The signed url, however can expire, which is why
+ * we need to renew it when it expires.
+ */
+ const { downloadUrl } = this.state;
+ const { expires } = queryParamsToArgs(downloadUrl.split('?')[1]);
+ const nowInSeconds = new Date().getTime() / 1000;
+
+ if(nowInSeconds > expires) {
+ event.preventDefault();
+ this.signUrl(() => this.refs.downloadButton.getDOMNode().click());
+ }
+ },
+
+ render() {
+ const { fileExtension, url } = this.props;
+ const { downloadUrl } = this.state;
+
+ return (
+
+
+ {/*
+ If it turns out that `fileExtension` is an empty string, we're just
+ using the label 'file'.
+ */}
+ {getLangText('Download')} .{fileExtension || 'file'}
+
+
+ );
+ }
+});
+
+export default S3DownloadButton;
\ No newline at end of file
diff --git a/js/components/ascribe_detail/media_container.js b/js/components/ascribe_detail/media_container.js
index e22069e1..5511fdb4 100644
--- a/js/components/ascribe_detail/media_container.js
+++ b/js/components/ascribe_detail/media_container.js
@@ -3,13 +3,14 @@
import React from 'react';
import Button from 'react-bootstrap/lib/Button';
-import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import MediaPlayer from './../ascribe_media/media_player';
import FacebookShareButton from '../ascribe_social_share/facebook_share_button';
import TwitterShareButton from '../ascribe_social_share/twitter_share_button';
+import S3DownloadButton from '../ascribe_buttons/s3_download_button';
+
import CollapsibleButton from './../ascribe_collapsible/collapsible_button';
import AclProxy from '../acl_proxy';
@@ -131,17 +132,11 @@ let MediaContainer = React.createClass({
show={['video', 'audio', 'image'].indexOf(mimetype) === -1 || content.acl.acl_download}
aclObject={content.acl}
aclName="acl_download">
-
- {/*
- If it turns out that `fileExtension` is an empty string, we're just
- using the label 'file'.
- */}
- {getLangText('Download')} .{fileExtension || 'file'}
-
+
{embed}
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js
index f7bac317..29e37724 100644
--- a/js/constants/api_urls.js
+++ b/js/constants/api_urls.js
@@ -76,7 +76,8 @@ let ApiUrls = {
'webhooks': AppConstants.apiEndpoint + 'webhooks/',
'webhooks_events': AppConstants.apiEndpoint + 'webhooks/events/',
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
- 'delete_s3_file': AppConstants.serverUrl + 's3/delete/'
+ 'delete_s3_file': AppConstants.serverUrl + 's3/delete/',
+ 'sign_url_s3': AppConstants.serverUrl + 's3/sign_url/'
};
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js
index 332eee49..2fee15c3 100644
--- a/js/constants/application_constants.js
+++ b/js/constants/application_constants.js
@@ -119,7 +119,7 @@ const constants = {
'twitter': {
'sdkUrl': 'https://platform.twitter.com/widgets.js'
},
-
+ 'cloudfrontDomain': 'd1qjsxua1o9x03.cloudfront.net',
'errorMessagesToIgnore': [
'Authentication credentials were not provided.',
'Informations d\'authentification non fournies.'
diff --git a/js/fetchers/s3_fetcher.js b/js/fetchers/s3_fetcher.js
index e6f50b72..1a02727e 100644
--- a/js/fetchers/s3_fetcher.js
+++ b/js/fetchers/s3_fetcher.js
@@ -11,6 +11,13 @@ let S3Fetcher = {
key,
bucket
});
+ },
+ signUrl(key, title, artistName) {
+ return requests.get('sign_url_s3', {
+ 'artist_name': artistName,
+ key,
+ title
+ });
}
};
diff --git a/js/utils/requests.js b/js/utils/requests.js
index fec31c00..5552731a 100644
--- a/js/utils/requests.js
+++ b/js/utils/requests.js
@@ -70,7 +70,7 @@ class Requests {
}
}).catch(reject);
});
- }
+ };
}
getUrl(url) {
From 23efaa368e43ccbbda89a079430e6b4701be82e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 22 Feb 2016 12:18:40 +0100
Subject: [PATCH 3/6] Apply PR feedback
---
.../ascribe_buttons/s3_download_button.js | 30 +++++++++----------
js/fetchers/s3_fetcher.js | 4 +--
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/js/components/ascribe_buttons/s3_download_button.js b/js/components/ascribe_buttons/s3_download_button.js
index 453bc6a8..5ae4f807 100644
--- a/js/components/ascribe_buttons/s3_download_button.js
+++ b/js/components/ascribe_buttons/s3_download_button.js
@@ -69,23 +69,21 @@ const S3DownloadButton = React.createClass({
const { downloadUrl } = this.state;
return (
-
-
- {/*
- If it turns out that `fileExtension` is an empty string, we're just
- using the label 'file'.
- */}
- {getLangText('Download')} .{fileExtension || 'file'}
-
-
+
+ {/*
+ If it turns out that `fileExtension` is an empty string, we're just
+ using the label 'file'.
+ */}
+ {getLangText('Download')} .{fileExtension || 'file'}
+
);
}
});
-export default S3DownloadButton;
\ No newline at end of file
+export default S3DownloadButton;
diff --git a/js/fetchers/s3_fetcher.js b/js/fetchers/s3_fetcher.js
index 1a02727e..bde6f6ba 100644
--- a/js/fetchers/s3_fetcher.js
+++ b/js/fetchers/s3_fetcher.js
@@ -14,9 +14,9 @@ let S3Fetcher = {
},
signUrl(key, title, artistName) {
return requests.get('sign_url_s3', {
- 'artist_name': artistName,
key,
- title
+ title,
+ 'artist_name': artistName
});
}
};
From b2a21c5cc15e8d16f60110193a9863219092ad43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 22 Feb 2016 17:38:02 +0100
Subject: [PATCH 4/6] Resign url based on setInterval
---
.../ascribe_buttons/s3_download_button.js | 49 ++++++++++++-------
1 file changed, 32 insertions(+), 17 deletions(-)
diff --git a/js/components/ascribe_buttons/s3_download_button.js b/js/components/ascribe_buttons/s3_download_button.js
index 5ae4f807..72b22115 100644
--- a/js/components/ascribe_buttons/s3_download_button.js
+++ b/js/components/ascribe_buttons/s3_download_button.js
@@ -24,7 +24,8 @@ const S3DownloadButton = React.createClass({
getInitialState() {
return {
- downloadUrl: null
+ downloadUrl: null,
+ signatureExpiryTimerId: null
};
},
@@ -36,6 +37,36 @@ const S3DownloadButton = React.createClass({
this.signUrl();
},
+ componentWillUnmount() {
+ window.clearInterval(this.state.signatureExpiryTime);
+ },
+
+ componentDidUpdate() {
+ const { signatureExpiryTimerId, downloadUrl } = this.state;
+
+ if(!signatureExpiryTimerId && downloadUrl) {
+ /**
+ * The signed url, however can expire, which is why
+ * we need to renew it when it expires.
+ */
+ const { downloadUrl } = this.state;
+ const expires = parseInt(queryParamsToArgs(downloadUrl.split('?')[1]).expires, 10);
+ const now = new Date().getTime() / 1000;
+
+ /**
+ * Amazon uses seconds as their signature unix timestamp
+ * while `setInterval` uses milliseconds. Therefore we need to
+ * multiply with 1000.
+ */
+ const interval = (expires - now) * 1000;
+
+ this.setState({
+ // Substract 5s to make sure there is a big enough window to sign again before expiration
+ signatureExpiryTimerId: window.setInterval(this.signUrl, interval - 5000)
+ });
+ }
+ },
+
transformS3UrlToS3Key(url) {
return url.replace(`https://${AppConstants.cloudfrontDomain}/`, '');
},
@@ -49,21 +80,6 @@ const S3DownloadButton = React.createClass({
.catch(console.logGlobal);
},
- reSignUrl(event) {
- /**
- * The signed url, however can expire, which is why
- * we need to renew it when it expires.
- */
- const { downloadUrl } = this.state;
- const { expires } = queryParamsToArgs(downloadUrl.split('?')[1]);
- const nowInSeconds = new Date().getTime() / 1000;
-
- if(nowInSeconds > expires) {
- event.preventDefault();
- this.signUrl(() => this.refs.downloadButton.getDOMNode().click());
- }
- },
-
render() {
const { fileExtension, url } = this.props;
const { downloadUrl } = this.state;
@@ -74,7 +90,6 @@ const S3DownloadButton = React.createClass({
download
className="btn btn-xs btn-default ascribe-margin-1px"
target="_blank"
- onClick={this.reSignUrl}
href={downloadUrl || url}>
{/*
If it turns out that `fileExtension` is an empty string, we're just
From e863349531064321bb6c63a772a1f16a50131397 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Tue, 1 Mar 2016 12:55:27 +0100
Subject: [PATCH 5/6] Refactor to comply with PR feedback
---
.../ascribe_buttons/s3_download_button.js | 55 +++++++++----------
js/stores/notification_store.js | 4 --
2 files changed, 27 insertions(+), 32 deletions(-)
diff --git a/js/components/ascribe_buttons/s3_download_button.js b/js/components/ascribe_buttons/s3_download_button.js
index 72b22115..9f7c355a 100644
--- a/js/components/ascribe_buttons/s3_download_button.js
+++ b/js/components/ascribe_buttons/s3_download_button.js
@@ -41,42 +41,41 @@ const S3DownloadButton = React.createClass({
window.clearInterval(this.state.signatureExpiryTime);
},
- componentDidUpdate() {
- const { signatureExpiryTimerId, downloadUrl } = this.state;
-
- if(!signatureExpiryTimerId && downloadUrl) {
- /**
- * The signed url, however can expire, which is why
- * we need to renew it when it expires.
- */
- const { downloadUrl } = this.state;
- const expires = parseInt(queryParamsToArgs(downloadUrl.split('?')[1]).expires, 10);
- const now = new Date().getTime() / 1000;
-
- /**
- * Amazon uses seconds as their signature unix timestamp
- * while `setInterval` uses milliseconds. Therefore we need to
- * multiply with 1000.
- */
- const interval = (expires - now) * 1000;
-
- this.setState({
- // Substract 5s to make sure there is a big enough window to sign again before expiration
- signatureExpiryTimerId: window.setInterval(this.signUrl, interval - 5000)
- });
- }
- },
-
transformS3UrlToS3Key(url) {
return url.replace(`https://${AppConstants.cloudfrontDomain}/`, '');
},
- signUrl(next) {
+ signUrl() {
const { url, title, artistName } = this.props;
S3Fetcher
.signUrl(this.transformS3UrlToS3Key(url), title, artistName)
- .then(({ signed_url: downloadUrl }) => this.setState({ downloadUrl }, next))
+ .then(({ signed_url: downloadUrl }) => {
+ const { signatureExpiryTimerId } = this.state;
+ let newState = { downloadUrl };
+
+ if(!signatureExpiryTimerId) {
+ /**
+ * The signed url, however can expire, which is why
+ * we need to renew it when it expires.
+ */
+ const expires = parseInt(queryParamsToArgs(downloadUrl.split('?')[1]).expires, 10);
+ const now = new Date().getTime() / 1000;
+
+ /**
+ * Amazon uses seconds as their signature unix timestamp
+ * while `setInterval` uses milliseconds. Therefore we need to
+ * multiply with 1000.
+ */
+ const interval = (expires - now) * 1000;
+
+ Object.assign(newState, {
+ // Substract 5s to make sure there is a big enough window to sign again before expiration
+ signatureExpiryTimerId: window.setInterval(this.signUrl, interval - 5000)
+ });
+ }
+ this.setState(newState);
+ })
.catch(console.logGlobal);
},
diff --git a/js/stores/notification_store.js b/js/stores/notification_store.js
index 7a9add9c..515a3730 100644
--- a/js/stores/notification_store.js
+++ b/js/stores/notification_store.js
@@ -34,10 +34,6 @@ class NotificationStore {
this.editionListNotifications = res.notifications;
}
- onFlushPieceListNotifications() {
- this.editionListNotifications = [];
- }
-
onUpdateEditionNotifications(res) {
this.editionNotifications = res.notification;
}
From 64d0dd008ecdebd48ce38964b7fcb4fa66c41fda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Thu, 3 Mar 2016 10:04:45 +0100
Subject: [PATCH 6/6] Correct timer variable name
---
js/components/ascribe_buttons/s3_download_button.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/ascribe_buttons/s3_download_button.js b/js/components/ascribe_buttons/s3_download_button.js
index 9f7c355a..8bc12f92 100644
--- a/js/components/ascribe_buttons/s3_download_button.js
+++ b/js/components/ascribe_buttons/s3_download_button.js
@@ -38,7 +38,7 @@ const S3DownloadButton = React.createClass({
},
componentWillUnmount() {
- window.clearInterval(this.state.signatureExpiryTime);
+ window.clearInterval(this.state.signatureExpiryTimerId);
},
transformS3UrlToS3Key(url) {