Merge pull request #153 from ascribe/fix-digital-work-file-name

Fix digital work file name download
This commit is contained in:
Tim Daubenschütz 2016-03-03 10:05:13 +01:00
commit 5b79648385
7 changed files with 121 additions and 19 deletions

View File

@ -0,0 +1,103 @@
'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,
signatureExpiryTimerId: null
};
},
componentDidMount() {
/**
* Initially, we request a signed url from
* the backend
*/
this.signUrl();
},
componentWillUnmount() {
window.clearInterval(this.state.signatureExpiryTimerId);
},
transformS3UrlToS3Key(url) {
return url.replace(`https://${AppConstants.cloudfrontDomain}/`, '');
},
signUrl() {
const { url, title, artistName } = this.props;
S3Fetcher
.signUrl(this.transformS3UrlToS3Key(url), title, artistName)
.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);
},
render() {
const { fileExtension, url } = this.props;
const { downloadUrl } = this.state;
return (
<a
ref="downloadButton"
download
className="btn btn-xs btn-default ascribe-margin-1px"
target="_blank"
href={downloadUrl || url}>
{/*
If it turns out that `fileExtension` is an empty string, we're just
using the label 'file'.
*/}
{getLangText('Download')} .{fileExtension || 'file'} <Glyphicon glyph="cloud-download" />
</a>
);
}
});
export default S3DownloadButton;

View File

@ -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">
<Button
bsSize="xsmall"
className="ascribe-margin-1px"
href={content.digital_work.url}
target="_blank">
{/*
If it turns out that `fileExtension` is an empty string, we're just
using the label 'file'.
*/}
{getLangText('Download')} .{fileExtension || 'file'} <Glyphicon glyph="cloud-download" />
</Button>
<S3DownloadButton
url={content.digital_work.url}
title={content.title}
artistName={content.artist_name}
fileExtension={fileExtension} />
</AclProxy>
{embed}
</p>

View File

@ -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/'
};

View File

@ -129,7 +129,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.'

View File

@ -11,6 +11,13 @@ let S3Fetcher = {
key,
bucket
});
},
signUrl(key, title, artistName) {
return requests.get('sign_url_s3', {
key,
title,
'artist_name': artistName
});
}
};

View File

@ -34,10 +34,6 @@ class NotificationStore {
this.editionListNotifications = res.notifications;
}
onFlushPieceListNotifications() {
this.editionListNotifications = [];
}
onUpdateEditionNotifications(res) {
this.editionNotifications = res.notification;
}

View File

@ -70,7 +70,7 @@ class Requests {
}
}).catch(reject);
});
}
};
}
getUrl(url) {